-
Notifications
You must be signed in to change notification settings - Fork 537
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
request context pool 回收机制影响到了 bytebuffer pool 的分配计算,导致系统容易发生OOM #1026
Labels
bug
Something isn't working
Comments
可以提一个修改默认 maxKeepBodySize 的 PR,以及可能的话,添加一个测试来保障修改效果 |
@784909593 If there is anything different to what has been concluded here, please provide more context for others to catch up. |
784909593
changed the title
request context pool 和 bytebuffer pool 的配合设计不合理,导致系统容易发生OOM
request context pool 回收机制影响到了 bytebuffer pool 的分配机制 ,导致系统容易发生OOM
Jan 27, 2024
784909593
changed the title
request context pool 回收机制影响到了 bytebuffer pool 的分配机制 ,导致系统容易发生OOM
request context pool 回收机制影响到了 bytebuffer pool 的分配机制,导致系统容易发生OOM
Jan 27, 2024
这里我想到了两种修复方式
|
784909593
changed the title
request context pool 回收机制影响到了 bytebuffer pool 的分配机制,导致系统容易发生OOM
request context pool 回收机制影响到了 bytebuffer pool 的分配计算,导致系统容易发生OOM
Jan 28, 2024
To Reproduce 单测: func TestBigBodyBug(t *testing.T) {
} 在这里增加一行日志,用来观测body大小
} |
可以加一个单测看一下修复后的效果吗? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Describe the bug
request context pool 回收机制影响到了 bytebuffer pool 的分配机制,导致系统弹性变低,系统在遇到偶发异常的情况下,会更容易OOM。
代码分析:
这里是用 response body 的 len 进行判断的,而不是 cap。如果 body 的 cap 较大,但是 len 较小时,这个 body 对象是不会被 put 回 responseBody pool 中的。也就是说,如果最初 Hertz 从 reponseBody pool 中取出的是一个较大的对象时,而这次请求返回的 response 数据又较小时,这个 body 对象是不会被重新 put 回 responseBody pool 中的,而是继续被 requestContext 持有,并一起被 put 回 requestContext pool 中。
如果 response body 的 len,小于 MaxKeepBodySize(默认 4M),那他会被放在 requestContext 内。而大于 MaxKeepBodySize 会被放回 reponseBody pool 中。因此这个过程相当于起到了一层过滤的作用,只有大的 body 会被 Put 回 reponseBody pool 中,也就是说在 Put 方法中统计到的 body 大小,都是大于 MaxKeepBodySize 的。这就导致了 reponseBody pool 在触发 Calibirate 方法对 defaultSize 进行重计算时,会将 defaultSize 调大到一个大于 MaxKeepBodySize 的值。
线上流量源源不断,Hertz 框架总会调用到 responseBody pool 中的 Get 方法创建新的 body 使用,而新分配到的 body 大小都将是大于 MaxKeepBodySize 的 defaultSize(我们场景下为 16M),这些新分配的 body 如果遇到了 response 数据较小的接口,那又会因为缓存机制分析一节中提到的 len 和 cap 的判断差异问题,这些大 cap 小 len 的 body 无法被放回到 responseBody pool 中,最终导致 requestContext pool 中所有 requestContext 的 response body 的大小都会变为 defaultSize(即 16 M)。
这就会使得在突发流量到来,或者旧的的请求在异常情况下无法结束使得 requestContext 无法释放时,框架会为新来的请求创建大量 defaultSize (16M)大小的对象,导致系统弹性很低,进而发生 OOM。
Expected behavior
框架不要做超出正常流量的内存分配
Screenshots
Hertz version:
v0.6.7
Environment:
go 1.21
The text was updated successfully, but these errors were encountered: