智能上线阻断的算法和实践

news2024/11/26 10:35:01

一、背景

上线是引起系统故障的主要原因之一,在有些公司甚至能占到故障原因的一半,及时地发现并阻断、回滚存在故障隐患的上线,可以有效地减少系统故障。

事实上,现在很多平台已经提供了基于手工配置规则来进行变更阻断的能力。业务同学可以在平台上选取指标并设置相应的阈值,当上线中或上线后指标突破阈值范围时,则认为相关服务出现了异常,需要阻断。但是阈值需要人工确定,并且根据指标变化不断调整,所以往往难以覆盖大量的指标限制了这种做法的有效性。

因此,我们希望能够通过算法自动检测指标的异常,从而可以覆盖大量的指标,提高变更阻断的覆盖度、便捷性和有效性。本文将系统地介绍我们在智能上线阻断中应用的算法和工程上的实践。

二、方案概述

一般来说,我们检测的是服务的黄金指标。黄金指标包括平响、可用性、QPM这三大类。当一个服务对外提供多个API时,每个API都会有这三个黄金指标。因此,一个服务的黄金指标就是所有这些API黄金指标的集合。

上线行为导致的服务异常可能有两种。第一种是变更的服务自身出现了异常,第二种是变更的服务自身没有出现异常,但与它有直接关联的其他服务出现了异常。因此在上线时,我们可以排查变更服务和与它有直接关联的其他服务的黄金指标。

因此,我们的方案是,首先让用户为每一个服务配置一个指标列表,在上线时由算法检查列表中的所有指标。如果发现异常,则可以阻断。每个服务的指标列表包括该服务自身的黄金指标,以及与该服务有关联的服务的黄金指标。

本文中我们将主要聚焦可用性因为它是标识服务稳定性最核心的指标,往往能帮助我们快速、准确地发现故障。

三、算法原理

那么排查可用性指标的具体方法是什么?作为一个有常态化波动的指标,我们又怎样定义指标的“异常波动”呢?这些问题将在下文中详细解答。

一个API的可用性本质上是该API的成功率或者错误率,我们假设接口的总请求数为x, 错误数为y,传统的方法是为错误率(即y/x)设置一个经验的阈值,但当请求数较小的时候(例如夜间时刻),错误率的波动会很大,如下图所示:

 

 上面三幅图分别为一个API的请求数,错误数和错误率,左侧红框标注的是一个真实的故障,但如果我们基于这个故障来设定错误率的阈值,则会发现在请求总数较低时,错误率很容易突破这个阈值,这也是直接手工配置规则来进行变更阻断的另一个问题。而二项分布可以较好地解决这一问题。

3.1 错误率指标检测的一般方法

首先,我们来介绍二项分布的数学原理,二项分布是大家所熟知的离散型概率分布了。它的数学定义如下:

在n次独立重复的伯努利试验(在同样的条件下重复地、相互独立地进行的一种随机试验,其特点是该随机试验只有两种可能结果)中,设每次试验中事件A发生的概率为p。用X表示n次试验中事件A发生的次数,随机变量X的离散概率分布即为二项分布。

对于错误率指标的监控来说,二项分布天然地比较适合,因为一个请求也像投硬币一样只有两种可能的状态:成功/失败。使用二项分布可以有效的解决以上问题。我们假设错误数y服从参数为x (请求总数)和p0 (基准错误率)的二项分布,则根据二项分布的定义有:

P \left\{y; x, p_0 \right\}=\binom{x}{y} p_0^y(1-p_0)^{x-y}P{y;x,p0​}=(yx​)p0y​(1−p0​)x−y

P \left\{y > y_j; x, p_0 \right\}=\sum_{k=y_j+1}^{xj}\binom{x_j}{k} p_0^k(1-p_0)^{x_j-k}P{y>yj​;x,p0​}=∑k=yj​+1xj​(kxj​​)p0k​(1−p0​)xj​−k

为了简化计算,我们还可以假设yj服从正态分布,则根据二项分布的性质,该正态分布的均值为xj*p0, 方差为xj*p0*(1-p0),则yj在标准正态分布中的取值z为:

z=\frac{y_j-x_jp_0}{\sqrt{x_jp_0(1-p_0)}}=\frac{\frac{y_j}{x_j}-p_0}{\sqrt{p_0(1-p_0)}}\sqrt{x_j}z=xj​p0​(1−p0​)​yj​−xj​p0​​=p0​(1−p0​)​xj​yj​​−p0​​xj​​

根据以上第二个公式,在一次真实的上线中,我们可以选取上线后五分钟的总请求数为xj, 错误数为yj, 如果我们知道该接口的基准错误率p0的话,我们就可以据此计算出上线后一段时间内错误数高于当前观测值yj的概率,如果这一概率过小,我们就可以比较有信心的判定这次上线有异常了。简化计算后,可以将z与我们基于经验设定的阈值(例如8)来进行比较,从而直接判定是否异常。

3.2 如何确定基准错误率p0?

3.2.1确定基准错误率p0的三种方法

接下来的问题就是如何确定基准错误率p0了。我们总共会使用三种方法来分别确定一个p0.

第一,我们能够比较直观地想到使用上线前的数据来计算一个基准错误率,当基于这个错误率p0建立二项分布的模型,发现上线后一段时间的错误数高于观测值的概率过低时,则认为上线有异常.

第二,我们发现有些指标的错误率会有天级别的周期性波动,如下图1:

对于上图的情形,如果上线刚好在波谷处开始,并在波峰处结束,使用上线前20分钟的数据计算基准错误率会很容易将该次上线错误地判断为异常。所以,在实践中我们还会选取上线后昨日同时段的数据来计算第二个基准错误率p0, 按照与第一个p0同样的逻辑判断上线是否有异常.

第三,我们还发现,有些API的错误率虽然在上线前后有较大的变动,但即便错误率有所上升,其绝对值仍然较小(比如错误率从千分之一上涨为千分之二),在这种情况下我们认为应该放行上线,而不是阻断。因此,我们可以结合较长时间的历史数据来计算第三个基准错误率p0, 这一p0的计算涉及到KDE和LDA算法,比较复杂, 将在后文中详细介绍

进一步地,如果我们可以分别获取上线过程中已上线和尚未完成上线实例的请求总数和错误数,则可以根据尚未完成上线实例的数据计算基准错误率p0,从而计算出已完成上线实例错误数高于观测值的概率。这样,就可以实现上线过程中实时的上线阻断了。

综上,使用二项分布判断上线行为是否异常的示意图如下:

3.2.2使用KDE算法确定全局p0

当我们有一段较长时间的历史数据时,我们可以基于这些数据计算一个全局的基准错误率p0. 一个简单的想法是可以取整个数据集的平均值,但在实践中我们发现很多错误率指标有较多的突刺,如下图2所示:

如果对上图取平均值作为二项分布的基准错误率来进行检测,那当上线后的时间刚好在突刺处时,我们很可能会错误地阻断上线。所以我们很自然地想到可以取数据集的高分位值(比如99.9分位值)来作为基准错误率,但是当历史数据比较少的时候,取高分位值可能会直接取到数据集中的最大值或接近最大值的值,用这样的值作为基准错误率,效果也很差。

KDE算法就可以完美地解决这个问题,它的思想是,将数据集中的每个点视为一个分布,将这些分布累加起来,就可以得到整个原始数据集的分布我们可以取这个分布的高分位值来作为全局阈值。比如,我们将每个点视为一个高斯分布,随着我们设定的高斯分布的标准差变大,整体分布的示意图如下:

在统计学中,核密度估计(Kernel Density Estimation)算法是一种用来估计随机变量的概率密度函数(PDF: Probability Density Function)的非参数方法。我们可以用它来估算数据集的分布,在上面的例子中,对于每个点分布的假设对应了核密度估计算法中“核”的选取,而高斯分布的标准差则对应了步长(bandwidth)的选取,有一系列经典的算法可以求出步长的最优解,感兴趣的同学可以通过以下链接继续学习:https://jakevdp.github.io/blog/2013/12/01/kernel-density-estimation/

当我们通过KDE算法估计出了一个错误率的历史数据集的分布(即PDF)时,可以进一步地得到它的累计概率密度函数(CDF: Cumulative Distribution Function)和累计概率密度函数的反函数(ICDF: Inverse Cumulative Distribution Function),而ICDF在0.999的取值,就是我们所希望求的全局阈值,即我们上文提到的第三个基准错误率p0

那么,为什么ICDF在0.999的取值等同于数据集的99.9分位置,并且是一个合理的全局阈值呢?我们可以用下面两张示意图来简单的理解:

上面第一张图是一个数据集的概率密度函数曲线(PDF),第二张图是该数据集的累计概率密度函数曲线(CDF)和累计概率密度函数的反函数曲线(ICDF)。我们知道CDF是PDF的积分,且PDF在整个定义域上的积分一定为1,而ICDF是CDF的反函数所以ICDF的定义域为[0, 1]。现在,我们想为以上数据集取一个全局阈值,ICDF在0.999的取值就对应于CDF曲线在纵轴取值为0.999时横轴的取值,即PDF曲线下方面积为0.999时横轴的取值,示意图如下:

上图中红线对应的横轴取值,就是ICDF在0.999时的取值,直观的看,这确实是一个合理的全局阈值。

总体上,计算全局阈值的流程图如下:

3.2.3使用LDA算法去除异常点

在使用KDE算法计算全局阈值的时候会遇到一个问题:如果历史数据中本来就包含一部分的异常数据(如故障导致的错误率偏高),我们最后通过KDE算法取到的全局阈值会受到异常值的干扰,变得异常地高,这显然会使得我们检测的效果变差,如下图所示:

这时,就需要使用LDA算法来先对历史数据进行切分,切除历史数据中的异常值。

LDA (Linear Discriminant Analysis)译作线性判别分析,是一种统计学方法,主要用于分类和降维。其应用和一般形式比较复杂,感兴趣的同学可以自行以维基百科作为起点来学习:https://en.wikipedia.org/wiki/Linear_discriminant_analysis

在智能上线阻断服务中,我们会在计算全局阈值时用到LDA在一维形态下的简单形式,将错误率排序后的时间序列数据切为两段从而将历史数据中可能存在的异常值切去。当然,如果我们发现LDA切走的数据太多,实际上意味着该数据集没有显著的异常值,可以不用切分使用原始数据集即可。以上思想示意图如下:

LDA的数学原理如下:

假设我们有数据集:

x_1, x_2, x_3 ...... x_nx1​,x2​,x3​......xn​

将数据集排序:

x_1 \leq x_2 \leq x_3 ...... \leq x_nx1​≤x2​≤x3​......≤xn​

以为xi切分点,将数据集分为两个集合:

X_L: \left\{x_1, x_2...... x_i \right\}, X_R:\left\{x_{i+1}, x_{i+1}...... x_n \right\}XL​:{x1​,x2​......xi​},XR​:{xi+1​,xi+1​......xn​}

计算两个集合的均值:

\bar x_l, \bar x_rxˉl​,xˉr​

计算两个集合的方差之和:

s_w = \sum_{1}^{i} (x_k - \bar x_l)^2+ \sum_{i+1}^{n} (x_k - \bar x_r)^2sw​=∑1i​(xk​−xˉl​)2+∑i+1n​(xk​−xˉr​)2

遍历i,求sw最小时i的取值即可。以sw为纵轴,i为横轴,在一个真实的数据集上遍历i的示意图如下:

 

上图中蓝色曲线的最小值就是我们要寻找的切分点,该点右侧的数据可以认为是异常值,需要切除

切除异常值后再带入KDE算法计算,全局阈值会回到一个较为合理的范围,如下图所示:

3.3总结

本节介绍了如何通过二项分布、LDA、KDE算法来有效、智能地判断上线是否造成了服务的异常。实际上是通过二项分布将服务上线后的状态(或上线过程中已完成上线实例的状态)与我们认为的基准状态(上线前,上线后昨日同时段,全局阈值)进行比较,寻求指标波动的合理性解释,如果与三种基准状态比较都无法找到这种解释,则说明这次上线确实有异常

四、工程实践

以上我们介绍了智能异常阻断的算法原理,本节将介绍智能上线阻断服务的工程实践,由于全局阈值计算需要的数据较多,计算量较大,需要离线训练,因此该服务的整体架构分为离线训练和在线检测两部分,如下图所示:

在服务开放前,业务同学需要配置服务与API的对应关系API对应的可用性指标等。配置完成后,我们会离线训练前文提到的全局阈值并存在数据库中,当有上线发生时,SRE运维平台会调用我们的智能上线阻断平台,并传递服务名称,上线开始、结束的时间戳等参数,由智能上线阻断服务读取数据库中相关API指标数据和离线计算的全局阈值,并最终判断该上线行为是否异常,将结果返回给SRE运维平台,其中在线检测的详细流程图如下:

目前,智能上线阻断服务已经部署上线,并开放给部分业务方试用,我们计划在未来继续从指标覆盖面、配置灵活性、算法精度等方面继续建设智能上线阻断能力。欢迎各位同学与我们交流。

五、参考资料

一篇介绍KDE编程实践的文章:https://jakevdp.github.io/blog/2013/12/01/kernel-density-estimation/

一篇介绍KDE算法原理的文章:https://mglerner.github.io/posts/histograms-and-kernel-density-estimation-kde-2.html?p=28

LDA算法维基百科:https://en.wikipedia.org/wiki/Linear_discriminant_analysis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Modern C++ | 谈谈万能引用以及它的衍生问题:将亡值、引用折叠和完美转发

文章目录前言左右值引用的铺垫万能引用&&引用折叠完美转发前言 在学习Linux系统编程的过程中,想着得到了新知识,不能把旧知识忘了啊,所以我就读起了以前写的博客,在Modern C介绍这篇博客中,关于完美转发只是介…

安科瑞智能仪表在密集母线行业中的应用

安科瑞 华楠AMB100智能母线监控系列系统示意图功能1.电压、电流、频率、有功功率、无功功率、功率因数、有功电能、无功电能、2-63次谐波、温度、湿度、漏电流等电参量测量;2.交流2DI、2DO,直流4DI、2DO;3.可信号取电或者独立辅助电源供电&am…

windows安装VMware最新版本(VMware Workstation 17.0 Pro)详细教程

目录 一、概述 二、下载 VMware Workstation 17.0 Pro 三、安装 VMware Workstation 17.0 Pro 四、创建一个空的虚拟机 一、概述 VMware Workstation Pro™ 是一个运行在window或Linux系统的软件,使开发人员能够在同一台 PC 上同时运行多个基于 x86 的 Windows、Li…

国内最全的Spring Boot系列之六

在新的一年祝大家兔年大吉,兔耳冲天,动如脱兔! 2022年就这么过去了,闭上眼回首2022年发生的事情,犹如过眼云烟 —— 一事无成的感觉。 2022年到底都发生了什么事情,坚持了什么?于是我闭上眼睛&#xff0c…

2023-1-16 刷题情况

子相似性 III 题目描述 一个句子是由一些单词与它们之间的单个空格组成,且句子的开头和结尾没有多余空格。比方说,“Hello World” ,“HELLO” ,“hello world hello world” 都是句子。每个单词都 只 包含大写和小写英文字母。…

K8s 如何通过 ConfigMap 来配置 Redis ?

1、创建 ConfigMap YAML 配置文件 cat <<EOF >./example-redis-config.yaml apiVersion: v1 kind: ConfigMap metadata:name: example-redis-config data:redis-config: "" EOF2、创建 ConfigMap 资源 kubectl apply -f example-redis-config.yaml创建完成…

VMware 已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作的解决方法

在电脑上安装VMWare&#xff0c;运行虚拟机发现提示无法执行64位操作。本人系统是windows10,64位系统。错误提示&#xff1a; 已将该虚拟机配置为使用 64 位客户机操作系统。但是&#xff0c;无法执行 64 位操作。 此主机支持 Intel VT-x&#xff0c;但 Intel VT-x 处于禁用状态…

HTML的body元素

&#xff08;1&#xff09;HTML的body元素 body是一个简单的HTML稳定最基本的必需元素。 <body> 标签定义文档的主体。 <body> 元素包含文档的所有内容&#xff08;比如文本、超链接、图像、表格和列表等等&#xff09;。 &#xff08;2&#xff09;HTML 网页结…

HTML零基础教程,九大知识点带你玩转前端(上)

博主&#xff1a;冰小九&#xff0c;新人博主一只&#xff0c;欢迎大佬前来指导 冰小九的主页喜欢请给个三连加关注呀&#xff0c;谢谢&#x1f337;&#x1f337;&#x1f337;三连加关注&#xff0c;追文不迷路&#xff0c;你们的支持就是我最大的动力&#xff01;&#xff0…

【自学Docker 】Docker管理命令大全(上)

文章目录Docker create命令Docker create命令概述Docker create命令语法Docker create命令参数列表案例创建容器运行容器Docker create命令总结Docker exec命令Docker exec命令概述Docker exec命令语法Docker exec命令参数列表案例查看文件创建文件进入容器Docker exec命令总结…

Dubbo 自适应SPI

Dubbo 自适应SPI 1. 原理 在 Dubbo 中&#xff0c;很多拓展都是通过 SPI 机制进行加载的&#xff0c;比如 Protocol、Cluster、LoadBalance 等。有时&#xff0c;有些拓展并不想在框架启动阶段被加载&#xff0c;而是希望在拓展方法被调用时&#xff0c;根据运行时参数进行加…

录屏软件无水印免费,分享一款功能强大且免费的录屏软件

市面上多数录屏软件&#xff0c;只能试用版录制几分钟的视频&#xff0c;且带有水印。想要长时间录制电脑屏幕、录制无水印的录屏&#xff0c;需要解锁才可以。那有没有一款录屏软件试用版就能无水印&#xff1f;当然有啦。小编今天给大家分享一款不限制录制时长&#xff0c;且…

springboot整合Freemarker模板引擎

2.2 模板引擎 2.2.1 什么是模板引擎 根据前边的数据模型分析&#xff0c;课程预览就是把课程的相关信息进行整合&#xff0c;在课程预览界面进行展示&#xff0c;课程预览界面与课程发布的课程详情界面一致&#xff0c;保证了教学机构人员发布前看到什么样&#xff0c;发布后…

【Win11 + VSCode配置OpenCV C++一站式开发调试环境教程】

Win11 VSCode配置OpenCV C一站式开发调试环境教程1 下载1.1 版本介绍&#xff1a;1.2 对应三个软件的连接&#xff1a;2 环境配置3 编译1 下载 需要下载三个软件&#xff1a;OpenCV 、MInGW、CMake 1.1 版本介绍&#xff1a; 打开 OpenCV-MinGW-Build&#xff1a;OpenCV-4.…

Android启动流程源码分析(基于Android S)

从上图我们可以清楚的看到Android系统的启动分为以下几个步骤 启动电源以及启动系统 当我们按下电源键时, 引导芯片代码开始从预定义的地方(固化在ROM)开始执行, 加载引导程序到RAM, 然后执行 引导程序 引导程序是在Android操作系统开始运行前的一个小程序. 引导程序是运行的…

图片转PDF怎么弄?这几个方法值得你试一试

PDF是一种特殊的文件格式&#xff0c;它可以在任何设备和平台上进行传输&#xff0c;并且能够保证文件版式不被修改&#xff0c;此外&#xff0c;还可以兼容不同的系统&#xff0c;因为它的这些优势&#xff0c;大多数的人就喜欢将自己编辑好的WORD、PPT、EXCEL、图片等文件转换…

MySQL InnoDB的MVCC实现机制

MySQL InnoDB的MVCC实现机制1.MVCC概述2.MVCC的实现原理隐式字段undo日志Read View(读视图)RR隔离级别的Read View方案1.MVCC概述 什么是MVCC&#xff1f; MVCC&#xff0c;即多版本并发控制。MVCC是一种并发控制的方法&#xff0c;一般在数据库管理系统中&#xff0c;实现对…

YOLOV8——快速训练指南(上手教程、自定义数据训练)

概述 本篇主要用于说明如何使用自己的训练数据&#xff0c;快速在YOLOV8 框架上进行训练。当前&#xff08;20230116&#xff09;官方文档和网上的资源主要都是在开源的数据集上进行测试&#xff0c;对于算法“小白”或者“老鸟”如何快速应用到自己的项目中&#xff0c;这…

操作系统IO控制方式

操作系统I&O控制方式 视频地址&#xff1a;https://www.bilibili.com/video/BV1YE411D7nH?p64 I&O设备按照信息交换的单位可以分为以下两类&#xff1a; 块设备 数据传输的基本单位是块&#xff0c;传输速率较高&#xff0c;可寻址&#xff0c;可随机读写任意一块。…

78.循环神经网络(RNN)

1. 潜变量自回归模型 2. 循环神经网络 计算损失是比较ot和xt之间来计算损失&#xff0c;但是xt是用来更新ht&#xff0c;使得其挪到下一个单元。 用一个额外的whh来存时序信息。 3. 使用循环神经网络的语言模型 4. 困惑度&#xff08;perplexity&#xff09; 5. 梯度剪裁 g表…