说明
本篇博文主要记录之前线上项目由于线程数过多导致内存溢出后,事故原因的分析排查过程。项目背景是其中使用了公司封装的管理类来操作RabbitMQ。
正文
初步猜想
项目出现oom后发现是线程数过多导致内存泄露,快速进行了重启。重启后,仍发现线程数在不断地增长。 查看代码发现,在从mq获取到消息后会进行http请求调用其他服务。查看工具类,发现每次请求都会新建CloseableHttpClient对象,请求完成后调用close()方法关闭连接。所以怀疑是连接没有关闭导致线程泄露。
对此,我们修改了工具类,创建CloseableHttpClient单例对象,并且使用连接池管理,自定义线程保活策略。设置最大连接数为50,默认最大单路径连接数为5,连接最长存活10s。
private static final int MAX_TOTAL = 50;
private static final int DEFAULT_MAX_PERROUTE = 5;
private static final int KEEP_ALIVE_TIMEOUT = 10 * 1000;
private static CloseableHttpClient HTTP_CLIENT;
static {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(MAX_TOTAL);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PERROUT