主要特点:高性能、事件驱动、易用易扩展、省协程省内存、节能环保
更多示例请参考文档和代码
1
byte10 2021-02-24 16:47:45 +08:00
没啥用的少年,java netty 就可以了,这些轮子用大厂的就可以了。你不用自己搞 NIO,网上很多 golang 的 NIO 框架。做这些东西 实际作用不大,不过面试的时候 可以适当吹吹
|
2
byte10 2021-02-24 16:51:01 +08:00
golang 本身有协程就是为了解决 nio 引入的异步编程问题,异步编程 函数式编程都是比较难写,难理解。go 的协程就是用来解决这些问题,本身性能就非常高。估计没你的高,不过性能差距肯定也是在 10%以内,整这些东西没人会用。用的人估计也是 餐桌鸡 架构师!
|
4
lesismal OP @byte10 兄弟,java 如果足够好,go 就不会诞生了。。。
go 的协程也不是万能灵药,对于中小项目确实没必要,对于大项目,nio 还是非常有必要的 想象一下,如果你手上大厂某些业务几百甚至几万台硬件,如果 nio,可以节省很多成本,单内存占用就可以省太多太多了 云服务越来越广,高并发相关设施用 go 协程这个成本还是很可观的 |
5
sujin190 2021-02-24 17:47:43 +08:00 1
go 辛辛苦苦做了协程解决异步化编程难题,然后你又把他变成 callback 了。。。
其实吧相对于带来的编程简洁性协程带来的性能消耗还是值得的,追求极致性能不管编程便利性真的那么重要么? |
6
lesismal OP @sujin190
兄弟,你这么说是对系统架构的理解有偏差了 基础设施异步不代表业务层也必须异步,比如: 网络层异步,收到数据、decode 后,把 message 丢给业务模块的协程池,业务模块的逻辑还是同步的,需要考虑的是协程池的 size 、避免因为协程池数量平静导致业务阻塞,协程池这个问题在其他基础设施也一样,比如 sql 、redis 的连接池,不够用了该排队等就排队等 golang 给我们了协程,我们不一定只能用协程的同步逻辑 同样道理,其他异步设施,也不是强制你上层必须异步 而是,多种姿势摆在这了,业务层同步还是异步逻辑,你可以自己设计 |
7
sujin190 2021-02-24 19:36:37 +08:00 via Android
@lesismal 协程就是在线程池的基础上封装来的,要啥协程池,再说基础架构不意味着就提供一个很丑的接口,既然协程的消耗本来就很低,为了简洁性可靠性抛弃 callback 直接提供协程接口是完全有必要的,再说既然都需要再在 callback 基础上封装适配协程,你这高性能岂不是白白浪费了,现实场景中只通过 callback 转发数据不使用协程的情况几乎不存在吧
|
8
dorothyREN 2021-02-24 20:01:14 +08:00
兄弟,先把错别字改下吧
|
9
lesismal OP @dorothyREN 十分想改,奈何 V 站似乎没有此功能,我找了好几次了 :joy: 。。。
|
10
lesismal OP @sujin190 兄弟,首先,等你遇到更大的业务量级,或者自己做些压测对比下不同方式下的各项资源占用,并且,不要按照做中小项目来思考,放飞一下自己,把眼光放到一个更上面的层次,去思考下更宏大的代码运行的世界,比如我上面 4 楼说的算是一个例子
|
11
byte10 2021-02-25 11:16:46 +08:00 1
@lesismal 我作为一个高手,你要听话,听我的。相信我,你这个是多此一举,我再次强调,你这个性能提升不了多少。还有你说的那个啥省点资源,说事实话我没具体比较多,理论上是少一些。你这个不算底层,底层都是 epoll 。很多网络框架都是在 epoll 层加上了协程来做好了这个网络编程开发的。你自己搞一个 NIO,然后别人在你的 NIO 封装那个啥协程,还不如直接用成熟的网络开发框架。
@sujin190 是的,他还没明白过了。另外业务层必须拒绝函数式编程,我不允许有函数式编程,只要有搞项目工程(不管大小),就不可以大规模函数式编程(少量的方便处理可以),否则就是餐桌鸡 架构师,严重的鄙视这样的 大头猪。自己搞一个 NIO,然后别人在你的 NIO 封装那个啥协程,还不如直接用成熟的网络开发框架。 @lesismal 大小项目 都必须要用协程同步来处理,不用关心底层这些。我是高手,听我的。 |
12
lairdnote 2021-02-25 12:03:48 +08:00
兄弟 听我的。。。如果协程都处理不了的业务 证明也业务方面有问题。。多和系统架构 或者代码架构 聊聊 。
再差的代码 系统有办法让他支持高并发 。 |
13
lesismal OP @byte10 兄弟,你可以先看下我 4 楼里说的场景,还可以自己稍微测一下 go 标准库的 net.Conn 对比 epoll 这类的内存占用情况以及连接数很多时候的情况比如至少 1w 连接起步、稍微配置好点的硬件来个 5w 起步的连接数(连接数少则协程数量少、异步框架相比 go runtime 没什么优势)
你实测到一些数据,还可以再看下系统编程类的书籍,并且最好也深入理解下 go 的并发模型,20 多年前互联网早期 server 的进程池线程池模型、异步 IO 、以及异步模型比如 C/C++、同步模型比如 erlang 、golang 这些的发展史 万变不离其宗的是系统层的资源的有限,不管语言层面提供何种模型,系统资源始终是那些,语言层的同步模型需要消耗的内存和调度的 CPU 成本,对应得到的同步模型的便利,这二者在中小业务量级的场景可以兼得,但是面对大业务量级会存在一些平衡点,协程数量多时,打破了平衡,就会显得浪费、吃力 与 CAP 类似,现实中也有很多其他事情类似,影响一件事情的多个因素,此消彼长,打破了平衡,就损失了整体的收益 看一下星爷的《功夫》,看一下那个理发师小哥,然后再想想高手该怎么定义,多读书 ps:我也不是什么少年,十几年经验、奔 40 的人了,日常做系统架构、底层框架基础设施,如果标准库性能足够且好用,我就不自己手撸这些了 |
14
lesismal OP |
15
samaaaaa 2021-02-25 12:36:19 +08:00 via iPhone
挺好的呢支持大神
|
16
guotie 2021-02-25 12:38:41 +08:00
great !!!
|
17
guotie 2021-02-25 12:39:53 +08:00
看了回复,很多人没有认识到你的这个库的价值啊
|
18
lesismal OP @guotie 慢慢来吧,有需要的朋友用就行。以后有时间了我再多写些其他的,毕竟绝大多数人的需要是业务框架,多谢老铁支持!
|
19
fenglangjuxu 2021-02-25 14:04:33 +08:00
虽然不懂 弹痕厉害
|
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 不行。
|
21
byte10 2021-02-25 15:54:40 +08:00
|
22
FrankAdler 2021-02-25 17:45:36 +08:00
@byte10 好奇什么是“餐桌鸡 架构师”,搜了下没找到,应该不是个啥梗?
|
23
byte10 2021-02-25 17:49:09 +08:00
@FrankAdler 哈哈我自己创作的非主流 梗,放在餐桌上吃的鸡就是一道菜,菜鸡。
|
24
king888 2021-02-25 21:25:53 +08:00
@byte10 #20 '百万连接的测试我也做过,netty 占用了 2G,nodejs 占用了 5g,golang 也是 13 个 G'
能否说下测试详情? |
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,当然内存也上去了,也是内存换出来的吞吐量。
|
26
lesismal OP @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 或者其他的异步框架,不存在协程消耗巨大内存的瓶颈 |
27
lesismal OP @king888 请看我上一楼回复的测试数据,有兴趣的话可以尝试下测试代码的链接。不是做 http 测试,因为暂时没有支持异步框架的完整功能的纯 go http parser,我打算闲余时间愚公移山搞一套
nbio 或者其他的 golang 异步框架,正是为了解决类似这种 13G 的问题 |
28
lesismal OP @byte10 如果觉得搞这种异步框架也没用,那是因为社区还没有足够多的支持 golang 异步网络库的业务层框架比如异步网络库之上的 web 框架
别着急,老夫抽空慢慢搞,或者其他哪位大神大仙,早晚会有人搞出来 |
29
lesismal OP 至于 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,因为好岗位多、待遇好,赚钱第一嘛~ |
30
lesismal OP 上一楼错别字:近年独角兽
不能编辑,这个真的有点难受 |
31
wslzy007 2021-02-27 23:36:22 +08:00
用实测数据说话吧: [golang 主流高性能 web 框架性能测试] https://yq.aliyun.com/articles/721540
|
32
fucUup 2021-02-28 15:39:19 +08:00 via Android
我是谷狗的,虽然我们闭源 stubby 库是 c++的不是 go,为啥你网络库用水平触发,谷狗是边缘触发的 。。不要问我然后商业机密源码
|
33
lesismal OP @wslzy007 不要用不一样的东西进行对比。nbio 目前只是网络库,不是 http 框架,所以没有意义。
另外,性能对比涉及很多方面,连接数、并发请求频率、payload 、应用层框架功能完整度、针对性优化等,每个点的差别都能带来较大的性能差异。 golang 的异步网络库主要优势是面对大量连接数场景下,节约大量的协程数量,从而减少对应的巨大内存消耗和协程调度成本。当连接数较少时比如几百几千个连接数(系统硬件资源不同这个阈值不同),异步网络库不会有明显优势,但是连接数上升到数万甚至数十万、上百万时,标准库的绝大资源消耗和性能下降会非常明显 |
34
lesismal OP @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 也没必要改 |
36
fucUup 2021-02-28 18:08:42 +08:00 via Android
@lesismal 原理都是公开的,发明了几十年的,我们不要谈原理,但是工程质量往往决定了成败,比如开源的 MapReduce 实在太弱鸡了
|
37
fucUup 2021-02-28 18:16:29 +08:00 via Android
rpc 请求一般限制 4mb 以内,公网条件还会更少,你框架有无做限制
|
38
lesismal OP @fucUup 兄弟,你上面问的是为什么你们谷狗用 ET 而我的用 LT,那我不给你讲原理和实现原因,该怎么回答你?难道因为你们某个项目用了 ET 所以就应该用 ET ?那我是不是可以回答因为 redis 用了 LT 所以用 LT ?
工程质量,谷狗项目用啥并不是工程质量的唯一标准。另外,这里说网络库,网络库跟 MapReduce 这两者本来就是处于基础设施的不同层次,网络仓库作为数据传输的基础设施,MapReduce 是在网络或者其他整合生产消费的数据层之上的层,更多的是需要对数据生产消费的整合和加工,跟网络库本身没有可比性 |
39
lesismal OP @fucUup 网络框架这一层处理数据收发。rpc 请求的限制,你在 rpc 框架收发数据的层完全可以自己限制。
兄弟,分层的理念你可以再加深下理解,不同的层处理自己的事情,从内核到应用,或者网络协议栈不同的层,都是各自处理自己层内的事情,该留给更高层去处理的留给更高层去处理,否则就拿你 rpc 4M 的来举例,如果网络库这一层写死了限制 4 M,你在其基础之上实现的 rpc 框架舒服了,但是其他人在其基础之上实现的其他业务可能需要大于 4M,那怎么办?所以,下层在自己层内资源可控的前提下提供上层所需的扩展机制、接口,而不是下层直接做这些限制 |
40
wslzy007 2021-02-28 19:44:07 +08:00
@lesismal 网络库最终还是要加载协议的,哪怕是简化版协议也行啊,等你的 http 协议对接后我测测。用数据说话最直接
|
41
newmlp 2021-02-28 19:48:52 +08:00
单机百万的轮子好多,随便写
|
42
lesismal OP @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 每一项都需要较多时间,慢慢搞 |
44
lesismal OP @newmlp 百万连接不是什么难事,难的是大量连接下的高请求量、吞吐量。真实的商业项目也很少真正单机搞百万连接的,避免万一故障。
但是不同框架对高连接数的优化,不只是为了达到百万连接数的目的,而是在这个基础上对整个系统各项资源消耗和指标的优化,对于 golang,同步模式的大量协程带来的内存和 cpu 调度浪费太大,异步框架还是有很大意义的 |
45
lesismal OP 希望能让 go 支持更广泛的业务,否则单就高阶的高并发,还真难干得过 java netty 或者其他异步方案
|
46
ERRASYNCTYPE 2021-03-09 14:10:20 +08:00
@byte10 为什么 golang 占的要比 node 高这么多,我的经历是 golang 跟 node 写同样业务的 http 服务,golang 的内存能明显小于 node
|
47
byte10 2021-03-09 15:04:04 +08:00
@ERRASYNCTYPE 我也不太清楚,nodejs 的其实也是有协程,跟 Kotlin 应该比较相似。go 的协程叫做纤程,虚拟线程也合适,它更像线程。我估计就是这些占用了内存了吧
|
48
lesismal OP @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,最大程度减少跨协程数据传递和调度的成本,细节我会在以后的帖子中慢慢整理,最近都忙于编码,还有很多细节或者性能优化可以做 |
49
lesismal OP @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 更强 |
51
lesismal OP @byte10 nbio http 如果想支持 fasthttp 这种也不难,参考默认的支持标准库的 Processor 实现一份 Processor 就行了,不过我暂时没当期在 nbio 自带一份实现给它,以后闲了考虑给它写个
|
52
lesismal OP |
54
lesismal OP 也不知道楼上有几位都是啥情况,老夫如此热情,连句话都不回,是因为看不懂吗。。。
|
55
foam 2021-05-12 23:59:38 +08:00 via Android
支持一下
|
56
kksco 2021-05-13 16:50:34 +08:00
邮件提醒我 github golang 的一个 issues 有更新,偶然翻到大佬这个仓库,已 star 支持一波
|
59
towser 2021-08-10 20:29:14 +08:00
两位老哥吵了半天都没有急眼说脏话,君子之争令人愉悦。
|
62
dubdub 2022-02-27 17:23:40 +08:00
> 用于读取的内存分配可由应用层定制,方便业务层做更适合的定制,这个不同场景可以玩很多姿势,简单的 pool 未必是最优
请教一下大佬还有什么其他姿势呢 |
63
lesismal OP @dubdub 比如标准库 tls 或者其他一些地方,或者 fasthttp 里,用到 2^N size 对齐的多级 pool ,nbio 里用的不是固定 size 的,go 的 gc 无法确定内存的精确释放时机,如果需要比较精准控制,甚至可以 cgo 直接调用 malloc 这些,得看实际需要了。
|
64
kingcanfish 2022-03-12 17:57:58 +08:00
虽然我不知道争论谁有道理 但是看帖子能学到很多知识(学生狗如是说
|