前几篇文章中,我列出了软件监控中的一些常见问题,大部分问题都是来自于它们对自身的信息暴露不足。还有一类问题来自于监控软件本身。
警报严重程度分级
与日志级别类似,很多警报信息也很难在Nagios的严重等级中对号入座(OK/WARN/CRIT/UNKNOWN)。不过,少就是多,而且这种分级法应用广泛,所以最好还是按照它的规则来比较好。
抽风的系统
抽风(flapping)的系统处于一种好与坏之间摇摆不定的状态。有些情况下,此类症状是因为系统的某方面负载正好在一个阈值处上下摇摆;另一些情况下,则是因为软件本身运行的某些条件不稳定。对于此类问题,Nagios用一种粗暴的方式进行应对,即直接忽略掉重复的报警。一种改进的方案是重置阈值,即在指标超过某X值时触发一次报警,然后忽略之后重复的报警,直到指标降低到某Y值(Y远小于X)后再恢复原报警条件。不过不论何种方案,其思路都是将抽风阶段的重复报警隐蔽起来。
警报信息浓缩
数量众多的重复警报往往只贡献很少的价值,却加重了解读者的负担。现在市面上已经有一些公司专门聚焦于报警信息的浓缩工作(比如将重复报警进行聚合分组等),不过你自己也可以通过一些简单的机制实现重复信息的隐蔽,比如设置一个隐蔽周期,一次警报触发之后的隐蔽周期内,不再播报这一条警报。
警报的取消
如果一个警报触发了某个条件变更,但却没有后续自动取消变更的设定,那么你的系统会积累越来越多的变更后的条件。久而久之,监控系统的噪音会越来越大,价值降低。
反常状态的检测
我在很多文章中都描述过在动态系统中使用静态阈值所造成的问题。真实的系统无时无刻不在变化,我的观点是,阈值的设定“必须”是带有适应性的。如果你的系统在使用静态阈值,我建议将它们删掉,或者替换成更复杂的反常检测系统。
另一方面,很多阈值可以用时间函数的方式表达,这比一个单纯的数字要更有用。比如,磁盘利用率的阈值,可以简单的设置一个“到了90%满时报警”,但也可以根据数据增加的速度设置为“预计还有多长时间会填满磁盘”。
有计划的维护工作
维护中的系统,其报警也应当可以关闭(或暂时隐蔽)。这对于大规
模系统而言是很重要的功能。
上面所列出的内容是相当有挑战性的,每一条都符合的监控系统(或应用)恐怕不多。不能全部满足也没关系,我们的目标是越多越好。
检测运行时应用
在设计应用架构的时候置入常开的监控接口,就可以实时检测各个组件在运行时的状态,这会带来很多方便。
大部分应用都在某种程度上实现了这一点,然而很多实现都是建立在牺牲应用本身的运行之上的。比如你想要监控运行时进程,当然可以用gdb,但gdb会在检测的时候冻结该进程。这里的一个正面教材是Erlang,它可以对运行中的进程进行检测和修改却完全不会打扰到它的运行,然而这样的正面教材实在太少了。
我们在VividCortex使用Go语言编写内部服务和外部服务,它提供的一些工具、框架和库让我们欲罢不能。无论你使用的是何种编程语言和框架,都最好能够实现运行时的检测,未来的你会因此感谢自己的。
以下是我们使用的一些关键技术:
开启profiling
Go的核心软件包就包含了一组profiling库,这组库可用于检测一个运行时库并完全不会干扰其运行。我们在程序里可以很简单的将其include进来(默认是不内置的),并通过HTTP端点将profiling的结果暴露。CPU和内存的profile也可以通过这个途径获取。
创建进程列表
我们开发了一组库,用于维持每个服务的状态、显示其正在处理的请求、显示其所处的状态、以及对其执行一些操作(比如取消服务)。这组库也通过HTTP接口对外暴露,这样我们就可以在Web应用或其他API客户端调用。这组库被命名为pm,现在已经开源。
至此,我们就能够确切的知道“哪些请求正在穿梭于我们的服务之间”,从而精准的干掉那些造成问题的请求,或者实现更多类似的功能。