Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ring buffer在高在线量场景可能导致高内存占用 #114

Closed
lesismal opened this issue Feb 3, 2022 · 4 comments
Closed

ring buffer在高在线量场景可能导致高内存占用 #114

lesismal opened this issue Feb 3, 2022 · 4 comments

Comments

@lesismal
Copy link

lesismal commented Feb 3, 2022

昨天看到自己仓库中的 Used By 有 github.com/gnet-io/gnet-benchmarks 这个仓库,去回访下,但是没看到我的库相关,所以浏览了下 issue ,看到 3 中各位关于 ring buffer 的讨论。刚好前阵子有人在我的 issue 中提到能不能支持 ring buffer,应该是看到你们其他各位作者的库有使用 ring buffer 所以也给我提起的,在 gnet-benchmarks 中提了issue,来这里也再交流下关于 ring buffer 的思考。

对于异步库,减少了大量的协程数,缓解了内存、gc、调度、stw,但是我自己库的早期版本进行http压测时仍然遇到高内存占用,其原因主要是 7层协议codec过程中 half-packet 需要为未解析完整的数据进行缓存,以及魔改标准库 tls 过程中 tls 原有的 bufio 等数据缓存,因为旧的方案每个连接上都挂载有一个或者多个这种 buffer 作为缓存,所以当连接数很高时,这些缓存数据结构的内存占用仍然很高、负担较大,bufio或者ring buffer都存在类似的问题,当遇到单个连接的类似大包体攻击的场景,这种问题会更加明显,大包体的问题,通常需要对单个连接最大包size进行限制,超过了就close,这点我早就做了,所以解决数据缓存占用高的问题,改成了解析到完整的就释放掉,正常的数据通信,绝大多数也就是这种。

举个例子,在线量1000k,qps 50k:

按照每个连接持有cache的方式,则cache需要的内存为 cache size * 1000k
按照每个协议包解析后释放,则每个连接最大持有协议包数量为 qps 个,则cache的内存只需要:cache size * 50k,节约了很多
4层的网络库在结合7层的实际应用并且遇到海量连接数时,仍然会有很多很多细节需要优化,ring buffer可能不是银弹。

@lesismal
Copy link
Author

lesismal commented Feb 3, 2022

另外,异步库与标准库单纯对比吞吐量,其实实际意义也不大,因为标准库方式的包体解析逻辑可能更简单,并且异步库解析完整包后通常需要跨协程传递再由其他逻辑协程池处理,时空亲和性、调度亲和性、生命周期等各种实际情况加起来。

7层业务下、普通在线量比如不同硬件规格10-100k这种量级,异步库未必比标准库有相应性能的优势

@lesismal lesismal closed this as completed Feb 3, 2022
@Choubeihai
Copy link

虽然我读懂了,但是还是建议你发表这种见解时组织一下语言。

@lesismal
Copy link
Author

虽然我读懂了,但是还是建议你发表这种见解时组织一下语言。

单就内容本身,已经表达的够清楚了,问题本身稍微有点复杂,即使再加上1、2、3、表格,一般的逻辑程序员也看不懂。这个只是给 Allenxuxu 交流、建议的,目测应该能看懂的

@lesismal
Copy link
Author

虽然我读懂了,但是还是建议你发表这种见解时组织一下语言。

我在 nbio 里做了很多功能支持和细节优化,tls/http/websocket,both server and client side,http的标准库兼容,websocket的全量测试,但这些都不是最难的。
最难的是把这个几个层的内存优化打通。不能简单使用2^N的内存池,因为异步流解析涉及half-packet,而且需要应用层协成池,所以buffer是需要跨协成传递的,buffer生命周期不确定,不能像使用net.Conn的方案那样简单地为每个连接复用同一个buffer(阻塞读一个、处理一个、然后再读下一轮读和处理)。
整体来说,去年优化内存这块花费了我最多的时间,其次是魔改标准库的tls支持异步流解析。

从某些使用方式的角度讲,异步库使用2^N的内存池在parser解析的过程中可能会有更多性能浪费,或者用ring buffer作为读或者写的cache与连接绑定、在连接数很大的时候会造成巨大内存消耗、甚至节省的协程数量的资源都无法弥补回来

这次还是没组织语言,能看懂就行吧,这些都是实现过程中总结的,我还希望在有可能的地方继续提升自己的库,所以希望跟大伙多多交流

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants