
生产环境中经常遇到这样的场景:监控系统报警显示服务无响应,但检查发现进程仍在运行,端口正常监听,CPU使用率异常(可能是100%或接近0%)。这种现象称为"服务假死"。
服务假死的核心特征:
与服务宕机不同,假死状态不会触发进程自动重启,会持续占用系统资源,影响范围更大。
问题表现: 应用线程大量阻塞在获取数据库连接的操作上,通过jstack可以看到线程堆栈停留在DataSource.getConnection()方法。
根本原因:
解决方案: 根据业务并发量合理设置连接池参数(最大连接数、最小空闲连接数、获取连接超时时间),优化慢SQL,使用连接池监控工具(如Druid)及时发现连接泄漏。
问题表现: 应用无法处理新请求,线程池队列已满,拒绝策略被频繁触发。
根本原因:
解决方案: 根据业务特点设置合理的线程池参数。对于IO密集型任务,线程数可设置为CPU核心数的2-3倍;对于CPU密集型任务,设置为CPU核心数+1。不同业务场景使用独立线程池,避免相互影响。Web请求处理应使用快速失败策略,批量任务可使用调用者运行策略。
问题表现: 日志中出现大量"Cannot get Jedis connection"或"Connection timeout"异常,接口响应时间显著增加。
根本原因:
解决方案: 优化Redis连接池配置,设置合理的超时时间(建议3-5秒),对Redis操作实施降级策略。避免使用大key,定期清理过期数据,必要时使用Redis集群分散压力。
问题表现: 应用线程大量阻塞在HTTP调用或RPC调用上,Tomcat工作线程耗尽。
根本原因:
解决方案: 所有外部调用必须设置超时时间(连接超时建议3秒,读取超时根据业务设置5-10秒)。引入熔断降级机制(如Hystrix、Sentinel),当下游服务异常时快速失败,避免雪崩效应。
问题表现: 通过jstack可以检测到死锁,相关线程永久阻塞。
根本原因:
解决方案: 避免嵌套锁,统一锁的获取顺序。使用Lock接口的tryLock方法设置超时时间,优先使用JUC并发工具类(ConcurrentHashMap、CopyOnWriteArrayList等)替代synchronized。
使用jstack导出线程堆栈是定位问题的关键手段:
jstack <pid> > thread_dump.txt重点关注线程状态:
如果发现大量线程堆栈相似且处于等待状态,说明存在资源瓶颈。例如,大量线程阻塞在DataSource.getConnection(),说明数据库连接池耗尽。
执行MySQL命令查看当前连接情况:
SHOW PROCESSLIST;关注TIME列较大的连接,这些可能是慢SQL。结合慢查询日志分析具体SQL语句,优化索引或改写查询逻辑。
检查CPU、内存、网络IO等系统指标:
所有外部依赖调用必须设置超时参数,建议值:
建立多层次监控:
设置合理的告警阈值,避免告警疲劳。关键指标应设置多级告警(预警、严重、紧急)。
定期进行压力测试,模拟生产环境流量:
服务假死问题的本质是资源耗尽或线程阻塞。通过合理的配置、完善的监控、规范的编码,可以有效预防此类问题。当问题发生时,系统化的排查方法能够快速定位根因。建议团队建立故障知识库,积累问题处理经验,提升整体应急响应能力。