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

2021-02-24 16:12:49 +08:00
 lesismal

项目地址

关于另一个框架

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

  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 有点浪费,还有不少优化空间,但是暂时够用、不着急进一步魔改优化。

一些例子

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

2. Echo

3. TLS Examples

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

欢迎关注

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

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

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

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

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

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

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

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

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

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/755862

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX