public static MdcThreadPoolExecutor getMdcPool() {return new MdcThreadPoolExecutor(8, 32, 1, TimeUnit.MINUTES,new LinkedBlockingQueue<>(10240),new NamedThreadFactory("MDC_POOL-",false));}
问题1: 一开始应该是打算写工厂类,单例线程池的,后面估计忘了变成了每次都new一个线程池。
问题2:线程数,队列数是否合理?没有尝试压测。试想一下,如果sql都是一些慢sql,300ms左右,那8个核心线程1s能处理 1/0.3*8≈24个任务。
假设某个时刻qps是50,即每秒+50-24,也就是每秒50-24=26个任务进入队列,需要390s约等于6分半钟队列才满,然后增加线程提高处理速度。 换个角度,如果不考虑超时,如果刚刚好10247个任务同时请求,8个核心线程开始工作,10247-8=10239个任务在队列里,最后一个任务需要等10239/24=426s也就是7分钟才能轮到它,当然这是极端情况,但也就意味着有可能会有一些任务在队列中等待过久超时
一开始还没发现这个问题,在测试环境用jmeter压测的时候,发现程序老崩溃。
jvm启动命令加了HeapDumpAfterFullGC
),而且加大了内存,后面压测的时候jstat -gc [pid] 1000
也没看到gc飙升,说明内存是够用的dmesg -T|grep java
看到kill日志是前几天的hs_err_pid.log
,然后看到说swap内存不够,不是堆内存不够也不是metaspace元空间不够,然后查了资料,发现是因为线程数太多这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下:
具体计算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
总结下影响Java线程数量的因素:
ulimit -u
查看), /proc/sys/vm/max_map_count。从我看到的错误日志errno=12,应该属于内存不足以至于不能创建新线程