架构师必备:CPU使用率不均匀排查
本次分享一下CPU使用率不均匀的排查过程先看问题现象再找问题根因、解决办法最后扩展到通用的排查思路、典型原因。先说结论根因是服务实例数大于kafka分片数。快速的解决办法是扩大kafka分片数彻底方案是拆成2个服务消费任务服务、业务API服务。除了这个原因其它典型的原因比如入口负载不均匀、存在热点、线程阻塞等待、线程池大小不够、GC耗时变长等日常积累加入到经验池。下面详细展开介绍。1. 现象线上服务有多个实例从监控看CPU使用率不均匀部分实例稳定偏高而不是个别实例有CPU尖刺重启服务实例后仍然无法消除但是过一段时间后又恢复均匀了2. 根因定位既然是部分实例有问题那关键就要找出异常实例与正常实例的差异首先确认负载是否均衡。先看接口qps没有明显差异再看kafka消费qps果然有差异CPU使用率高的实例有消费消息消费qps较高而其它正常实例无消费那么问题就清楚了一个kafka topic由多个分片组成每个分片只能被一个服务实例消费当服务实例数大于kafka分片数时只有部分服务实例能分到partition消费消息并处理业务逻辑CPU使用率偏高其它未分配到的实例则相对空闲当kafka topic不再产生新消息并且消息都消费完毕后各服务实例的CPU使用率就恢复均匀了回顾一下历史上做的变更一开始接口qps不高部署的服务实例数不多比如10个后续又新增了消费逻辑每天离线导出数据、并消费处理相当于定时消费任务申请的kafka topic分片数等于服务实例数也是10个此时还察觉不出来CPU使用率的差异随着业务流量持续增加服务实例扩容比如100个此时问题就凸显了3. 解决方案快速方案扩大kafka分片数优点快速解决问题缺点只对增量消息起作用已发到topic里的消息是改不了partition编号的长期看kafka分片数无法与服务实例数联动增长彻底方案拆分消费任务服务、业务API服务优点彻底解决问题消费任务服务实例数相对固定比如n个可以按倍数申请kafka分片数比如2n个使得每个消费服务实例分到均匀的kafka分片。业务API服务可以随着流量变化灵活调整动态扩容、缩容。4. kafka核心概念回顾下面再回顾一下kafka核心概念。topic消息队列与partition分片topic是消息的逻辑队列每个topic被划分为多个partition它是物理存储与并行消费的最小单位。一个topic的消费处理上限取决于partition个数partition越多并发度就越大。一个partition内的消息严格有序不同partition之间无序。生产者可通过消息key一般是业务id将消息发送至指定的partition来实现同一业务id的消息有序性。consumer group消费组与rebalance再平衡consumer group是一组协同消费的消费者实例。核心规则同一个partition在同一时刻只能被group内的一个消费者实例消费。rebalance当消费者增减或partition数量变化时partition会在消费者间重新分配。offset消费位点与超时风险每个partition的offset由consumer group独立管理。如果单条消息处理时间超过max.poll.interval.ms默认5分钟消费者会被踢出消费组触发rebalance进一步恶化性能。5. CPU使用率不均匀的排查思路、典型原因面对CPU使用率不均匀的问题最高效的排查思路是固定时间窗口如最近5分钟拉取所有问题实例的监控指标进行横向对比。差异点就是线索。第一步对比请求量首先确认负载是否均衡、请求是否真的打进来了。确认接口qps、消息消费qps、是否有热点类似于本文提到的排查步骤。除了上面的kafka分片数问题以下原因都可能导致负载不均匀生产者消息key严重倾斜热点key导致全部落入同一partition上游负载均衡策略失效或RPC一致性哈希倾斜第二步对比线程状态在流量一致的前提下如果CPU不同则继续重点关注线程状态以下原因可能导致CPU使用率飙升RPC线程池/业务自定义线程池/数据库连接池因大小不够而耗尽调存储、调下游超时时间设置不合理导致阻塞线程数变多CAS乐观锁并发较高导致不停自旋、无法更新死锁第三步对比GC状态如果线程状态无异常则继续排查GC状态。对比GC是否变慢、GC频率是否变多是否有大对象堆内存大小是否足够确认JVM参数是否设置合理第四步重启服务如果实在没有思路又想快速恢复可以尝试重启服务说不定是底层k8s容器、或宿主机的问题可以说是终极大法了。6. 总结架构设计要合理消费任务、在线业务逻辑要拆分到不同的服务监控要完善在遇到CPU使用率不均匀问题时的排查思路是找差异按照几步来定位根因对比请求量、对比线程状态、对比GC状态、重启服务