大家是否遇到过这样的场景,老板在群里 @ 你,向你反馈线上有 BUG。一般老板反馈的问题,都属于重要且紧急的需求,需要快速解决。这样的高优需求,即让你神经紧绷,又打破了你原有的计划,常常弄的人很累。靠充分的测试能够解决一部分问题,但是线上的场景永远比测试的场景更加丰富,难免会有遗漏 BUG 被带上线,造成业务损失。
可靠地、实时地、准确地提前发现问题
一个好的告警系统会提前发现问题,发出警告。你就有可能在老板 @ 你之前,就把问题给解决。
告警系统要提前发现问题的三个关键是:
- 可靠性。告警系统本身要可靠,不能时灵时不灵。
- 实时性。要快,慢了就没有意义了。
- 准确性。狼没来,喊狼来了,喊了三次后就没人信了。
接下来,我会先带大家看下我们的告警系统设计的全貌,再从可靠性、实时性、准确性三方面来详细介绍。
实时告警:整体实现
实时告警功能主要的工作量在 node.js 层,其整体实现如下:
- 每分钟批量执行一次定时任务
- 向Druid发出请求,获取线上实时的聚合数据
- 判断聚合数据是否超出阈值,如果超出则执行下一步
- 发送短信、微信、邮件通知开发者
可靠性:每台机器启动一个定时任务,会执行多次
一台机器运行定时任务,只有一个定时任务,指标超出阈值也只会发出一次告警。
但是,为了保障可靠性,我们就要避免单点风险,也就是至少要启动两台机器来运行定时任务,即使其中一台机器挂了,告警功能也能正常运行。但是,引入多台机器问题就来了。
二台机器运行定时任务,有两个定时任务,会发出两次告警。分布式 node.js 集群,会有多台机器运行定时任务,超出阈值就会发出多次告警,引入了重复告警的新问题。
定时任务:Redis锁保障只执行一次
我们需要的是多台机器,只执行一次定时任务,有啥办法来保障呢?我们想了两个方案。
- 共识方案:一个集群中的多台机器之间,选出一台机器来执行定时任务。
- 抢锁方案:一个集群中的多台机器同时向 redis 发出请求,谁抢到 redis 锁谁执行定时任务。
共识方案,在 Java 中有 zookeeper 之类的分布式调度工具可以使用,底层共识算法会选举出一台机器作为主(leader),其他机器作为从(follower)。可以只让主机器执行定时任务。但是在 node.js 中,我们并未找到类似于 zookeeper 的框架,所以就放弃了。
抢锁方案,是我们采用的方案。其原理是通过共享缓存的唯一性,来保障定时任务执行的唯一性,依赖的是 redis 的可靠性。在实际的业务中,我们认为 redis 比较稳定,单台就够了。如果以后发现问题,再改用多台 redis 也不迟。node.js 中有 bull、redlock 的分布式锁工具可以用。
- bull 的功能主要是分布式队列,用来实现分布式锁有些大材小用。
- redlock 是 redis 官方提出的分布式锁算法,也有 node.js 的实现,正好符合我们的需求。
因此,在告警功能的可靠性上,我们使用了 node.js 集群,避免了单点故障。同时,使用 redis 锁,保障一个告警定时任务,只会执行一次。
实时性:关键是“快”
实时性的关键词是“快”,从用户异常发生到开发者收到异常告警的时间越快越好。
其中关键点是:
- Web 发生异常后,马上上报,SDK 层不缓存。
- 使用时间序列数据库 Druid,减少海量数据聚合耗时。
- 每分钟 node.js 执行一次告警定时任务。
大家可以看到,从发生时间到告警时间,中间有 8 个时间点,用哪个时间点好呢?
在 8 个时间点中,最为关键时间点有 2 个:
- 发生时间(橙色):用户行为轨迹需要对用户异常日志、正常日志按时间进行排序。异常日志是立刻上报的,正常日志是用户主动上报的,这就只能用发生时间进行排序,其他时间肯定都不对。
- 接收时间(蓝色):开发者搜索某天某个用户发生的异常,如果用户本地时间是错的,可能就会搜不到。但我们可以相信,服务端的接收时间是准确的,按照接收时间搜索,肯定能搜到。
那么告警指标的统计以那个时间点为准呢?具体的统计方式应该怎么设计呢?
实时性:统计方式
从两方面考虑,我们的统计时间点用的是接收时间。一方面,服务端时间的准确性是我们自己控制的,是可信的。另一方面,考虑有海外用户会跨时区,时区问题处理起来会比较麻烦,统一用服务端时间更好。
但是,这里还是有一些细节需要大家注意,从接收到可被读取之间,还有经过 kafka 消息队列和 druid 聚合计算的时间。理论上 kafka 只要不发生消息堆积,是能马上被 druid 进行消费的,druid 本身又有实时计算模块,聚合计算也是非常快的。但是,我们考虑到可能会有偶发的一些超时情况,可能会导致统计数据偏少,从而导致误报。因此,拍脑袋给 kafka 和 druid 预留了 1 分钟的缓冲时间,算作对实时性的一种妥协吧。
准确性:线上异常的总量监控指标不可靠?
现在,我们来聊聊最后一个特性,准确性,也就是告警指标是否可不可靠。
我们假设一个场景,有位开发者看到异常总数这个指标快速上升,他心中一紧,这线上是啥情况啊?
如果恰巧,前端页面刚刚有上线,大概率是前端问题。
如果恰巧,后端同时发出宕机告警,大概率是后端问题。
如果恰巧,业务刚刚在冲量,那么引起页面异常总数指标快速上升的原因,大概率只是因为 PV 涨了而已。
同理,在0~6点是业务范围量少,到了 8 点~10点,流量会有很大的上涨,同时也会影响异常总量上涨。
准确性:异常PV比代表平均每个PV发生异常的数量
在异常总数和PV同步增长的情况下,异常PV的比值其实会保持不变。其原因是平均用户每次访问,页面发生异常数量是一样的。因此,在我们的业务中,相对于异常总数,我们认为异常PV比的变化更重要。
当业务异常PV比大于预设的阈值,或者环比上升较快,那么就可以判断线上出现新的异常了。并向业务发出告警。
准确性:全面的监控指标
为了更全面的监控线上应用,我们设定了一系类的监控指标,其中深蓝色的是核心指标,它的准确性会更高一些。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。