随着目前互联网市场的不断发展,已经抵达了一个比较成熟的阶段。在这个阶段中,各个互联网公司的技术发展方向,已经逐渐开始关注到服务稳定性治理这块了。
因此,服务治理这类的话题,我预估会是接下来几年中比较多人讨论的一个技术点。各个互联网公司为了提升自己系统的稳定性,都会考虑到引入一些监控框架类型的产品。但是随着越来越多的监控类型产品引入,一个新的问题就诞生了,那就是告警治理。
其实如果你的系统比较简单,只有几个微服务,几台机器,那么可能不会感觉到告警治理的重要性。
但假若你的服务有成千上万个节点,它们的告警指标应该如何制定和管理呢? 一旦某一环出现了故障,故障应该如何发配给到下有的负责人呢?
如何制定告警指标
首先我将告警策略做了一些简单的分类,当然其内容可能并不是很完善,大家也可以基于这份列表去进行一些完善。
首先是接口层面的监控,这块我们重点关注RT,异常率,耗时
-
RPC的提供端响应超时大于阈值
-
RPC的调用方等待超时大于阈值
-
接口的异常率大于阈值
-
接口的请求参数体积大于阈值
-
接口的QPS/TPS大于阈值
-
接口的调用次数大于阈值
然后是JVM层面的监控,可以参考如下思路去设置告警指标
- JVM的堆内存使用比例大于阈值
- JVM的YGC频率大于阈值
- JVM的 FULL GC 频率大于阈值
- JVM的STW时间大于阈值
- JVM的非堆内存占用情况
- JVM的线程总数
好了,基本上90%的Java进程异常,我们都可以通过上边的这些指标去监控起来。但是还有一些情况我们可能没有考虑到,例如一些离线任务,或者异步任务。
通常这类任务没有对外提供直接的接口,所以大家就很容易把一些耗时的东西,往这里面去堆,但是这样做会有风险。万一在一些异步任务里面对某张高读写频率,且大数据量的表做了一次全表扫描,那么就会导致影响到其他请求的执行。
因此我们还可以加入一些指标,如下:
- Java线程池内部的耗时情况:
- Java线程池的堆积指标
- Java线程池的活跃线程数,任务队列长度,任务执行耗时等信息的采集
数据层面的指标:
-
SQL执行时间的监控
-
SQL异常次数的监控
-
SQL调用次数的监控
上边我们提及的监控指标更多是应用层面,那么对于底层也需要监控起来:
-
机器CPU使用率
-
机器内存使用率
-
网卡每分钟出口数据包体积大小
-
网卡每分钟入口数据包体积大小
好了,关于告警指标我们通过一番简单的罗列,你会发现居然有这么多方面需要配置告警规则。那么针对如此之多的告警规则,我们应该如何去制定这里面的告警流程和告警策略呢?
告警流程
其实从告警的流程来分析,本质就是:发生问题的机器将故障信息传达给到具体的负责人。
这个流程看似简单,但是会存在以下几个问题:
告警降噪
业务异常通常一旦发生,都会有连续性,很容易就会造成“异常风暴”,对于这种情况,我们不应该做成每个异常都通知一次给到业务方,这样对业务的干扰非常严重。
所以这里应该要有一种抑制机制,例如一分钟内报错100次,只需要抽样其中的1-2条信息发送给业务方即可。
告警负责人
为了能够实现告警的及时性,一般我们会对业务服务配置具体的负责人,这里的配置规则可以是如下设定:
应用服务负责人:例如springboot服务中的spring.application.name作为划分标准,不通的业务服务都需要配置具体的负责人。
机器负责人:部署服务的机器需要有配置具体的负责人。
告警升级
假设A机器上的user-provider服务出现了故障,那么第一时间应该是通知给到user-provider服务的负责人。如果超过一定次数通知后,没有收到user-provider负责人的确认处理响应(有可能是业务负责人没有看到消息通知),那么该故障就应该升级告警给机器负责人。
告警抑制
有些特殊场景中,告警未必需要特殊处理,所以还需要支持一套告警抑制的功能。大致可以理解为,对某类异常发生的默许。
如果将上述的几个问题给解决好的话,那么我们整体的告警流程图就大概如下所示:
本文只是简单介绍了一些告警治理的思路,但是真正要落地下来,这里还会牵扯到很多跨部门沟通以及和技术层面的东西。例如:需要实现对服务的多方面指标结果的采集和存储。(常见方案是promethus存储指标,然后写ptsql去监控指标变化)
需要有一个统一的负责人将各个部门的leader都汇聚在一起,然后让多方配合接入使用。总而言之,这东西绝不单单是一项简单的工程。