美文网首页
自愈:问题自动发现与修复

自愈:问题自动发现与修复

作者: tiankongus | 来源:发表于2020-03-17 23:24 被阅读0次

    分享一个颇为曲折的故事。

    一、背景

    早在2016年的时候,我实现了一个监控系统,自动检查数据平台各节点的基础数据是否一致。

    可是,这个仅仅是监控系统,用于检验缓存实时更新功能的正确性。

    2019年春节前夕,部门提出要做一个万能的通用的自愈系统。

    当时各种脑暴讨论,讨论到最后,发现要做到万能与通用,这个自愈系统就需要与业务无关,也就变成了一个状态机模式的调度系统。

    而当时周围还没有任何一个自愈相关的实践,大家不仅希望万能通用,还希望与业务有关系,后来大部分人都有新的项目了,这件事便不了了之了。

    年前的时候,我们团队的服务遇到一个问题,然后做了一个实实在在的自动发现与自动修复系统,为自动修复积攒了不少经验,下面分享给大家。

    二、几年后出问题了

    image

    还是上面的数据平台,基础数据通过内部设计的一套通知机制,几乎做到数据完全一致。

    而对于非基础数据,比如第三方储存或服务提供的数据,无法走内部这一套通知机制。
    这部分数据修改后,生效时间会比较久。

    为了加速第三方服务的生效时间,第三方服务也复用了内部的通知机制。

    但是这样有一个问题。
    缓存服务收到更新通知后,会去第三方服务拉最新数据,此时第三方服务有很小的概率返回旧数据。

    这导致第三方服务数据不一致问题小概率性出现。

    ……

    巧妙的是,以前底层cms的很多计算逻辑都是通过各种脚本定时完成的。
    这使得每计算一个数据,都会触发一次写操作。

    这种多次写恰好修复了这个不一致问题。

    因为第一次写的时候,第三方服务会有小概率计算出旧数据。
    几秒后第二次写的时候,第三方服务依赖的下游是旧数据的概率就非常小了。
    实际情况时,会写很多很多次,所以概率被无限缩小。

    PS:对于后面的重复写,大家可以理解为第三方服务计算的新数据没变化,但是缓存认为有变化,再次去拉取第三方服务。

    就这样第三方服务运行了好几年,几乎没出现什么问题。

    ……

    不幸的是,春节的前几周,底层cms升级改造正式上线,所有计算逻辑只会写一次。

    这使得第三方服务问题暴露出来,被无数运营投诉。

    让底层cms暂时回滚是行不通的。
    对数据系统的架构进行重构,使这个第三方服务支持快速更新,短期内也没那个时间。
    所以做一个自愈系统就显得非常有必要了。

    三、自愈系统架构

    简单思考下,自愈系统大概分为三大模块:数据输入模块、数据拉取模块、数据对比修复模块。

    如下图

    image

    数据输入模块一般是从消息队列接收消息。
    这里可能还需要对输入的数据进行过滤标准化等预处理逻辑。
    最终将需要监控的数据放入任务队列。

    由于不同任务需要等待不同的时间才能启动检查。
    任务队列可以是一个按处理时间排序的列表。

    数据拉取模块每次从任务队列顶部检查是否有到达时间的任务。
    有了取出,先拉取基准数据(认为是正确的),再拉待校验的数据(可能需要拉很多接口的数据)。
    当然,这里与数据输入一样,需要对拉取的结果进行过滤与标准化。

    之后就是对比数据是否一致,不一致了调用修复接口进行修复。

    上面就是一个自愈系统简化后的模型。

    四、加强版自愈

    年前的时候,让一个同事做了这样一个系统。

    那个版本为了快速测试流程,很多参数是 hardcode 的。
    我简单的 codeview 了架构流程,看着没啥问题。

    后面我提出一个要求:这些参数需要配置化。
    于是相关参数被改成配置文件读取后,就直接发布上线了。

    上线后的一个月内,运营也都没有来反馈问题了。

    ……

    可是,半个月前,运营突然又大面积反馈这个问题了。

    我心中有一个很大的疑惑。
    如果自愈系统有问题,一个月前就应该不断的遇到问题。
    如果自愈系统没问题,这些问题就应该被自动发现自动修复。
    难道仅仅是概率问题?

    于是我同时要到 自愈系统和 第三方系统的代码,进行 codereview
    然后发现第三方系统存在两个问题,自愈系统存在一个过滤问题。

    将问题反馈给相关负责人后,第三方系统的问题被修复了一个,自愈系统的过滤问题也被修复了。

    但是运营依旧在投诉,这说明问题依旧存在。

    此时,我们正处于组织架构调整期。
    第三方系统 和 自愈系统的负责人都去做其他新项目去了。

    问题还是需要解决,于是我开始接手这两个服务了。

    ……

    接手后需要做两件事情。

    第一件事是修复第三方系统遗留的那个已知问题。
    第二件事是分析自愈系统为啥没有发现问题、修复问题。

    由于数据节点众多,目前自愈系统检查节点数据的逻辑是抽样拉取的。
    分析了之前有问题的数据,如果数据有问题,是必现的。

    难道刚开始那几秒,数据在反复变化?
    于是我猜想,一次抽样可能发现不了问题,全部计算量又太大。

    一种不错的方法是有策略的多次检查。

    最常见的策略有:等差策略、指数策略。

    等差策略就是每隔多少秒触发一次检查。
    比如第5、10、15、20、25、30秒检查。

    指数策略就是每次间隔时间翻倍。
    比如第5、10、20、40、80、160秒检查。

    我对这两个策略都不是很满意,因为时间间隔的太近了。

    于是我引入了阶乘策略,即相乘的因子每次加一。
    比如第5、10、30、120、600、3600秒检查。

    算法确定后,就是代码实现了。

    将算法封装在一个对象内后,实现还算简单,很快我就上线了。

    image

    当我分析策略的正确性时,我惊呆了。
    数据拉取模块竟然有一个隐藏很深的BUG,使得结果永远都被认为是一致的。

    自此,我前面提到的疑惑算是得到了解释,确实是概率问题。自愈系统从来没正常执行过。

    问题修复后,运营果然几乎不反馈问题了。
    后来他们又反馈了一个问题,分析之后,发现是新功能不在监控范围之内,我补充进去后,然后到现在为止再也没收到反馈了。

    五、回顾

    回顾一下这个自愈系统,整个流程大概确定了。

    大概如下:

    1、MQ 输入任务、过滤、标准化
    2、有策略的进入任务队列
    3、调度任务拉取基准数据与对比数据,结果标准化
    4、任务结果对比,不一致时进行自愈修复

    疑惑解开之前,我引入了有策略的多轮检查机制来确保问题被发现与修复。

    而最终的问题竟然是一个隐藏的BUG。

    这个问题属于逻辑BUG,只能引入单元测试来发现。

    由于涉及到各种接口网络调用,还需要使用 MOCK 钩子来解决依赖。

    单元测试和MOCK钩子我在个别项目中用到过,后面有时间了,也引入到这个项目来。

    到时候再给大家分享一下单元测试的实践与MOCK钩子的实践。

    《完》

    -EOF-

    相关文章

      网友评论

          本文标题:自愈:问题自动发现与修复

          本文链接:https://www.haomeiwen.com/subject/ovlfyhtx.html