导读:百度搜索系统是百度历史最悠久、规模最大而且对其的使用已经植根在你们平常生活中的系统。坊间有一种有趣的作法:不少人经过打开百度搜索来验证本身的网络是否是通畅的。这种作法说明百度搜索系统在你们心目中是“稳定”的表明,且事实确是如此。百度搜索系统为何具备如此高的可用性?背后使用了哪些技术?以往的技术文章鲜有介绍。本文立足于你们所熟悉的百度搜索系统自己,为你们介绍其可用性治理中关于“稳定性问题分析”方面使用的精细技术,以历史为线索,介绍稳定性问题分析过程当中的困厄之境、破局之道、创新之法。但愿给读者带来一些启发,更但愿能引发志同道合者的共鸣和探讨。前端
全文5110字,预计阅读时间11分钟。算法
上周,在《百度搜索稳定性问题分析的故事(上)》中,已经介绍了咱们是如何经过全面的数据系统建设解决问题追查的死角,没看过的朋友能够从新看下这篇文章。接下来,将分享咱们如何进行故障的自动化、智能化分析,提升问题追查的效率。后端
第4章 再创新:应用价值的再释放
4.1 巨浪——故障分析的“终点”
拒绝的分析是一个定性的过程,根据拒绝query激发的日志信息,就能够定位业务层面的缘由,或者定位到引发异常的模块。网络
这个过程能够抽象为下面几步:架构
(1) 故障(拒绝)信号的感知工具
(2) 故障单位(query)全量信息(日志)的收集post
(3) 根据收集到的信息进行故障单位(query)的归因编码
(4) 对批量故障单位(query)的缘由进行再归类,以及特征挖掘url
整个过程须要在秒级完成,时效性要求很高。过程的顺利执行面临下面8个挑战:spa
挑战1:如何实现快速的日志检索。在采集到拒绝信号以后,拒绝的分析须要快速拿到日志原文,这些信息若是直接从线上扫描,速度和稳定性上显然达不到要求。
挑战2:拒绝定位的实时性和准确性之间的矛盾如何解决。日志越完整,拒绝缘由的分析结果越准确。可是由于网络延迟等缘由,分析模块没法保证立刻拿到全部的日志。接收到拒绝信号后就开始分析,能够确保分析的实时性,可是准确性难以保证。而延迟一段时间再分析,可能会拿到更完整的日志,可是会影响拒绝分析的实时性。
挑战3:如何准确全面地描述故障。生产环境的故障“五花八门”,若是逐个进行表达和管理,维护成本会很是高。须要寻找一种方案,把全部的故障(规则)系统、准确、全面地管理起来。
挑战4:特征工程如何进行。在拿到日志原文以后,咱们须要肯定从日志中应该拿哪些信息,如何采集这些信息,而且以程序能够理解的方式将这些特征表达出来,最终和拒绝缘由关联起来,即特征的选择、提取、表达和应用。
挑战5:如何还原query现场。在线系统为了保证可用性,关键模块上都会有重查。在定位拒绝时,须要还原出完整的调度树,这样才能看到由根节点出发到叶子节点各条路径失败的缘由,否则可能会获得矛盾的结果。以下图所示,A-一、B-1和B-2节点都发生了重查,当拼接错误时(C模块的实例挂到了错误的B模块节点下),B-1(或B-2)的错误状态和挂在它之下的C模块的日志状态多是矛盾的,没法得出正确的定位结论。
挑战6:如何对拒绝特征进行深度挖掘。自动定位难以定位到根因,更精确的定位依赖人工参与的继续分析。分析工具须要能从各类拒绝中找到汇集特征并以必定的优先顺序展现给用户,为根因定位或者止损提供更多线索。query中能够提取的信息包括query的查询词(word),发送query的client端ip,query的语种或者处理query的机器所在的物理机房等。好比,当发现系统拒绝都和某个ip的攻击流量有关时,能够对该ip进行封禁止损。
挑战7:级联故障如何感知。当某个模块故障引发拒绝时,可能会产生级联的次生故障,表现为拒绝直接缘由多样化。下图展现了 一种典型的级联故障:E异常后B对C发起了大量重查,首查叠加剧查流量完全把D压垮,最后A对B也开始发起大量重查。拒绝的流量在个个模块都有可能命中限流策略,表现为不一样的拒绝缘由。所以,在产生故障时,依赖某一个时间点的拒绝统计信息可能会掩盖引发拒绝的根因。
挑战8:如何定位未知故障。故障是偶发的,咱们进行拒绝缘由划分的时候所使用的划分集合,没法完总体现系统可能出现的拒绝缘由。对于未知故障或者未被归入到拒绝定位规则中的拒绝,咱们须要有手段“制造”故障,发现未知或者未采集到的故障。
下面,将依次介绍咱们是如何解决这8个问题的。
4.1.1 索引镜像技术
为了实现日志的快速检索,日志索引由在线采集模块提取后,除了推送本机创建索引以外,还将定位须要的子集主动推送至旁路索引模块,该模块会以日志对应的queryID为key写入内存介质的全量索引存储中。这里的索引支持多列稀疏存储,相同queryID的多条日志location能够追加写入。这样,单条拒绝query的location信息能够已O(1)的时间复杂度拿到,接下来并行地到目标机器上捞取日志,并将其写入持久化的故障日志存储中。最后对这些日志进行特征提取并分析拒绝缘由。
4.1.2 流式分析
为了解决问题2,咱们借鉴了流式分析的理念。不管是分析模块收到了拒绝信号仍是增量的拒绝日志信号,都触发一次拒绝缘由的分析,并更新结论。这里有2个关键点:一是分析自动触发,线上只要发生拒绝,拒绝分析就开始工做。二是增量更新,只要某个拒绝query的日志有更新,就从新触发故障缘由分析。对于入口模块,在线采集端会根据其日志中的指定字段判断是不是拒绝,并将这个信号连同索引一块儿推送到旁路索引模块。旁路索引模块在收到该信号后会当即通知分析中心对这个queryID进行分析,所以分析流程能够在拒绝报警发出以前触发,最大化故障定位止损效率。当旁路索引模块向分析模块触发完一次分析请求后,会将这个queryID记录到全量索引存储的pvlost表中,当后续有非入口模块日志的索引到达时,旁路索引模块拿该索引中的queryID到这个表中查找,便可判断是不是须要触发增量分析。增量分析会合并全部已知日志,并更新分析结论。
4.1.3 完备labelset
在入口模块接收到用户query后,该query会经多个模块的处理。每一个模块都有读取、解析请求包,请求后端,处理后端返回结果,以及最后的打包发送流程。在这个抽象层级上,请求处理各个步骤的划分是足够明确的,而且均可能出现失败而引发query在该模块的拒绝。因此,咱们对这个处理过程当中可能失败的缘由进行了枚举,构建了单模块故障缘由完备模板,将该模版应用到全部的必查模块就构成了故障缘由的完备集合。
4.1.4 特征工程
在肯定了完备labelset(拒绝缘由)以后,咱们须要在程序中实现自动的特征提取、表达,并和拒绝缘由创建映射。不一样模块的业务日志差别很大,为了解决特征的提取问题,咱们实现规则提取引擎,输入为日志原文和提取规则,输出为采集到的特征。特征的类型主要有2种:指定内容是否存在、值是多少。在提取出特征以后,咱们使用一个向量表示各个特征的取值,当向量中某些特征的取值知足指定的条件(等于、在指定范围等)时,就给出对应的拒绝缘由。
4.1.5 单query现场还原
日志分析模块拿到的日志只是相互独立的节点,进行query现场还原后才能开始分析。从入口模块开始,搜索系统的各个模块会把本身的span_id,以及所调度的多个后端的span_id打印出来,依据这些信息便可还原调度现场。须要注意的是,模块发起的首查和重查是有前后顺序的,经过对一个节点的孩子节点的span_id进行排序,便可还原这种调度上的前后次序。在还原调度树以后,将调度树由根节点到叶子节点路径上的全部异常日志汇总,从中拿到全部的特征并和规则列表进行比对,便可获得该路径(调用链)的拒绝缘由。
4.1.6 智能rank算法
问题6的难点在于:在一批query全部维度的特征中,找到有明显汇集性的一个(一组)维度。这能够进一步表示为:在不一样维度之间进行排序,找到排名最考前的维度,而排序的依据就是该维度内部取值是否有高度的汇集性。为了解决这个问题,咱们借用了熵的概念——当拒绝的query在某个维度上取值汇集越强时,它的熵就会越低。在构建排序模型时,咱们对不一样维度的取值进行了变换,确保不一样维度可比,并加入了人工经验肯定维度权重。这样就能够在出现拒绝时,按照顺序给出拒绝query在不一样维度的汇集性,帮助定位根因或制定止损策略。
4.1.7 时间线分析机制
为了准确感知到拒绝的演化过程,咱们实现了timeline机制。收到拒绝报警后,该工具会自动从巨浪获取拒绝信息,按照秒级粒度进行拒绝缘由数量统计,并进行二维展现,以下图所示。在该展现结果上,能够看到不一样秒级时间各类拒绝的数量,以及不一样拒绝缘由随时间的变化趋势,帮助咱们定位根因。
4.1.8 混沌工程技术
问了解决问题8,咱们引入了混沌工程的技术。混沌工程提供了向在线服务精确注入各类故障的能力,这样就能够拿到丰富且带标记的样本补充到定位知识库中。这样不只解决了日志样本问题,还可提高对未知故障的预测能力,从“亡羊补牢”进化到“未雨绸缪”,防患于未然。
这8大技术,很好的解决了前面的8个问题。在定位效果上,准确率可达99%,出现拒绝后,产出模块粒度的拒绝缘由能够在秒级完成,分析能力可覆盖大规模拒绝。
4.2 长尾批量分析
搜索系统中存在着一些响应时间长尾,为了解决这个问题,咱们基于全量tracing和logging数据,实现了一套例行长尾缘由分析机制。该机制定时从入口模块拿到响应时间长尾的query,再对每一个query调用全量调用链的接口拿到完整的调度树。在分析长尾缘由时,从入口模块开始,经过广度优先遍历的方式,逐步向后端模块推动,直到找到最后一个响应时间异常模块,即认为长尾是由该模块引发的。
模块响应时间异常的定义为:该模块的响应时间超过了正常请求的极限响应时间,而且它所调用的模块的响应时间是正常的。在肯定异常模块以后,能够进一步从全量调用链中有针对性的拿到该模块的日志,从日志中根据规则找到该模块处理耗时异常的阶段。
4.3 异常状态全流程追踪
为了确保用户体验的稳定性,搜索会按期分析未召回预期结果的query。query没有返回预期结果,多是由于它命中了“捣乱者”写入的cache,也有可能它穿透了cache,召回了有问题的结果,这里问题的缘由多是偶发的或者是稳定的。咱们须要能筛选出能够稳定复现的问题进行追查。为了实现这个需求,咱们先拿到各个query的tracing以及logging信息,根据这些信息能够:
(1)找到哪些query命中了“捣乱者”写入的脏cache;
(2)哪些query穿透到了后端并从新进行了检索。
将命中cache的query和写入cache的query关联起来,便可获得下图所示的结果——异常状态的全流程追踪。只要异常效果持续时间内的cache命中是连续的,而且触发了屡次cache的更新,那么就能够认为在这一段时间内,故障是稳定复现的,能够投入人力追查。
第5章 总结
本文首先介绍了百度搜索可用性保障的困境,超大的服务规模、极高频的变动和参与人数、海量数据和请求量、多样且多变的故障种类等构成的复杂系统,对年只能停服5分钟的极端严格可用性目标构成了极大挑战。而后,以时间顺序介绍了咱们对百度搜索可用性保障的解决经历和经验。
首先,为了解决问题追查死角的问题,咱们建设了可观测基础——logging、tracing、metrics,这些没有精细加工的基础数据解决了可用性保障中的一部分问题,可是咱们发现基础数据的自动化程度较低、智能性较差,复杂问题须要大量人力投入,分析效果强依赖人工经验,甚至根本没法分析。
更进一步,为了解决可用性保障的效率问题,咱们对体系中的各个组件进行升级,使可观测性的产出变得可观测,复杂的效果故障由不可追查变得可追查,拒绝分析从人工变得自动、准确、高效。在整个体系建设过程当中,咱们从数据的消费者,变成数据的生产者和加工者,经过数据的生产、加工、分析全流程闭环,使得百度搜索中各类故障无处遁形、无懈可击,使得百度搜索可用性保障摆脱困境,持续维持较好的用户口碑,同时本文也但愿给读者带来一些启发,更但愿能引发志同道合者的共鸣和探讨。
本期做者 | ZhenZhen;LiDuo;XuZhiMing
招聘信息:
关注同名公众号百度Geek说,点击菜单栏“内推”便可加入搜索架构部,咱们期待你的加入!
推荐阅读:
---------- END ----------
百度Geek说
百度官方技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
欢迎各位同窗关注