怎么排查页面响应慢的问题
一、排查流程图
+-----------------+
| 全局监控报警触发 |
+-----------------+
|
▼
+-----------------+
| 定位异常服务节点 |
+-----------------+
|
+---------+---------+
▼ ▼
+-----------------+ +-----------------+
| 基础设施层排查 | | 应用层代码排查 |
| (网络/硬件/OS) | | (线程/GC/锁等) |
+-----------------+ +-----------------+
| |
▼ ▼
+-----------------+ +-----------------+
| 中间件层排查 | | 依赖服务排查 |
| (DB/缓存/MQ等) | | (下游接口/SLA) |
+-----------------+ +-----------------+
二、分层排查方法论
1. 基础设施层排查
(1) 网络问题
-
排查工具:ping、traceroute、mtr、tcpdump、netstat
-
关键指标:
- RTT (Round Trip Time):如果大于50ms,需要警惕。
- 丢包率:>0.1%即可能引发重传,影响服务稳定性。
- 带宽利用率:接近带宽上限时,系统可能触发瓶颈,影响通信。
-
常见问题:
- 跨机房调用未走专线:通常由于公网不稳定引发,可能导致时延和丢包。
- 容器网络虚拟化层丢包:可能由于Calico/IPVS配置问题,建议检查容器网络的配置。
-
优化措施:
- 配置专线,优化公网带宽
- 在容器化环境中,调整网络策略或切换网络插件
(2) 硬件资源
-
排查工具:top、vmstat、iostat、free、sar
-
关键指标:
- CPU利用率:若User% > 70%,可能意味着应用的瓶颈,考虑优化代码或增加资源。
- 内存使用:Swap使用率 > 0 即有潜在风险,系统可能开始使用交换空间,性能下降。
- 磁盘IO:
await > 10ms
时,需要优化磁盘读写。
-
常见问题:
- 宿主机超卖导致CPU争抢:常见于容器化环境中,多个容器争夺CPU资源。
- 日志未异步写入导致磁盘IO打满:高并发情况下同步日志写入可能影响磁盘IO性能。
-
优化措施:
- 调整CPU资源配额或考虑优化容器调度策略。
- 使用异步日志框架(例如Log4j2)减少磁盘IO压力。
(3) 操作系统层面
- 排查工具:sysctl、dmesg、/proc文件系统
- 关键配置:
- 文件句柄数:
ulimit -n
(建议大于65535),限制文件句柄数可能导致系统无法打开足够的连接。 - TIME_WAIT连接数:可以通过
net.ipv4.tcp_max_tw_buckets
调优。 - 内存分配策略:检查
vm.overcommit_memory
,在内存不足时采取合理的回收策略。
- 文件句柄数:
2. 应用层排查
(1) 线程模型
- 排查工具:jstack、Arthas、SkyWalking、VisualVM
- 关键检查点:
- 线程池队列堆积:监控线程池队列长度,若发现增长异常,需考虑调整线程池配置。
- 锁竞争:分析热点代码是否存在大量
synchronized
或ReentrantLock
竞争,检查等待链是否正常。 - 阻塞IO:检查数据库连接池是否被正确释放,避免因为未释放连接导致线程阻塞。
- 优化措施:
- 设置合理的线程池参数(例如核心线程数、最大线程数)。
- 优化锁粒度,避免长时间持有锁;使用
ReentrantLock
的tryLock
来避免死锁。 - 确保数据库连接池的连接被及时归还,并且使用合适的连接池管理工具。
(2) JVM性能
- 排查工具:JDK Mission Control、GC日志、Heap Dump分析
- 关键指标:
- Full GC频率:如果频繁触发Full GC (>1次/小时),会影响系统响应时间,需调整JVM参数。
- Young GC耗时:超过100ms,可能是因为Eden区的设置不合理或内存压力过大。
- 元空间溢出:监控Metaspace的增长情况,防止元空间溢出。
- 调优建议:
- 使用G1回收器来优化GC行为:
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
- 通过设置
NativeMemoryTracking
来检测堆外内存泄漏。 - 对于频繁的Full GC,调整JVM堆内存大小或使用分代GC策略优化。
- 使用G1回收器来优化GC行为:
(3) 代码逻辑
-
排查工具:Arthas热诊断、Async Profiler、火焰图(Flame Graph)
-
常见问题:
- 正则表达式性能问题:正则表达式中使用
.*
会导致回溯爆炸,导致性能严重下降。 - 频繁序列化大对象:频繁的对象序列化会占用大量内存,特别是JSON和Protobuf格式的序列化。
- 递归调用:递归调用未收敛,导致
StackOverflowError
。
- 正则表达式性能问题:正则表达式中使用
-
优化措施:
- 使用高效的正则表达式,避免过多的回溯。
- 对大对象的序列化进行优化,避免频繁操作,考虑使用压缩或缓存。
- 限制递归深度,或将递归改为循环实现。
3. 中间件层排查
(1) 数据库
- 排查工具:慢查询日志、EXPLAIN、SHOW PROCESSLIST
- 优化方向:
- 索引缺失:确保数据库查询条件字段上有合理的索引,避免全表扫描。
- 事务隔离级别:避免在
RR
隔离级别下发生死锁,考虑使用RC
或READ COMMITTED
。 - 连接池配置:合理设置
maxWait
,避免因为连接池耗尽导致线程阻塞。
(2) 缓存
- 排查工具:Redis慢查询、MEMORY STATS
- 典型问题:
- 大Key引发延迟:当Key大于10KB时,Redis可能导致网络延迟,需要避免大对象作为缓存。
- 热Key未拆分:单一热Key可能导致单节点压力过大,分布式缓存应该拆分热点数据。
- 缓存击穿:缓存过期时直接请求数据库,导致数据库压力增大。
(3) 消息队列
- 排查工具:Kafka控制台、RocketMQ监控
- 关键指标:
- 消息堆积量:Consumer Lag(消费者滞后)过大时,需要扩容消费者实例。
- 端到端延迟:P99延迟超过1s时,需要调整队列配置,或扩容。
4. 依赖服务排查
(1) 下游服务SLA
- 排查工具:分布式链路追踪工具(Jaeger、Zipkin)
- 关键检查:
- 第三方接口响应慢:通过链路追踪定位具体接口,查看响应时间的P99,确认是第三方问题还是网络问题。
- 服务熔断器异常率阈值不合理:设置熔断器时,确保阈值合理,避免误判。
(2) 配置中心
- 排查工具:Nacos、Apollo
- 典型问题:
- 动态线程池配置错误:参数调整不当,可能导致线程池过小或过大,影响性能。
- 缓存过期时间配置错误:缓存的过期时间设置不合理,导致频繁从数据库读取。
三、根治性优化方案
-
容量规划:
根据历史流量数据及QPS(每秒查询数)增长趋势,预留30%额外资源缓冲。定期进行全链路压测,类似阿里双11的负载测试方式,确保系统高并发下仍能稳定运行。 -
可观测体系:
引入黄金指标(RED):- Rate:请求的数量
- Errors:错误率
- Duration:响应时间
定期检查这些关键指标,使用APM
工具实时监控各个环节的性能瓶颈。
- 异步化和解耦:
尽可能将高延迟的操作(如发送邮件、调用外部API)异步化,减少对主流程的影响。