
问题现象在容灾演练的时候为了验证当前单元能够承载所有的线上流量我们会将另一个互备单元的所有流量调拨过来过一个高峰期来验证。在收集验证数据的过程中我们的虾反馈: A应用一共20台机器有3台CPU明显偏高达到了50%而其余的只是在10-20%之间波动提示负载不均衡需要重点关注。笔者挑了两台监控对比如下图所示:3.问题分析既然虾都提示负载不均衡了那我们就直接按照虾的指示排查吧。3.1先看接口QPS于是笔者去监控平台上看了下这两台机器(机器1和机器2)这两台机器的QPS基本一样甚至机器1略小于机器2的QPS。3.2再看Mafka同样的Mafka的消费速率也是一样。3.3再看定时任务那么会不会是CPU高的机器上跑了定时任务其它机器没跑呢带着疑问笔者去翻了下进程的定时任务。确实有但每台机器都有的。那么会不会是不同机器在同样的定时任务下处理了不同数量的数据呢3.4数据不均于是笔者翻了下这个应用的源代码发现它需要从数据库里面获取订单数据来进行比对。自然的就去翻这个应用每台机器对于SQL的QPS。发现两台机器依旧没啥区别。不过SQL QPS没啥区别不代表SQL返回的Row行数没啥区别这点监控上没有精确的表达。于是笔者就想到去翻JVM younggc和fullgc的情况如果行数多gc肯定更加频繁一点没想到还是没啥区别。3.5 其它进程额那笔者不得不怀疑有其它进程了。要么直接看java应用占了多少CPU吧。看了一下发现这两台机器的CPU占用是一致的都是20%左右。就是其它进程的锅了于是笔者看了一圈监控上当台机器其它进程的监控并没有发现占用CPU高的。3.6 监控对不上如果我们假设有其它进程会耗大量的CPU当CPU.busy达到50%的时候应用的耗时以及cpu本身load的计算肯定要反应出来。但是奇怪的是高CPU机器的耗时非常正常load也和低CPU机器一模一样。3.7 CPU.busy计算是不是有问题?在上面的数据观察之后笔者就感觉这两台机器好像负载是一模一样的其它所有的指标都在证明着点而且机器上的应用没有任何耗时上的差异。是不是CPU.busy计算错了或者说我对于CPU.busy解读错了于是翻了一下计算这玩意的源代码:每分钟采样一次 CPU.busy (当前采样时刻容器累计 CPU 时间 - 1 秒前容器累计 CPU 时间) / 1s好了这个 CPU 指标是每分钟采样一次。。而且每分钟只采样那一秒的CPU。笔者看到的一瞬间就知道了这又是一个监控的采样问题。3.8 10秒级CPU.busy指标还好我们有10秒级的CPU.busy指标于是笔者翻了一下。发现一旦到了10秒级CPU.busy的表现是完全一致的。这两台机器都是在前一个10s内CPU到50%后一个10s内CPU到10%。那么监控的矛盾就很清楚了不同机器的采样时间是不一样的。采样点在50% CPU时间内采样监控就是50%在10% CPU时间内采样监控就是10%。两台负载一模一样的机器由于采样点的不同而在监控上反应出了完全不同的读数。如下图所示:4.数据解释4.1 两台机器为什么CPU消耗不一样刚才已经解释了。两台同样负载的机器采样的时间点不一样一个是每分钟内CPU 50%时候采样的一个是每分钟内CPU 10%采样的。在监控看来自然是不同的CPU.busy。4.2 为什么java进程CPU消耗一样监控中对于Java进程CPU的计算方式为:proc.cpu/java (进程当前运行总时间-进程上一秒运行总时间)/60s这个就和上面容器的cpu.busy不一样了。虽然都是每分钟取一个点但是一个取的是1s内的均值一个是1min内的均值。这就导致了容器的CPU.busy会随采样时间点而不一致而Java进程CPU消耗不会。也就是说:容器 CPU.busy分钟级但只看某1秒 Java proc.cpu分钟级但看过去60秒平均那为什么是20%左右呢那笔者详细的看了一下监控个数据。实际情况要更加复杂CPU监控的取点是950189如此循环计算下来平均确实是20%左右。这也解释了为啥20台有3台会有问题因为4个点只有一个点高25%的计算下来是5台但机器太少无法精确的平均分布3台属于可接受范围。4.3 为什么CPU高的机器一直高因为每台机器的采样间隔是一致的。区别只在于监控系统什么时候去采集不同机器采集的分钟内秒数不同但同一台机器基本都是按照一分钟的间隔去采集的。机器1一直采样到50%机器2一直采样到10%4.4 为什么load一样Linux的load计算是5s一次并且按照指数平滑的在这个case下也没有采样点的问题。当然了笔者遇到过一个更诡异的load采样的问题以后有机会可以写下。