"监控不仅是一种技术,更是一种文化。" - 艾德·高斯林
1. 背景与挑战
1.1 背景
“唯一确定的就是不确定。” - 杰克·韦尔奇(Jack Welch)
我们生活在一个不确定的世界里。在软件系统领域,这种不确定性尤为突出。我们无法完全预知软件系统在运行时会发生什么,所以监控就会变得尤为重要。一个好的监控可以帮助我们实时观测软件运行情况,及时帮助我们发现问题和协助定位问题。
但我们不得不面临另一个问题就是软件系统本身其实是极其复杂的,所以如何把监控做好做全变得异常困难。相信大家在日常开发过程中都会遇到类似的场景,我自己觉得我做好了监控,但线上还是偶尔有一些“惊喜”发生,由于没有特定地布防监控,导致线上问题一直没有被发现,影响面越来越大。
我们在实际的业务场景中也遇到了同样的问题,曾经我们也布防了很多监控,但历史上仍然出现了多次由于线上监控不及时产生的线上故障。
接下来就分享一下我们是如何解决这个问题的。
1.2 冲突
上面提到历史上我们系统出现过多次的线上问题,其中包括代码bug引起,也包括运营修改配置出错引起。通过对于问题的复盘总结发现,其实我们有足够多的监控,但究竟是为什么仍然不能及时地帮助我们发现问题呢?
通过分析发现,过往的监控主要聚焦于系统层面和接口层面。这些监控本身是非常有必要的,但随着业务复杂度的增加,只有这些监控是往往不够的。我们真正缺失的是完善的业务监控。
抓住主要矛盾:缺失完善的业务监控
e.g. 我们线上有一处代码bug导致价格计算错误,应该是100元被算成120元。这时系统层面和接口层面的监控全部是正常的,所以几乎无法通过现有监控暴露出这个bug。这个时候就必须通过业务监控来发现。
就像这个天枰一样,我们过于注重系统和接口层面的监控,对于业务监控的关注度太小。导致天枰发生倾斜,无法及时帮助我们发现线上可能出现的问题。
在进行业务监控体系搭建的时候也遇到了很多的挑战。
1.3 挑战
业务监控可借鉴的经验较少
行业内针对系统维度、接口维度的解决方案数不胜数,但对于业务监控的方法论其实是严重不足的。导致我们几乎没有太多可借鉴的经验。需要我们自己摸索出一条道路来。
计价业务对于监控的要求非常高
计价业务系统对于监控的准确率是非常高的。
2. 解决思路
2.1 整体思路
监控的核心要义在于发现异常情况。所以我们要分析出当出现异常情况时,可能在哪些东西上有所体现。这里以计价业务为例,下图是一次简化的计价过程。
在一次算价过程中,首先要进行路径规划得到起点和终点的距离。然后进行各个费用项的计算,比如起步价、超里程价等等。接着进行营销部分的计算,比如平台减免和优惠券等等。最后将这些结果聚合起来形成一个最终的总价。
首先,我们知道肯定要对结果数据进行监控。即把整个计价过程看成一个黑盒,观察总价的变化曲线、趋势、最值等等是否出现异常。
其次,我们假设计价过程中任何环节都可能出现异常,而有时过程中的出错可能并不能直接体现到总价上,但往往又是用户和司机特别关注的。
e.g. 某个城市的总价的平均值是100元,如果优惠券部分出现问题导致由5元错算为2元。这个时候总价上的曲线是完全体现不出来的。但是对于用户和司机感知还是非常强烈的,这就要求对于优惠券必须单独监控起来。
所以仅仅监控总价是不够的。我们还要监控过程数据,类似于白盒。即观察计算过程是否异常,比如费用项A、路径规划、优惠券等等是否正确。
因此总结一下,我们可以将业务监控整体分为:结果监控和过程监控。即任何的异常无非就是体现在这两类数据上。
2.2 结果监控
结果数据监控类似于黑盒测试,将我们的系统看成一个黑盒,并不知道里面是具体如何运行的。这时我们所知道的只有请求和对应的结果,我们就针对结果进行监控。
而关注的方向大致分为以下两种:
结果数据是否正常
判断结果是否正常的方法可以有两种:是否缺失和是否正确。而每种方法都有各自的评判标准,决定了各自的监控方式。
业务关键性数据是否缺失
- 核心数据必须存在,以里程计费为例,起步价和距离是所有价格计算的基础,如果不存在,则可以认为关键性数据缺失。
系统对外暴露的数据(接口、mq消息等)是否正确
⭐️ 评判标准:
- 核心数据必须在预设的范围之内;以里程计费为例,起步价是不可能低于0,如果出现此类情况,则可认为暴露的数据不正确。
- 业务结果单个字段指标趋势(枚举、数值大小区间、数值变化)。以里程计费为例,起步价、超里程的趋势可以从侧面验证此类计价的正确性。
- 关联性比较大的业务指标组合,趋势是否正常。以里程计费为例,由于客单价与距离会有某些关联,如果各自使用单指标趋势,可能无法体现两者互相影响的程度,这时就需要指标组合,将两者的关联性清晰的展现出来
结果数据是否符合业务预期
有些场景下,我们仅通过结果是否正常并不能真正的发现问题。比如业务A和业务B是有关联的,单看某个业务曲线都是正常的,但放在一起比较就会发现是有问题的。
e.g. 车型A的平均价格是100元,车型B的平均价格是200元。如果单看车型A和车型B的价格曲线,各自都是正常的。但业务上规定:车型B的价格一定小于车型A的价格。所以我们只能通过两个曲线结合才能发现问题。
总结一下:就是从结果里找到关键的业务字段来组建业务大图,判定返回结果的是否符合业务预期。
2.3 过程监控
有些场景下,仅仅通过结果监控并不能发现线上问题,必须通过过程数据才能发现。
e.g. 城市A的平均价格是100元,价格是由多个费用项组成。这时某个费用项由于代码bug引起,由1元算错成了5元。如果仅仅通过最终的结果总价来看,是无法感知波动的(因为4元的波动对于总价100来说几乎看不出来)。必须针对过程数据(此费用项)进行监控,才可以发现问题。
与侧重于黑盒的业务结果指标不同,过程指标更像是白盒测试,是对业务执行的内部逻辑和数据结构进行分析。
大概可以分为以下几个部分:
过程执行中产生的核心中间数据是否被监控到
核心中间数据是程序执行过程产生的数据和依赖服务数据,当它出现问题时会阻断主流程或者带来一些严重的业务故障;所以它需要更加精细和敏感的监控力度,不仅仅是异常情况需要感知,某些必须的数据返回也需要监控,出现问题时可能需要相关方立即修复。
如果我们把系统代码中的分支都抽象成一张图的话,可以发现每个业务都会有自己的执行路径。所以我们可以针对性地监控业务的执行路径是否正确,从而来发现线上问题。
关于代码分支理论上分为两类:业务分支、开关分支。由此可以画出自己系统的分支路径图。
3. 具体方案
下面我们结合了具体实际的计价业务场景,进行了业务监控体系的搭建。
3.1 计价结果监控
通过分析我们找到了结果数据中一定不能缺失的数据字段,如下。
- 零容忍
对象 | 指标 | 备注 |
---|---|---|
费用项 | 起步价不存在 | 起步价如果不存在,代表本次请求必定出现问题 |
通过分析我们找到了结果数据中字段异常情况和趋势异常情况,如下。
- 零容忍
对象 | 指标 | 备注 |
---|---|---|
费用项 | 起步价为负 | 起步价计算为负,计算必定错误 |
费用项 | 超里程为负 | 超里程可能没有,但是不会为负 |
- 趋势:
对象 | 指标 | 备注 |
---|---|---|
费用项 | 客单价请求量命中率 | 总费用的组成部分,例:起步价、超里程等 |
计价场景 | 估价:首页选定城市车型地址时间后计算得出的价格核价:支付前再次确认价格,是否与先前估价价格一致 | |
大区/城市 | 影响计价结果的因素之一,不同大区/城市会有不同配置 | |
同城/跨城 | 影响计价结果的因素之一,不同区域会影响部分费用项计算 | |
大车/小车 | 影响计价结果的因素之一,不同车型会影响部分费用项计算 |
我们通过分析得到,价格的费用项中起步价、超里程和路径的长短有着非常密切的关系,所以针对性的进行布防业务大盘。下面只是给了部分的截图示例。
3.2 计价过程监控
我们通过分析,得到了关于计价业务场景的核心中间数据和执行过程。下面给出部分的监控示例。
对象 | 指标 | 备注 |
---|---|---|
费用项 | 车型价格不存在 | 基础里程价格计算强依赖数据,如果没有,计价失败(第三方获取数据) |
对象 | 指标 | 备注 |
---|---|---|
费用项 | 业务开城 | 通过此类指标,可观察新增功能的开城进度,也可辅助查询某个城市可能产生的费用项种类(开关) |
4. 结果
结果:
我们已经搭建完成计价业务监控大盘,包括计价结果数据大盘和计价过程数据大盘。
结果数据包括不同模式、不同大区、不同业务线等的客单价曲线。总计20+个
过程数据包括费用项、距离、营销等价格曲线。总价100+(其中关键过程监控30+)。
收益:
e.g. 线上xx业务调整,我们通过监控的曲线波动预警,及时发现问题并与相关研发业务确认,防止一些误操作。
5. 建议
在这里我们也给大家在做业务监控时一些建议:
"你无法预防你无法监控的。" - 埃里克·托马斯(Eric Thomas)