**CPU 高使用率及服务重启问题调查小记**
最近在H项目实施环境中,某业务应用服务在业务高峰期间出现 **CPU 使用率长时间维持在 90% 以上** 的告警,同时伴随 **服务频繁重启**
的现象。这一问题直接影响系统的可用性,导致用户操作中断、运行中数据丢失、以及第三方系统调用失败等严重后果,已成为最高优先级的生产事故。
在此之前,虽然偶尔出现过 CPU
使用率较高的告警,但频率很低,且大多为瞬时高峰现象。我们初步判断这些告警与用户的批量操作有关,并未引起足够重视。然而,近期问题表现出以下特点:
1. **高频率告警** :告警频次显著增加,且集中在业务高峰时段。
2. **长时间高占用** :CPU 使用率长时间维持在 90% 以上,未能及时回落。
3. **频繁服务重启** :服务在 CPU 高占用期间频繁宕机重启,进一步加剧系统不稳定性。
为快速缓解当前生产环境的高优问题,项目组采取了两步临时应对措施:
1. **临时扩容资源** -与基础设施团队(Infra)协作,调整 Kubernetes(K8S)中对应业务应用的POD 配置:CPU 和内存资源翻倍:提升单个 POD 的资源上限,降低服务频繁重启的概率,缓解生产环境的紧急状况。
2. **成立技术调查小组** -项目组成立临时技术调查小组,集中资源和精力对问题进行深入分析和彻底解决。
尽管我们在资源扩容后,成功降低了服务重启的频率,但 **CPU 使用率依然持续飙升**
,且服务偶尔仍会重启。虽然短期内减少了重启次数,但问题的根本原因并未得到解决。系统负载依然过高,给业务稳定性带来了隐患。当前的状况就像是
**悬在头上的一把刀** ,不断督促我们必须尽快找到并解决根本原因,以确保系统的长期稳定运行。
同时调查小组已开始深入开展问题排查,调查思路如下:
1. **分析 API 调用频率** \- 定位问题发生前后的 API 调用频率,检查是否存在异常的高频调用或响应时间较长的接口。确定是否有某些 API 在高负载期间被频繁调用,从而导致 CPU 使用率飙升;
2. **模拟压测并复现问题** \- 针对频繁调用或响应缓慢的 API,在测试环境中进行模拟压测,尽可能复现生产环境中的问题。通过模拟高并发请求,验证是否某个特定接口是引发生产问题的根本原因;
3. **代码分析与优化** \- 确定问题所在的接口后,进行详细的代码分析,查找潜在的性能瓶颈。针对发现的问题进行优化,改进接口性能或调整处理逻辑,减少资源消耗;
4. **确认问题解决** \- 完成优化后,再次进行压测,验证问题是否已解决,并确保在高负载情况下系统稳定运行。
这里不得不提一下 **Glowroot** 工具,在调查 API 过程中,我们首先考虑并搭建了 Glowroot
监控工具,它提供实时和历史性能监控,展示详细的性能指标,极大地帮助我们排查和定位每个 API 的调用频率和性能瓶颈。
由于时间紧迫,调查小组在分析 API 调用频率和模拟压测方面进行了并行处理。我们在排查到疑似问题的 API
后,立即同步进行了测试环境压测,并尝试复现生产环境中的问题。然而,在排查了若干 API
后,尽管进行了压测,但始终未能复现生产中出现的异常现象,这使得我们感到非常焦虑。
由于压测未能复现问题,调查小组召开了紧急会议,进行信息同步并进一步分析。通过 **Glowroot 监控** ,我们发现已排查完 **TOP10**
关键接口,但问题依然未得到有效复现。由此,我们快速确定了下一步的调查方向:
**加大压测数据量和并发** :通过提高压测的规模,尝试更精确地复现生产中的问题;
**扩大 API 排查范围** :除了现有排查的接口,进一步扩展调查范围,检查是否存在其他未发现的类似问题,并进行压测复现。
最终,通过分析生产环境中的 API 调用参数,并加大压测数据量和并发,我们成功地复现了生产中的问题,最终定位到问题的 **根本原因 API** 。
一旦定位到问题根源的API,接下来的工作就聚焦于分析和优化代码。虽然仍需深入解决问题,但至少方向已明确,大家稍微松了一口气。
CPU 使用率高通常由以下原因引起:高并发请求、不高效的算法或代码、数据库瓶颈、频繁的 I/O
操作、内存泄漏或内存过度使用、线程池或资源管理不当、垃圾回收(GC)等。接下来,我们将围绕这些方向展开代码分析,制定针对性的优化方案,彻底解决问题。
在此,我还想给大家推荐一个非常实用的工具—— **Arthas** 。Arthas 是一个功能强大的 Java 诊断工具,能够在运行时动态地对 Java
应用进行分析和调试。它提供了丰富的命令集,可以帮助我们实时查看系统的运行状态、分析代码瓶颈、查看线程堆栈、监控方法调用等。通过使用
Arthas,我们可以更加高效地排查和解决问题,尤其在生产环境中进行在线调试时,它非常有价值。
在使用 Arthas 分析接口性能时,我们最终定位到一个拷贝操作,导致内部内存泄漏,进而引发了 CPU 占用率持续高的问题。
高并发调用 **SerializationUtils.clone** 引发了性能瓶颈和内存溢出问题。具体原因如下:
**CPU 占用** :序列化和反序列化是 CPU 密集型操作,特别是在处理较大的对象或复杂对象图时,CPU 占用会显著增加;
**内存压力** :每次序列化都会生成临时的字节流对象,在高并发环境下,频繁的内存分配和回收可能导致 **垃圾回收压力增大** ,甚至引发 **内存溢出**
。
接下来就简单多了,我们与产品技术团队进行深入沟通,制定并实施代码优化方案。优化完成后,我们也进行全面的压测,以确保问题得到彻底解决。与此同时,在排查过程中,我们还发现了其他
API 的性能问题,已将其纳入排期进行优化,确保系统的整体稳定性。
**总结**
:在项目开发中,应谨慎使用拷贝操作,避免因频繁的内存分配导致内存溢出。同时,要实时关注生产环境的运行情况。一旦出现异常,需快速排查原因,精准定位问题,随后进行优化。此外,生产环境的监控和问题排查离不开专业工具的支持。本次项目中,我们使用了
**Glowroot** 和 **Arthas** ,它们在快速定位问题方面发挥了重要作用,强烈推荐大家在日常开发和运维中加以使用。
**END**
作者 | 袁国庆
审核 | 梁 超
编辑 | 王 锐