moqsien / niogin

NioGin is a Non-blocking implementation of Gin. All functionalities from Gin are supported by NioGin. 异步gin框架。
MIT License
1 stars 0 forks source link

可能存在与gobwas/ws同样的问题 #1

Open lesismal opened 1 year ago

lesismal commented 1 year ago

我看到readme中的描述:

本项目主要参考和使用了Thanks To中的项目,适用于学习eventloop的实现,以及对单机性能要求较高的场景。代码注释和实现逻辑描述比较清楚,比nbio和gev学习起来更方便。性能理论上比gev要强,没有nbio混乱的engine,request读取使用的是官方包的方法,比较清晰;因此可以方便地利用Gin的router、middleware、Context封装,得到一个功能完善的http server。

没有完整读作者的代码,但猜测(这类问题与线头阻塞是类似的): 既然request读取使用了官方包的方法,那说明就是阻塞读,所以其实你的eventloop只是处理读写事件,可读的时候让协程来处理读。但是真实的网络环境可能没那么顺畅,不能保证一次刚好读到一个完整包,所以这个连接就可能一直占用一个协程。这并不能保证比标准库节约协程,性能也不比标准库好。 我没有深入看这个库的代码,但是扫到一眼httpserver用的是标准库的tls,这同样是阻塞的读,与request的读一样的。

真正的异步框架,不只是io事件触发,还要包括异步/流式解析器之类的。

gobwas存在同样的问题,我在它的issue列表里参与了一些讨论。

nbio混乱的engine,两个原因,一是少注释,二是支持的功能、可扩展的点太多。 少注释是因为很多点,不太好阐释清楚,也不想加中文注释,所以放空了很多注释,另外就是代码并不复杂、没那么重的模式,除了并发需要想象力,普通部分的代码还算容易理解。文档、甚至出一份详细的教程是我想要做的,但是写通俗易懂的文档教程甚至比代码海南,所以目前没那么多档期去整理。

但是对于nbio混乱的engine的说法,我不太敢赞同。框架实现是复杂一点,因为功能确实有点复杂,但是对于用户而言,几乎是透明的,而且基本都提供了默认配置,默认配置通常足够用户跑出不错的效果了,而且nbio的http对标准库的兼容性也是很easy,不只是gin,基于标准库的其他框架也一样替换下网络层就可以了。曾经还想支持下fasthttp,但fasthttp一些字段是private的,给提过issue希望开放这些字段,但涉及到对老用户旧版本兼容性、所以放弃了。分阶段搞,优先考虑用户方便,文档注释代码结构重构都得等以后有档期再搞了。 其他一些框架,使用起来才是有点虐心吧。

lesismal commented 1 year ago

本来的纯异步,目测目前除了gev是异步解析websocket,其他poller框架都没支持,tls/http/websocket全异步解析的好像也只有nbio一个。 另外就是,近期nbio支持了http/websocket的多种IO模式,性能需求场景得到提升,并且混合模式能和承载量低占用做到更好的平衡,这目前应该也是整个社区独一份的,欢迎来交流: https://github.com/lesismal/nbio/releases/tag/v1.3.5

lesismal commented 1 year ago

看了眼gknet,应该也是标准库的tls和http读写,那么存在同样的问题。

阻塞IO接口,不只是读可能持续占用一个协程,如果支持了websocket之类的,涉及到广播的时候,写单个连接也是可能阻塞的,那么广播的循环遍历所有连接时,就会造成一个连接卡了导致其他连接都跟着等待的问题。 如果你的设计目标不是减少CPU内存占用,那倒是可以,但另一个问题就是这种实现并不比标准库有所提高。 字节的rpc框架虽然也是基于自己实现的netpoll,但他们的目的好像主要是提升响应速度,而占用似乎甚至比标准库更高,相当于空间换时间了。在这种目的明确的情况下,异步+同步IO接口才有效,否则实现起来bu难、意义不大

moqsien commented 1 year ago

看了眼gknet,应该也是标准库的tls和http读写,那么存在同样的问题。

阻塞IO接口,不只是读可能持续占用一个协程,如果支持了websocket之类的,涉及到广播的时候,写单个连接也是可能阻塞的,那么广播的循环遍历所有连接时,就会造成一个连接卡了导致其他连接都跟着等待的问题。 如果你的设计目标不是减少CPU内存占用,那倒是可以,但另一个问题就是这种实现并不比标准库有所提高。 字节的rpc框架虽然也是基于自己实现的netpoll,但他们的目的好像主要是提升响应速度,而占用似乎甚至比标准库更高,相当于空间换时间了。在这种目的明确的情况下,异步+同步IO接口才有效,否则实现起来bu难、意义不大

是的,后面有时间会改。方便分享一下nbio对tls的修改在哪些地方吗?比如哪些.go文件的哪些方法等,我去学习一下,感谢!

lesismal commented 1 year ago

主要是协议解析的地方,未读到完整包就把当前数据缓存起来,等下次有数据来了append了再继续根据当前的state解析,同步读不需要这种。因为tls本身有点复杂,改动的地方比较多,也是模拟粘包测来测去的搞了很久。改的时候是用的go1.16的源码,可以直接对比下差异。 改动的方式难度不大,主要是琐碎、要覆盖到位。