最近测试提了个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 Error 为OOMKiller,莫名奇妙,文件上传怎么会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,使用堆外内存只需要在堆上分配一个指针指向堆外内存即可

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

1650

被折叠的 条评论
为什么被折叠?



