线程池
都说线程池不要滥用,本周踩了一个坑,深有体会。业务服务器一直是4核16G配置,单程承载1000QPS,经查看服务器磁盘、IO、内存等资源都很充足,只有CPU负载很高,于是将一个机器升级到8核,并分配给了之前两倍的流量,刚切换时运行得挺好的,但运行一段时间之后,就会出现爆内存问题。查看监控记录,发现老年代会一直增长,即使FullGC之后也会比之前高,积累到占满堆内存后,就无法再GC,怀疑是由内存泄漏,dump下内存进行查看,原来是线程池的队列达到了几百万,占满了内存。
这里用到线程池是在业务代码完成后发送mq消息,由于消息量很大,就把这个操作放到了线程池,但是这里定义线程池时写死了coreSize,本来4核机器上的线程数是能够消化请求量的,但到8核的机器上就不够用了。于是将coreSize改为CPU核数的指定倍数,问题基本解决了。但是问题并没有彻底解决,因为一旦QPS升高,还是会出现堆积,于是加了一个监控,定时打印出线程池的运行状况,包括活跃线程数、当前队列数等参数,方便了解线程池的负载。另外需要做服务拆分,将统计服务单独拆分出来,前端纯统计请求走这个单独的服务。
网上查到一个计算coreSize的公式:coreSize = NCPU *(1 - 等待时间/计算时间),大概就是如果线程池的任务等待时间相比计算时间比值越大,coreSize就越高,实际项目可以以此为参考,比如如果任务是IO密集型的,coreSize可以配置比较高,如果任务是计算密集型的,coreSize相应就要低。
Spring全家桶
项目中天天在用Spring,但其实一直没有真正明白Spring,搞不懂如何定义它,这几天看了《Spring实战》,书中总结的很好,Spring是一个提高Java开发效率的框架,主要体现在以下四个方面:
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
如今Spring全家桶已经非常丰富,可以做很多事情,但Spring框架之所以优秀的本质还是以上几点。
JVM
由于服务器性能问题,本周又被逼研究了下JVM性能分析,列一下几个主要的命令
# 查看所有java进程
jps -mlv
# 查看java进程状态
jstat
# 查看java进程GC信息,每10s打印一次,总共打印4次
jstat -gc PID 10s 4
# 查看java进程运行时参数
jinfo -flags PID
# 查看堆信息
jmap -heap PID
# 查看线程信息,可检测死锁
jstack PID
复制代码end
本文分享了一位全栈工程师在业务服务器升级过程中遇到的线程池调优经验,详细分析了线程池参数设置不当导致的内存泄漏问题及解决方法,并探讨了Spring框架的核心价值和使用心得。

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



