环境是 go1.20, 测了一下 6w websocket 连接, 每 10s 收发一条消息, 我发现第三方网络库内存占用可能会低一些, 但是 CPU 占用率上没表现出优势. 使用 std net, 如果活跃连接不多, 即使有海量连接也不会明显提高 CPU 占用率.
1
lesismal 2023-04-09 11:36:36 +08:00 1
6w 不算海量,连接数几十万上百万甚至两百万,差别就大了。
正常的业务也不至于每个连接上都是压测的场景、很高交互频率,普通业务的交互频率,逻辑代码本身需要的 cpu 不至于那么极端所以用标准库,这种逻辑代码本身的 cpu 需求也是够用。优化主要是为了: 1. 节省内存总量从而降低硬件总成本:一般中厂的业务量,比如 500w 连接数,用标准库单硬件 4/8c 8-16g ,稳定起见,单个节点处理 10-20w 连接,要部署 25-50 个节点。如果用其他方案,相同配置单个节点可以处理 100w 连接数,则5个节点就够用了。这是中厂业务,如果大厂、云基础设施,在线数、节点数量可比这大的多,能省下的成本也是不小。 2. 控制协程数量,降低调度成本:虽然 go 的调度很优秀了,但是比如百万个协程毕竟还是太多了 3. 控制对象数量,降低 gc 造成的 cpu 压力。上面说了,普通交互频率的逻辑代码 cpu 需求压力不大,但是对象数量巨大、gc 本身的消耗就很大,偶尔请求高一秒 stw 可能就比较明显了,还容易 cpu 尖刺 多数人需要处理的业务量级都不是特别大的,所以就用标准库足够了。 真正有大需求的,还是需要搞搞的。 |
2
Nazz OP @lesismal 六万也不少了,大部分公司都没这么多在线用户,标准网络库够用了,大厂才需要极端优化. 我测了好几个网络库, nbio 的内存占用是最优秀的,gws 内存占用比较高,看堆内存是因为读写都使用了 bufio.
|
3
Nazz OP 性能要求非常高直接就上 c++/rust 了.
|
4
lesismal 2023-04-09 12:56:22 +08:00
@Nazz 我最近都在琢磨,要不要单独弄个库,然后把 openssl cgo 弄到 nbio 里用,还有 nodejs 那个 c 的 httpparser 也弄进来,这样性能和内存都能再优化一波,并且如果不考虑兼容标准库 http 的话,性能也能做更大优化,但就不是 pure go 了。
需要不少工作量,我有点懒得动 :joy: |
5
lesismal 2023-04-09 12:57:34 +08:00
@Nazz c++/rust 性能强,但开发效率太低了,所以我才会有 #4 的想法,性能与开发效率兼得、性能和消耗的损失更小
|
7
Nazz OP @Nazz 而且很多 gopher 会尽量避免使用依赖 cgo 的库,cgo 会给交叉编译带来麻烦,不能在 alpine 里运行
|
8
lesismal 2023-04-09 13:16:26 +08:00
@Nazz 不涉及 syscall ,只是 buffer 传递、解析回调 /回传,这点跨语言栈之间的小结构体字段拷贝开销应该不会很大( buffer 强转避免大段 buffer 的跨语言栈拷贝)
|
13
artnowben 2023-04-09 21:11:54 +08:00
必要性不大,6K QPS 不算高,如果压力大了,可以先用四层负载均衡,后面带几个服务器,现在服务器的成本并不高,还是人力成本高。
四层负载均衡可以用:DPVS 四层负载均衡的性能测试可以用:dperf https://github.com/baidu/dperf |
14
liuxu 2023-04-09 22:53:45 +08:00
这种情况不用 rust 来整,是真的徒增烦恼了,go 整完后面还是要用 rust 重构的
|
15
opengps 2023-04-10 07:48:23 +08:00
处理到位就行 ,没必要区分是否第三方
|
20
opengps 2023-04-10 10:40:45 +08:00 1
@Nazz #19 不过有一点认知你还需要继续深入理解下:多连接容易造成启动成本耗时很大。
所以即使级单机做到了 6 万连接,实际依然建议低于一定的数值,我之前做的系统是按照每台 2 核 4G 机器承载 2 万连接的指标规划的。4 层负载均衡是做 tcp 长连接业务不可避免的选择。注意配合改好软件架构 |
21
opengps 2023-04-10 10:42:14 +08:00
自己使用标准库和直接采用第三方库,最大的差异在于经验,当你的经验和水平提高到一定程度,那么你就可以是一个稳定第三方库的输出者
|
22
jones2000 2023-04-10 11:06:28 +08:00
c++ 自己搞下呗, 端口复用, 连接数多了多 fork 几个进程处理, 连接数少了,就关几个进程。 最主要的还是提高单个请求的处理速度。
|
26
lesismal 2023-04-16 12:47:45 +08:00 1
@lysS
> go 的 tls 以及那些套件都是标准库支持的,你弄过来有啥意义? 哦。 因为: 1. 标准库的 tls 只支持同步读的解析,这意味着,需要单独一个协成处理读 2. 不只是标准库的 tls ,从 net.TCPConn 到 net/http ,都是同步读的解析,都需要单独一个协成 3. 海量连接的场景,每个连接一个协程对硬件消耗太多了,单个节点协程多了以后,内存、调度、GC & STW 都对进程的健康度不够友好,对企业成本、能源消耗和环保也都不友好 4. 我搞 nbio 是为了解决 3 的问题,解决 3 的问题,就要避免每个连接一个协程的方案,回归其他传统语言的异步方案。虽然 go 底层也是异步 io ,但是如 1/2 所述,标准库提供给用户的同步接口导致海量连接数场景下协程爆炸问题。所以实际上是要做 event driven+async io+nonblocking user interface 。所以 nbio.Conn 实现了异步的 net.Conn ,也实现了异步流解析的 http parser ,也魔改了标准库 tls 实现了异步流解析的 tls 大多数人都会说,实际业务没那么大连接数,即使多一些,堆机器也足够了。 可能大家业务不一样吧,我处理的业务量相对而言,稍微多一点,能省不少,而且也有些老外在用我的库去做类似的事情。通常大中厂的业务量,用我的这个,相比于标准库,都能节省不少资源。 不知道这算不算有意义 |
27
lesismal 2023-04-16 12:57:53 +08:00
@Nazz
#9 的结论不太对。我上次测试,是用纯 c 对比 go 里用 cgo 调 c ,纯 c 确实快很多。但是实际应该是对比纯 go 和 cgo 。搜了下刚好有其他人做了 openssl 的 cgo wrap ,他的 benchmark 数据好于纯 go 。。。 所以应该还是有的搞 |