gnet-io / gnet-benchmarks

Benchmark test of gnet
MIT License
34 stars 12 forks source link

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

Closed lesismal closed 2 years ago

lesismal commented 2 years ago

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

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

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

  1. 按照每个连接持有cache的方式,则cache需要的内存为 cache size * 1000k
  2. 按照每个协议包解析后释放,则每个连接最大持有协议包数量为 qps 个,则cache的内存只需要:cache size * 50k,节约了很多

4层的网络库在结合7层的实际应用并且遇到海量连接数时,仍然会有很多很多细节需要优化,ring buffer可能不是银弹。

lesismal commented 2 years ago

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

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