V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Nazz
V2EX  ›  程序员

有必要在海量长连接场景使用第三方网络库吗?

  •  
  •   Nazz · 2023-04-09 10:48:49 +08:00 · 2511 次点击
    这是一个创建于 596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境是 go1.20, 测了一下 6w websocket 连接, 每 10s 收发一条消息, 我发现第三方网络库内存占用可能会低一些, 但是 CPU 占用率上没表现出优势. 使用 std net, 如果活跃连接不多, 即使有海量连接也不会明显提高 CPU 占用率.

    30 条回复    2023-04-16 13:33:28 +08:00
    lesismal
        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 尖刺

    多数人需要处理的业务量级都不是特别大的,所以就用标准库足够了。
    真正有大需求的,还是需要搞搞的。
    Nazz
        2
    Nazz  
    OP
       2023-04-09 12:08:47 +08:00 via Android   ❤️ 1
    @lesismal 六万也不少了,大部分公司都没这么多在线用户,标准网络库够用了,大厂才需要极端优化. 我测了好几个网络库, nbio 的内存占用是最优秀的,gws 内存占用比较高,看堆内存是因为读写都使用了 bufio.
    Nazz
        3
    Nazz  
    OP
       2023-04-09 12:15:37 +08:00 via Android
    性能要求非常高直接就上 c++/rust 了.
    lesismal
        4
    lesismal  
       2023-04-09 12:56:22 +08:00
    @Nazz 我最近都在琢磨,要不要单独弄个库,然后把 openssl cgo 弄到 nbio 里用,还有 nodejs 那个 c 的 httpparser 也弄进来,这样性能和内存都能再优化一波,并且如果不考虑兼容标准库 http 的话,性能也能做更大优化,但就不是 pure go 了。
    需要不少工作量,我有点懒得动 :joy:
    lesismal
        5
    lesismal  
       2023-04-09 12:57:34 +08:00
    @Nazz c++/rust 性能强,但开发效率太低了,所以我才会有 #4 的想法,性能与开发效率兼得、性能和消耗的损失更小
    Nazz
        6
    Nazz  
    OP
       2023-04-09 13:04:53 +08:00 via Android
    @lesismal 没必要吧,cgo 性能损失很大,而且线上一般会用 nginx 做 tls
    Nazz
        7
    Nazz  
    OP
       2023-04-09 13:11:25 +08:00 via Android
    @Nazz 而且很多 gopher 会尽量避免使用依赖 cgo 的库,cgo 会给交叉编译带来麻烦,不能在 alpine 里运行
    lesismal
        8
    lesismal  
       2023-04-09 13:16:26 +08:00
    @Nazz 不涉及 syscall ,只是 buffer 传递、解析回调 /回传,这点跨语言栈之间的小结构体字段拷贝开销应该不会很大( buffer 强转避免大段 buffer 的跨语言栈拷贝)
    lesismal
        9
    lesismal  
       2023-04-09 13:52:08 +08:00
    @Nazz cgo 以前只是用、没做过压测。刚试了下,确实拉垮,这下好了,我不用再惦记 #4 这事了 :joy:
    Nazz
        10
    Nazz  
    OP
       2023-04-09 14:15:45 +08:00
    @lesismal 我也不用惦记着换网络库了, 标准库足够优秀.
    godymho
        11
    godymho  
       2023-04-09 14:25:33 +08:00
    @Nazz alpine 就是个大冤种镜像啊,需要的东西加完体积里面就上去了
    Nazz
        12
    Nazz  
    OP
       2023-04-09 14:28:54 +08:00 via Android
    @godymho 一般只需要加时区.
    artnowben
        13
    artnowben  
       2023-04-09 21:11:54 +08:00
    必要性不大,6K QPS 不算高,如果压力大了,可以先用四层负载均衡,后面带几个服务器,现在服务器的成本并不高,还是人力成本高。
    四层负载均衡可以用:DPVS
    四层负载均衡的性能测试可以用:dperf https://github.com/baidu/dperf
    liuxu
        14
    liuxu  
       2023-04-09 22:53:45 +08:00
    这种情况不用 rust 来整,是真的徒增烦恼了,go 整完后面还是要用 rust 重构的
    opengps
        15
    opengps  
       2023-04-10 07:48:23 +08:00
    处理到位就行 ,没必要区分是否第三方
    Nazz
        16
    Nazz  
    OP
       2023-04-10 08:23:05 +08:00 via Android
    @opengps 标准库能满足需求就没必要用第三方
    Nazz
        17
    Nazz  
    OP
       2023-04-10 08:25:48 +08:00 via Android
    @opengps 毫无疑问标准网络库更加成熟稳定,更好的跨平台支持
    opengps
        18
    opengps  
       2023-04-10 09:13:30 +08:00
    @Nazz #16 看起来你已经有了答案,用第三方其实唯一需要判断的就是你是否信得过第三方
    Nazz
        19
    Nazz  
    OP
       2023-04-10 09:30:56 +08:00
    @opengps 主要是我以前认知陷入了误区, 以为协程越多 CPU 使用率越高, 标准库撑不了多少连接.
    opengps
        20
    opengps  
       2023-04-10 10:40:45 +08:00   ❤️ 1
    @Nazz #19 不过有一点认知你还需要继续深入理解下:多连接容易造成启动成本耗时很大。
    所以即使级单机做到了 6 万连接,实际依然建议低于一定的数值,我之前做的系统是按照每台 2 核 4G 机器承载 2 万连接的指标规划的。4 层负载均衡是做 tcp 长连接业务不可避免的选择。注意配合改好软件架构
    opengps
        21
    opengps  
       2023-04-10 10:42:14 +08:00
    自己使用标准库和直接采用第三方库,最大的差异在于经验,当你的经验和水平提高到一定程度,那么你就可以是一个稳定第三方库的输出者
    jones2000
        22
    jones2000  
       2023-04-10 11:06:28 +08:00
    c++ 自己搞下呗, 端口复用, 连接数多了多 fork 几个进程处理, 连接数少了,就关几个进程。 最主要的还是提高单个请求的处理速度。
    Nazz
        23
    Nazz  
    OP
       2023-04-10 12:52:33 +08:00 via Android
    @opengps 业务系统限流是必须的
    Nazz
        24
    Nazz  
    OP
       2023-04-10 12:56:22 +08:00 via Android
    @jones2000 开发网关代理服务器这些基础设施才会考虑 cpp ,业务开发还是算了吧
    lysS
        25
    lysS  
       2023-04-11 10:16:59 +08:00
    @lesismal go 的 tls 以及那些套件都是标准库支持的,你弄过来有啥意义?
    lesismal
        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

    大多数人都会说,实际业务没那么大连接数,即使多一些,堆机器也足够了。
    可能大家业务不一样吧,我处理的业务量相对而言,稍微多一点,能省不少,而且也有些老外在用我的库去做类似的事情。通常大中厂的业务量,用我的这个,相比于标准库,都能节省不少资源。
    不知道这算不算有意义
    lesismal
        27
    lesismal  
       2023-04-16 12:57:53 +08:00
    @Nazz
    #9 的结论不太对。我上次测试,是用纯 c 对比 go 里用 cgo 调 c ,纯 c 确实快很多。但是实际应该是对比纯 go 和 cgo 。搜了下刚好有其他人做了 openssl 的 cgo wrap ,他的 benchmark 数据好于纯 go 。。。
    所以应该还是有的搞
    lesismal
        28
    lesismal  
       2023-04-16 13:02:10 +08:00
    @lesismal #27
    应该是要考虑阈值的问题:
    如果 c 的功能比较复杂、c 开销+cgo 的开销大于纯 go 实现的开销,就没必要。比如一个简单的 sum(a, b),妥妥的纯 go 划算。否则 cgo 搞,还是有提升空间。
    Nazz
        29
    Nazz  
    OP
       2023-04-16 13:21:17 +08:00 via Android
    @lesismal 跑 https 压测 cgo 比纯 go 快多少?
    lesismal
        30
    lesismal  
       2023-04-16 13:33:28 +08:00
    @Nazz 还没试过,尝试这个要改造的工作量也不小
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5661 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 08:42 · PVG 16:42 · LAX 00:42 · JFK 03:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.