一、背景
生产环境某应用运行在容器集群中,此模块pod在配置2个实例,每个pod规格为4c8G。查看异常日志如下:
[o.a.http.impl.nio.client.InternalHttpAsyncClient] [] >>> I/O reactor terminated abnormally
org.apache.http.nio.reactor.IOReactorException: I/O dispatch worker terminated abnormally
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:359)
at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:221)
at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase$1.run(CloseableHttpAsyncClientBase.java:64)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.OutOfMemoryError: Java heap space
at org.apache.http.util.ByteArrayBuffer.expand(ByteArrayBuffer.java:57)
at org.apache.http.util.ByteArrayBuffer.append(ByteArrayBuffer.java:87)
at org.apache.http.util.EntityUtils.toByteArray(EntityUtils.java:139)
一旦 IO worker异常退出,会导致后续的请求无法进行,HTTP CLIENT IO线程退出。
二、排查步骤
按理说查询代理模块工作任务并不繁重,主要承担查询转发逻辑,理论上8G内存应该不出问题,固问题应该在8G内存无法使用导致。通过ps -ef 查看运行命令如下:
java -server -jar app-xxxx.jar
为指定JDK的启动内存配置,由于使用的是JDK8,查询官方文档显示,在不指定情况下,JDK通过操作系统&内存的大小动态计算得到最大可使用的内存:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html#default_heap_size
通过在容器内执行 java -XX:+PrintFlagsFinal -version | grep MaxHeapSize 得到:
即 2147483648 bytes = 2G,可以知道,在不声明内存情况下,此容器规格(8G)默认只能使用2G的heap内存。规格为8G也利用不起来,固一旦超过2G内存则会触发OOM,从而导致后续的请求异常。
三、解决办法
由于启动命令为 java -server ${JAVA_OPTS} -jar app_xxxx.jar
固环境变量中增加 JAVA_OPTS 值为 -Xms1g -Xmx7g 即可,如下图:
另外同时注意filecache占用的内存,在容器中filecache也认为是一种内存占用,并且可能会触发容器OOM KILL。