V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
lesismal
V2EX  ›  分享创造

发布个 golang 高性能异步网络框架 nbio,单击百万不是梦!

  •  
  •   lesismal ·
    lesismal · 2021-02-24 16:12:49 +08:00 · 7466 次点击
    这是一个创建于 1347 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址

    关于另一个框架

    • https://github.com/lesismal/arpc

    • arpc 包括但不限于 rpc,网络交互模式完善推送、游戏、IM 等业务也都可以使用。并且 arpcnbio 也打通了,支持使用 nbio 作为网络层实现更大并发量的支持

    设计与实现的一些基本思考和细节方案

    1. 跨平台支持:*nix 用 epoll 、kqueue, windows 用的 std/net
    2. epoll LT,单次读最大可配,避免饿死
    3. epoll 没有使用 trigger 模式,因为较新版本的内核 epoll 相关系统调用以及其他并行流 close 都是安全的,trigger 模式的无锁对性能提升也是伪命题,额外的系统调用以及内核部分的锁仍然是开销,应用层有锁并且单个 Conn 竞争几乎可以忽略,所以 trigger 模式未必有优势
    4. Write 是直接写,写失败才挂到 Conn 的队列,再添加写事件,可写、flush 后清理掉写事件,尽量减少了 epoll/kqueue 的系统调用
    5. 支持 writev
    6. 实现了 net.Conn,支持 DeadLine,并发安全,也方便业务层多个并行流随意操作
    7. 连接的管理,*nix 直接是 fd 做数组下标对应 Conn
    8. 读缓冲、应用层最大写缓冲都可配
    9. 用于读取的内存分配可由应用层定制,方便业务层做更适合的定制,这个不同场景可以玩很多姿势,简单的 pool 未必是最优
    10. Conn 提供 Hash 方法,方便业务层用于消息分发到指定协程进行处理,从而保证每个连接的消息处理有序
    11. 单独的 heap timer,不使用 time.AfterFunc 节约协程
    12. 支持管理标准库的 net.Conn,比如使用 net.Listener Accept 或者 net.Dial 得到 net.Conn 放到 nbio.Gopher 里管理读写
    13. 最少依赖,除了 tls 作为扩展是需要依赖我的另一个仓库以及 go1.6,单纯作为异步框架,nbio 只依赖标准库
    14. server-side/client-side 都支持
    • 可定制、扩展的挺多的,不一一列举

    与其他一些 golang 异步网络框架对比

    1. 性能:我这里同样配置、参数压测,nbio qps 基本最高,多个框架的 pprof 分析,nbio 的 syscall read/write 占比应该是最高的,进入到 syscall 后的部分是框架层没法再优化的,这说明同一段时间内,nbio 更多的时间是在执行系统调用进行读写、框架本身的消耗占比小于其他框架
    2. 易用性:nbio 实现了 net.Conn,更加业务友好、方便扩展定制,所以我最近花了几天把 go 1.6 std 的 crypto/tls copy 了一份,并重写支持了 nbio 的 tls server-side 、server-side,标准哭 tls 的读写 buffer 有点浪费,还有不少优化空间,但是暂时够用、不着急进一步魔改优化。
    • 后续还考虑标准库的 http 是否也魔改一下支持异步,但是如果要改,工程量有点大,也是得慢慢搞了

    一些例子

    1. 使用 nbio 管理标准库 net.Conn

    2. Echo

    3. TLS Examples

    更多示例请参考文档和代码

    欢迎关注

    • 欢迎 issue / pr / fork , star 更好
    64 条回复    2022-03-12 17:57:58 +08:00
    byte10
        1
    byte10  
       2021-02-24 16:47:45 +08:00
    没啥用的少年,java netty 就可以了,这些轮子用大厂的就可以了。你不用自己搞 NIO,网上很多 golang 的 NIO 框架。做这些东西 实际作用不大,不过面试的时候 可以适当吹吹
    byte10
        2
    byte10  
       2021-02-24 16:51:01 +08:00
    golang 本身有协程就是为了解决 nio 引入的异步编程问题,异步编程 函数式编程都是比较难写,难理解。go 的协程就是用来解决这些问题,本身性能就非常高。估计没你的高,不过性能差距肯定也是在 10%以内,整这些东西没人会用。用的人估计也是 餐桌鸡 架构师!
    lesismal
        3
    lesismal  
    OP
       2021-02-24 17:35:02 +08:00
    @byte10 兄弟,我已经不是少年了。。。本来没想自己撸一套,但是其他那几个,实在不好用
    lesismal
        4
    lesismal  
    OP
       2021-02-24 17:38:29 +08:00
    @byte10 兄弟,java 如果足够好,go 就不会诞生了。。。
    go 的协程也不是万能灵药,对于中小项目确实没必要,对于大项目,nio 还是非常有必要的
    想象一下,如果你手上大厂某些业务几百甚至几万台硬件,如果 nio,可以节省很多成本,单内存占用就可以省太多太多了
    云服务越来越广,高并发相关设施用 go 协程这个成本还是很可观的
    sujin190
        5
    sujin190  
       2021-02-24 17:47:43 +08:00   ❤️ 1
    go 辛辛苦苦做了协程解决异步化编程难题,然后你又把他变成 callback 了。。。

    其实吧相对于带来的编程简洁性协程带来的性能消耗还是值得的,追求极致性能不管编程便利性真的那么重要么?
    lesismal
        6
    lesismal  
    OP
       2021-02-24 19:22:29 +08:00
    @sujin190
    兄弟,你这么说是对系统架构的理解有偏差了

    基础设施异步不代表业务层也必须异步,比如:
    网络层异步,收到数据、decode 后,把 message 丢给业务模块的协程池,业务模块的逻辑还是同步的,需要考虑的是协程池的 size 、避免因为协程池数量平静导致业务阻塞,协程池这个问题在其他基础设施也一样,比如 sql 、redis 的连接池,不够用了该排队等就排队等

    golang 给我们了协程,我们不一定只能用协程的同步逻辑
    同样道理,其他异步设施,也不是强制你上层必须异步
    而是,多种姿势摆在这了,业务层同步还是异步逻辑,你可以自己设计
    sujin190
        7
    sujin190  
       2021-02-24 19:36:37 +08:00 via Android
    @lesismal 协程就是在线程池的基础上封装来的,要啥协程池,再说基础架构不意味着就提供一个很丑的接口,既然协程的消耗本来就很低,为了简洁性可靠性抛弃 callback 直接提供协程接口是完全有必要的,再说既然都需要再在 callback 基础上封装适配协程,你这高性能岂不是白白浪费了,现实场景中只通过 callback 转发数据不使用协程的情况几乎不存在吧
    dorothyREN
        8
    dorothyREN  
       2021-02-24 20:01:14 +08:00
    兄弟,先把错别字改下吧
    lesismal
        9
    lesismal  
    OP
       2021-02-24 20:11:56 +08:00
    @dorothyREN 十分想改,奈何 V 站似乎没有此功能,我找了好几次了 :joy: 。。。
    lesismal
        10
    lesismal  
    OP
       2021-02-24 20:16:11 +08:00
    @sujin190 兄弟,首先,等你遇到更大的业务量级,或者自己做些压测对比下不同方式下的各项资源占用,并且,不要按照做中小项目来思考,放飞一下自己,把眼光放到一个更上面的层次,去思考下更宏大的代码运行的世界,比如我上面 4 楼说的算是一个例子
    byte10
        11
    byte10  
       2021-02-25 11:16:46 +08:00   ❤️ 1
    @lesismal 我作为一个高手,你要听话,听我的。相信我,你这个是多此一举,我再次强调,你这个性能提升不了多少。还有你说的那个啥省点资源,说事实话我没具体比较多,理论上是少一些。你这个不算底层,底层都是 epoll 。很多网络框架都是在 epoll 层加上了协程来做好了这个网络编程开发的。你自己搞一个 NIO,然后别人在你的 NIO 封装那个啥协程,还不如直接用成熟的网络开发框架。

    @sujin190 是的,他还没明白过了。另外业务层必须拒绝函数式编程,我不允许有函数式编程,只要有搞项目工程(不管大小),就不可以大规模函数式编程(少量的方便处理可以),否则就是餐桌鸡 架构师,严重的鄙视这样的 大头猪。自己搞一个 NIO,然后别人在你的 NIO 封装那个啥协程,还不如直接用成熟的网络开发框架。

    @lesismal 大小项目 都必须要用协程同步来处理,不用关心底层这些。我是高手,听我的。
    lairdnote
        12
    lairdnote  
       2021-02-25 12:03:48 +08:00
    兄弟 听我的。。。如果协程都处理不了的业务 证明也业务方面有问题。。多和系统架构 或者代码架构 聊聊 。
    再差的代码 系统有办法让他支持高并发 。
    lesismal
        13
    lesismal  
    OP
       2021-02-25 12:18:31 +08:00   ❤️ 1
    @byte10 兄弟,你可以先看下我 4 楼里说的场景,还可以自己稍微测一下 go 标准库的 net.Conn 对比 epoll 这类的内存占用情况以及连接数很多时候的情况比如至少 1w 连接起步、稍微配置好点的硬件来个 5w 起步的连接数(连接数少则协程数量少、异步框架相比 go runtime 没什么优势)
    你实测到一些数据,还可以再看下系统编程类的书籍,并且最好也深入理解下 go 的并发模型,20 多年前互联网早期 server 的进程池线程池模型、异步 IO 、以及异步模型比如 C/C++、同步模型比如 erlang 、golang 这些的发展史
    万变不离其宗的是系统层的资源的有限,不管语言层面提供何种模型,系统资源始终是那些,语言层的同步模型需要消耗的内存和调度的 CPU 成本,对应得到的同步模型的便利,这二者在中小业务量级的场景可以兼得,但是面对大业务量级会存在一些平衡点,协程数量多时,打破了平衡,就会显得浪费、吃力
    与 CAP 类似,现实中也有很多其他事情类似,影响一件事情的多个因素,此消彼长,打破了平衡,就损失了整体的收益

    看一下星爷的《功夫》,看一下那个理发师小哥,然后再想想高手该怎么定义,多读书

    ps:我也不是什么少年,十几年经验、奔 40 的人了,日常做系统架构、底层框架基础设施,如果标准库性能足够且好用,我就不自己手撸这些了
    lesismal
        14
    lesismal  
    OP
       2021-02-25 12:20:48 +08:00
    @lairdnote

    既然回帖的各路大神画风都很自信了,我也就不谦虚了

    老夫本人就是系统架构,老夫搞这些就是为了解决、优化这些问题
    samaaaaa
        15
    samaaaaa  
       2021-02-25 12:36:19 +08:00 via iPhone
    挺好的呢支持大神
    guotie
        16
    guotie  
       2021-02-25 12:38:41 +08:00
    great !!!
    guotie
        17
    guotie  
       2021-02-25 12:39:53 +08:00
    看了回复,很多人没有认识到你的这个库的价值啊
    lesismal
        18
    lesismal  
    OP
       2021-02-25 13:13:08 +08:00
    @guotie 慢慢来吧,有需要的朋友用就行。以后有时间了我再多写些其他的,毕竟绝大多数人的需要是业务框架,多谢老铁支持!
    fenglangjuxu
        19
    fenglangjuxu  
       2021-02-25 14:04:33 +08:00
    虽然不懂 弹痕厉害
    byte10
        20
    byte10  
       2021-02-25 15:45:16 +08:00
    @lesismal 我是高手,你要信我。百万连接的测试我也做过,netty 占用了 2G,nodejs 占用了 5g,golang 也是 13 个 G 。golang 确实渣,但是没关系。硬件不值钱,就算你换成了 NIO,达到了 netty 那样的水平也没用,你上层应用还是要用 go 协程去实现业务,所以白干了。我的意思是你不管如何优化,到了业务层还是一样,所以还不如一开始就用协程,搞得花里胡哨的不实际。如果作为基础的网络接入层,那么直接用替换成 nodejs 和 java 都可以,生态贼好,golang 不行。
    byte10
        21
    byte10  
       2021-02-25 15:54:40 +08:00
    @guotie 没有啥大价值,netty 那么强,直接搞 netty 就可以了。golang 和 C 一样都是喜欢造轮子,每个人都在造轮子,这就是这种语言的特性,低级语言的特性(相对 java,python 这些)。

    @lairdnote 他是要搞底层优化,上层还是会用协程的。他是底层 NIO 作为网络并发编程,别人的大部分框架是底层 epoll+协程来实现网络并发编程。本质没多大的区别,他把编程开发是否异步还是同步交给上层业务来选择,但是业务层一定是要用协程的,不然就是大菜鸟了。所以结论是,还不如直接实现一份同步的网络并发框架。另外要搞 nio 的话,直接用 netty 就很好了。
    FrankAdler
        22
    FrankAdler  
       2021-02-25 17:45:36 +08:00
    @byte10 好奇什么是“餐桌鸡 架构师”,搜了下没找到,应该不是个啥梗?
    byte10
        23
    byte10  
       2021-02-25 17:49:09 +08:00
    @FrankAdler 哈哈我自己创作的非主流 梗,放在餐桌上吃的鸡就是一道菜,菜鸡。
    king888
        24
    king888  
       2021-02-25 21:25:53 +08:00
    @byte10 #20 '百万连接的测试我也做过,netty 占用了 2G,nodejs 占用了 5g,golang 也是 13 个 G'
    能否说下测试详情?
    byte10
        25
    byte10  
       2021-02-26 09:30:51 +08:00
    @king888 一台机器运行 30 个 docker 容器作为客户端(用的是 nodejs 作为 websocket 客户端)每个容器跑 3.5 万个连接,每个连接随机 10 秒请求一次后台,算下来就是平均每秒 10w 并发。然后服务端是 8 核的 AMD-4800U,设置后文件打开数量限制,正常跑 netty 回复信息。实际下来每秒处理 10w 请求还可以。如果并发 20w 的话,客户端收到消息回复就会平均在 2 秒多。nodejs 在单线程情况下,表现挺不错的,如果部署多个进程完全利用好 8 核,吞吐量可以大大超过 netty,当然内存也上去了,也是内存换出来的吞吐量。
    lesismal
        26
    lesismal  
    OP
       2021-02-26 20:31:14 +08:00
    @byte10 linux 下 nbio 普通压测,客户端服务器共用单机 localhost 2w 连接数,2w 个 client echo 压测不停收发,payload 比较小只用了 64 字节,4c8t/4g 的虚拟机,ps -aux 查看内存占用 0.4%或者 20M 左右,qps 大概 25-30w,如果只是连接数较高、qps 不高,除了 nbio.Conn 的结构体按比例扩大下内存占用(估计百字节左右乘以个连接数),处理请求使用的内存也不会太大

    测试代码在这里,有兴趣的话可以来试试:
    https://github.com/lesismal/go_network_benchmark/blob/master/nbio/nbio.go

    ps:linux 下每个 Conn 是挂到对应的 poller 上,poller 每次 loop 的协程执行读,所以这个 poller 上的所有 Conn 可以共用这个 readbuffer,读到一个处理一个,当然如果需要解析、粘包 save 下次继续解析之类的,内存占用会更高,但是由于没有使用标准库的协程模型,已经把协程的资源消耗降到最低了,否则单个协程,go 不同版本有 2k 、4k 、8k,不记得现在是不是 16k 了,反正百万连接,较新版本的 go 单单用于创建协程就已经 8G 甚至十几 G 了
    但是 nbio 或者其他的异步框架,不存在协程消耗巨大内存的瓶颈
    lesismal
        27
    lesismal  
    OP
       2021-02-26 20:35:49 +08:00
    @king888 请看我上一楼回复的测试数据,有兴趣的话可以尝试下测试代码的链接。不是做 http 测试,因为暂时没有支持异步框架的完整功能的纯 go http parser,我打算闲余时间愚公移山搞一套
    nbio 或者其他的 golang 异步框架,正是为了解决类似这种 13G 的问题
    lesismal
        28
    lesismal  
    OP
       2021-02-26 20:37:12 +08:00
    @byte10 如果觉得搞这种异步框架也没用,那是因为社区还没有足够多的支持 golang 异步网络库的业务层框架比如异步网络库之上的 web 框架
    别着急,老夫抽空慢慢搞,或者其他哪位大神大仙,早晚会有人搞出来
    lesismal
        29
    lesismal  
    OP
       2021-02-26 20:43:05 +08:00
    至于 netty,确实挺不错的,但是要真说强,咋都当 c/cpper 灭绝了?比性能都不带上他们,这太不讲武德了

    另外,我无意挑起语言之争,只是个人审美,喜欢简洁,java 本身强于社区而非语言本身,但是性能也并不足够强,否则 google 当年引进 python 失败就不至于搞 go 了( google 被 cpp 虐惨了,看 py 牛逼,想引进 py 解决工程问题,也正是那个时段,py 之父去了 google,但是后来 google 醒了,发现 py 的性能实在坑,所以又放弃了,但是没有选择 java,而是搞了 go,也正是 go 开始逐渐成型后,py 之父离开了 google,虽然 py 之父的来去未必都是直接联系,但也一定程度上是 google 内部技术升级的时代使然)

    还是那句话,如果 java 真的足够好,天下一统,全都 java 不就完事了?为啥今年独角兽、明星企业大量搞 go 为啥 java 份额下降了?

    但是,如果新手选技术路线,我还是建议 java,因为好岗位多、待遇好,赚钱第一嘛~
    lesismal
        30
    lesismal  
    OP
       2021-02-26 20:44:58 +08:00
    上一楼错别字:近年独角兽

    不能编辑,这个真的有点难受
    wslzy007
        31
    wslzy007  
       2021-02-27 23:36:22 +08:00
    用实测数据说话吧: [golang 主流高性能 web 框架性能测试] https://yq.aliyun.com/articles/721540
    fucUup
        32
    fucUup  
       2021-02-28 15:39:19 +08:00 via Android
    我是谷狗的,虽然我们闭源 stubby 库是 c++的不是 go,为啥你网络库用水平触发,谷狗是边缘触发的 。。不要问我然后商业机密源码
    lesismal
        33
    lesismal  
    OP
       2021-02-28 17:30:36 +08:00
    @wslzy007 不要用不一样的东西进行对比。nbio 目前只是网络库,不是 http 框架,所以没有意义。
    另外,性能对比涉及很多方面,连接数、并发请求频率、payload 、应用层框架功能完整度、针对性优化等,每个点的差别都能带来较大的性能差异。

    golang 的异步网络库主要优势是面对大量连接数场景下,节约大量的协程数量,从而减少对应的巨大内存消耗和协程调度成本。当连接数较少时比如几百几千个连接数(系统硬件资源不同这个阈值不同),异步网络库不会有明显优势,但是连接数上升到数万甚至数十万、上百万时,标准库的绝大资源消耗和性能下降会非常明显
    lesismal
        34
    lesismal  
    OP
       2021-02-28 17:47:47 +08:00
    @fucUup 目前没有测试表明 ET 更快,实际上只作为网络库压测的情况,ET 和 LT 能达到基本相同的吞吐量,很多选择 ET 的可能是出于对 epoll_ctl 说明以及对 LT 用法不当导致的误解:
    https://man7.org/linux/man-pages/man7/epoll.7.html

    When used as an edge-triggered interface, for performance
    reasons, it is possible to add the file descriptor inside the
    epoll interface (EPOLL_CTL_ADD) once by specifying
    (EPOLLIN|EPOLLOUT). This allows you to avoid continuously
    switching between EPOLLIN and EPOLLOUT calling epoll_ctl(2) with
    EPOLL_CTL_MOD.

    但实际上 LT 也可以避免不必要的 syscall,可以参考 nbio 的实现

    ET 和 LT 各有利弊,比如 ET,需要谨慎处理读写、避免 bug 导致 hang up,而 LT 处理逻辑更简单( nbio 的方式,其实可能比 ET 更省 syscall,因为不需要每次读完再去重新 epoll_ctl )

    ET 要求单次 event loop 读完单个 fd 的所有,但其实,如果这单个 fd 上面数据非常大,比如多个应用层协议,反倒可能造成这单次 loop 内处理它耗时长、其他 fd 的等待,而 LT 单次 event loop 内单个 fd 可以不全读完,可以控制数量避免其他 fd 等待太久,反而能更公平

    另外,redis 是用的默认 LT,muduo 陈老板也是默认 LT
    nginx 年代较早,man 手册的建议以及 ET 也并不比 LT 性能差,所以即使 LT 实现逻辑更 easy 也没必要改
    lesismal
        35
    lesismal  
    OP
       2021-02-28 17:49:09 +08:00
    @fucUup 还有云风的 skynet,印象中也是 LT 的
    fucUup
        36
    fucUup  
       2021-02-28 18:08:42 +08:00 via Android
    @lesismal 原理都是公开的,发明了几十年的,我们不要谈原理,但是工程质量往往决定了成败,比如开源的 MapReduce 实在太弱鸡了
    fucUup
        37
    fucUup  
       2021-02-28 18:16:29 +08:00 via Android
    rpc 请求一般限制 4mb 以内,公网条件还会更少,你框架有无做限制
    lesismal
        38
    lesismal  
    OP
       2021-02-28 18:51:20 +08:00
    @fucUup 兄弟,你上面问的是为什么你们谷狗用 ET 而我的用 LT,那我不给你讲原理和实现原因,该怎么回答你?难道因为你们某个项目用了 ET 所以就应该用 ET ?那我是不是可以回答因为 redis 用了 LT 所以用 LT ?

    工程质量,谷狗项目用啥并不是工程质量的唯一标准。另外,这里说网络库,网络库跟 MapReduce 这两者本来就是处于基础设施的不同层次,网络仓库作为数据传输的基础设施,MapReduce 是在网络或者其他整合生产消费的数据层之上的层,更多的是需要对数据生产消费的整合和加工,跟网络库本身没有可比性
    lesismal
        39
    lesismal  
    OP
       2021-02-28 18:55:54 +08:00
    @fucUup 网络框架这一层处理数据收发。rpc 请求的限制,你在 rpc 框架收发数据的层完全可以自己限制。
    兄弟,分层的理念你可以再加深下理解,不同的层处理自己的事情,从内核到应用,或者网络协议栈不同的层,都是各自处理自己层内的事情,该留给更高层去处理的留给更高层去处理,否则就拿你 rpc 4M 的来举例,如果网络库这一层写死了限制 4 M,你在其基础之上实现的 rpc 框架舒服了,但是其他人在其基础之上实现的其他业务可能需要大于 4M,那怎么办?所以,下层在自己层内资源可控的前提下提供上层所需的扩展机制、接口,而不是下层直接做这些限制
    wslzy007
        40
    wslzy007  
       2021-02-28 19:44:07 +08:00
    @lesismal 网络库最终还是要加载协议的,哪怕是简化版协议也行啊,等你的 http 协议对接后我测测。用数据说话最直接
    newmlp
        41
    newmlp  
       2021-02-28 19:48:52 +08:00
    单机百万的轮子好多,随便写
    lesismal
        42
    lesismal  
    OP
       2021-02-28 19:55:24 +08:00
    @wslzy007 只是为了压测做的那种特别简单的 http 解析没什么意义,比如一些网络库加的那个 http echo 压测,只解析了这个测试用的特定的 http 请求,这个写起来也简单,解析到\r\n\r\n 直接回包就行了,但是对于商业项目毫无帮助,用这种压测跟别人完整功能的 http 框架对比性能也没有任何意义。只是对比网络库的话,可以跟其他网络库比吞吐量之类的就可以了,有兴趣可以参考这里:
    https://github.com/lesismal/go_network_benchmark

    我对 http 的支持可能需要较长时间,暂时规划几步走:
    1. http 1x parser 基础功能,为了省体力,考虑直接参考 go 标准库重写解析,尽量兼容标准库,这样的话,wrap 个中间层、其他基于标准库的框架 /router 方案 就能改用 nbio 了
    2. tls,现在已经魔改 1.6 标准库的 tls 支持了 nbio 的 non-bloking,但是标准库原来的 tls 代码写得有点性能不友好,很浪费,我还是打算以后有档期了全重写一份,但是目前可以用,暂时不从头搞、太耗体力了
    3. websocket 支持
    4. http 2

    每一项都需要较多时间,慢慢搞
    wslzy007
        43
    wslzy007  
       2021-02-28 19:59:40 +08:00
    @lesismal 简单报文恰恰可以测试网络库调度能力啊,且直接有效
    lesismal
        44
    lesismal  
    OP
       2021-02-28 20:00:07 +08:00
    @newmlp 百万连接不是什么难事,难的是大量连接下的高请求量、吞吐量。真实的商业项目也很少真正单机搞百万连接的,避免万一故障。
    但是不同框架对高连接数的优化,不只是为了达到百万连接数的目的,而是在这个基础上对整个系统各项资源消耗和指标的优化,对于 golang,同步模式的大量协程带来的内存和 cpu 调度浪费太大,异步框架还是有很大意义的
    lesismal
        45
    lesismal  
    OP
       2021-02-28 20:01:51 +08:00
    希望能让 go 支持更广泛的业务,否则单就高阶的高并发,还真难干得过 java netty 或者其他异步方案
    ERRASYNCTYPE
        46
    ERRASYNCTYPE  
       2021-03-09 14:10:20 +08:00
    @byte10 为什么 golang 占的要比 node 高这么多,我的经历是 golang 跟 node 写同样业务的 http 服务,golang 的内存能明显小于 node
    byte10
        47
    byte10  
       2021-03-09 15:04:04 +08:00
    @ERRASYNCTYPE 我也不太清楚,nodejs 的其实也是有协程,跟 Kotlin 应该比较相似。go 的协程叫做纤程,虚拟线程也合适,它更像线程。我估计就是这些占用了内存了吧
    lesismal
        48
    lesismal  
    OP
       2021-03-10 12:39:22 +08:00
    @ERRASYNCTYPE golang 标准库每个连接一个协程,当前版本一个协程栈应该是 8k,连接数多了内存消耗就巨大了。其他语言多数是异步底层,每个连接不需要固定分配这么大的内存。连接数少的时候 golang 内存浪费不明显,连接数多的时候,会很明显

    另外,最近一周多我又撸了份 http 1.x 的 parser,封装了 http server,在 nbio 基础上可以跑 http server 了,兼容标准库 http.Request,百万连接测试请看这里:

    https://github.com/lesismal/nbio/tree/master/examples/http/1m

    我单虚拟机做这种测试,虚拟机是 6C8T 的,因为客户端服务器都在这个虚拟机,所以没测百万那么多,50w 连接数,2k qps 的情况,server 端 cpu 平均 100%以内( load 小于 1,不到单核),client 请求是多协程并发一直进行的不是平均的所有 server 端有偶发尖刺到百分之几百算正常,内存占用 400-500M
    连接数更多、qps 更高内存会消耗更多些,但是跟其他语言异步底层相比,内存已经很省了,并且,50w 连接数,这种简单的 echo 测试,也随便能跑到 qps 5w+,定制少用协程的话可以跑 10w+。

    另外,nbio http 从数据的 read 到 parse 到 handle request,这三个流程之间的协程使用都是可定制的,如果是做 nginx 类似的网关代理这种基础设施、不需要数据库等耗时操作,完全可以直接在 read/poller 协程内进行 parse 和 handle request,最大程度减少跨协程数据传递和调度的成本,细节我会在以后的帖子中慢慢整理,最近都忙于编码,还有很多细节或者性能优化可以做
    lesismal
        49
    lesismal  
    OP
       2021-03-10 12:45:17 +08:00
    @byte10 请看我上一楼的回复,有兴趣的话来跑下 1m 测试,老夫这一两周撸的 http parser 和 nbio 基础之上的 http server,并且兼容标准库的 http.Handler,所以除了 fasthttp 那种没使用标准库的,其他的 gin 、iris 、echo 、beego 等各种,都能比较容易地使用 nbio http 作为网络层,实现内存的巨大节约。不同的业务类型对性能和资源的考量不一样,响应速度和内存可能不能兼得,老夫也正考虑研究下 golang 里更高性能的协程池是否能搞定,如果能搞定,那就可以兼得了

    后续还考虑支持 websocket 、http 2.0,但是每一项也都是个大活,http 1.x 已经基本完成,还剩下边边角角的细节优化项和测试,也是要耗费老夫不少时间,慢慢搞,老夫一定要让 golang 更强
    lesismal
        50
    lesismal  
    OP
       2021-03-10 12:46:06 +08:00
    @lesismal 修正:虚拟机是 6c12t 的
    lesismal
        51
    lesismal  
    OP
       2021-03-10 12:51:32 +08:00
    @byte10 nbio http 如果想支持 fasthttp 这种也不难,参考默认的支持标准库的 Processor 实现一份 Processor 就行了,不过我暂时没当期在 nbio 自带一份实现给它,以后闲了考虑给它写个
    lesismal
        52
    lesismal  
    OP
       2021-03-10 13:21:53 +08:00
    @ERR @byte10 为了省去虚拟网络或者 docker 或者多台机器之类的部署环境的麻烦,1m 连接测试的代码是开了多个监听端口,因为即使只是 1 个端口,实际处理接受连接和数据读写的 poller 还是那些个 epoll fd 协程,所以开多个端口对性能影响不大,但是测试起来就方便多了,如果想只用一个端口,代码稍微改下或者各位用自己的 cleint 代码并部署就行了
    lesismal
        53
    lesismal  
    OP
       2021-03-10 13:23:12 +08:00
    @wslzy007 http 1.x 已经支持,详情请看我上面几楼的回复
    lesismal
        54
    lesismal  
    OP
       2021-04-01 11:47:27 +08:00
    也不知道楼上有几位都是啥情况,老夫如此热情,连句话都不回,是因为看不懂吗。。。
    foam
        55
    foam  
       2021-05-12 23:59:38 +08:00 via Android
    支持一下
    kksco
        56
    kksco  
       2021-05-13 16:50:34 +08:00
    邮件提醒我 github golang 的一个 issues 有更新,偶然翻到大佬这个仓库,已 star 支持一波
    lesismal
        57
    lesismal  
    OP
       2021-05-13 18:16:28 +08:00
    @foam 感谢支持!
    lesismal
        58
    lesismal  
    OP
       2021-05-13 18:17:04 +08:00
    @kksco 感谢支持!太爱 golang 了
    towser
        59
    towser  
       2021-08-10 20:29:14 +08:00
    两位老哥吵了半天都没有急眼说脏话,君子之争令人愉悦。
    shujun
        60
    shujun  
       2021-08-24 00:33:04 +08:00
    @lesismal 非常棒,支持一下。
    lesismal
        61
    lesismal  
    OP
       2021-08-24 11:36:11 +08:00
    @shujun 感谢支持!
    dubdub
        62
    dubdub  
       2022-02-27 17:23:40 +08:00
    > 用于读取的内存分配可由应用层定制,方便业务层做更适合的定制,这个不同场景可以玩很多姿势,简单的 pool 未必是最优
    请教一下大佬还有什么其他姿势呢
    lesismal
        63
    lesismal  
    OP
       2022-02-28 10:26:00 +08:00
    @dubdub 比如标准库 tls 或者其他一些地方,或者 fasthttp 里,用到 2^N size 对齐的多级 pool ,nbio 里用的不是固定 size 的,go 的 gc 无法确定内存的精确释放时机,如果需要比较精准控制,甚至可以 cgo 直接调用 malloc 这些,得看实际需要了。
    kingcanfish
        64
    kingcanfish  
       2022-03-12 17:57:58 +08:00
    虽然我不知道争论谁有道理 但是看帖子能学到很多知识(学生狗如是说
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1206 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 18:18 · PVG 02:18 · LAX 11:18 · JFK 14:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.