在k8s下坑人的OOM问题

本文讲述了作者在处理Spring Cloud Gateway中批量图片上传引发的500错误时,发现是由于过大文件导致堆外内存不足引发的OOM。通过排查和调整配置,揭示了堆外内存的重要性及nio DirectByteBuffer在大文件传输中的作用。

最近测试提了个bug,说批量图片上传会返回500错误。然后我弄了两个zip压缩包一个3MB,一个120MB,发现3MB的压缩包每次上传都没问题,而120MB的每次上传都会报500,于是上spring cloud gateway网关查看了下日志,发现网关报了一个莫名奇妙的错误

Connection prematurely closed BEFORE response

意思为连接在响应前过早关闭了。显得莫名奇妙,然后拿着这个报错百度google了一番,没找到答案,于是换个方向。小文件没有问题,而大文件出问题,那么会不会是spring cloud gateway 不支持大文件上传?然后到官方找对应issue,果然找到了一个类似的issue是17年的。dose gateway support large file transfer,然而并未找到答案。又去问了下测试,以前可不可以,测试说,以前是正常的。就是这段时间不行的。原因是这个接口改动了。然后本地起项目调试了下,发现一切正常。然后又测试了下测试环境的,发现每次返回这个错误的时候,相关服务就宕机重启了。好吧,去看下pod的状态

kubectl -n test describe po/xxxx 

查看Last ErrorOOMKiller,莫名奇妙,文件上传怎么会oom呢?然后去看了下相关配置
k8s 的配置

resources:
  limits:
    cpu: 2
    memory: "4Gi"
  requests:
    cpu: 2
    memory: "4Gi"

jvm配置

"-Xms4096m -Xmx4096m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m

我的天,开发在部署项目的时候啥都不看的,这样配置肯定导致native memory不足啊。接着又去看了下代码。
所以里面调整下参数,预留500MB给native重启下,在测试下,果断就好了。
所以部署项目的时候还是要稍微注意下此类问题。不然排查问题又要老半天。
那么这里引出一个问题。不管有没有以上问题,这个堆外内存预留本身就是必要的。

为什么要预留的原因

  • 操作系统本身需要一定的内存空间运行
  • java的应用除了metaspace本身占用了堆外内存外,还有其它的方式可能占用堆外内存,比如nio,jni等。

关于堆外内存

  • 堆外内存的最大大小可以通过 -XX:MaxDirectMemorySize 设置
  • Java VisualVM中可以安装Buffer Pools插件监控堆外内存

所以规划好内存是一件极其重要的事情。比如给docker分配了多少内存,给堆多少,给元空间多少,应用有没有使用直接内存的情况,该预留多少。
而此次oom的原因就是没有堆内存做规划,图片批量上传,由于文件比较大,使用到了nio的堆外内存.

关于NIO

在NIO中使用FileChannel作为读写文件的通道,并且读写使用了缓冲区。而这个缓冲区有两种实现,一种是使用堆内存HeapByteBuffer,第二种是使用堆外内存DirectByteBuffer,使用堆外内存只需要在堆上分配一个指针指向堆外内存即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值