SRE是什么
SRE(Site Reliability Engineering,站点可靠性/稳定性工程师),SRE模型是Google对Dev+Ops模型的一种实践和拓展,首个专门面向应用运维的理论体系,一套方法论。
SRE提出的目标:只要是软件,就可能存在bug或者各种运行上的问题。而SRE就是聚焦于的软件系统的稳定性运行。
SRE提出的管理体系:提出了要有服务质量目标(SLO)、on-call轮值、变更和事故管理、故障复盘、应急响应机制等一系列的管理手段。
SRE提出的组织体系:强调以软件工程的方式来解决这些稳定性问题,SRE团队中所有的人都具有软件开发能力,其中50% ~ 60%是纯软件工程师,40% ~ 50%既具备软件开发技能,又具备运维技术(PS:如果运维能有这样的人员配比,感觉“永不宕机”指日可待)。
SRE提出的技术体系:人员能力目标太难达到,我们还是从“事”的角度出发吧。Google认为SRE的职责在于负责软件系统的可用性、时延、性能、效率、变更管理、监控、应急响应和容量管理相关的工作。
稳定性能力建设绝不是一个简单的话题,它需要标准化、流程化、数据化,需要将ITOM的配置、监控、自动化、流程等能力融合,需要我们结合多年的运维经验和不断涌现的各种运维技术来逐步构建、升华。运维界现在在大谈AIOps,但我们知道,除了关键的AI算法能力外,有质量的数据也是AI的基础。
SRE 首先是一套方法论 - 从传统运维中与稳定性相关的工作内容提炼出来进行升华,构建了 SRE 的方法论体系。冗余和容灾、容量规划、系统自动保护、失败预案、监控能力、发布与变更管理、故障应急处理等构成了 SRE 领域的蓝图,并不断地快速迭代着。
方法论的落地实施离不开相关组织和个人,还需要有一系列配套的技术产品和工具来支撑
Mikey 金字塔
Mikey 金字塔可以说是本书作者总结 SRE 运维体系的灵魂,自下而上分为:监控、事故响应、事后回顾、测试与发布、容量规划、构建工具、用户体验等七层。每一层都建立在前一层的基础之上,每一层都被沟通这个基本要求所包围。
从这个框架内容,我个人认为 SRE 运维所遵守几个基本原则:
1)以业务连续性为目标
SRE 的根本出发点和目标就是业务连续性。由于软件做不到 100%完全可靠,一方面,我们基础设施做不到完美,各部分出故障是常态,这会影响到应用可用性;另一方面,我们的软件是人编写的,所以 Bug 不可避免,Bug 出现也会引起异常停机。SRE 做到的是尽可能快的发现和处理故障,并找到可能发生的故障,在预算范围内以有用的方式优化应用、基础设施,满足用户体验的需求。
2)从技术到业务
从监控、事故响应、事后回顾、测试与发布、容量规划、开发到用户体验这七层的递进,可以看出 SRE 运维不只是单纯的技术栈(主机、存储、基础软件设施等)的设备运维,SRE 还逐步延伸业务运维领域,管理应用发布、业务需求以及用户对系统体验的总体期望。这种从技术栈到业务栈的递进,体现了 SRE 运维体系对传统运维体系演进和拓展。
3)高度自动化和工具化
SRE 本身是一个软件工程师以软件工程的方法解决运维问题的体系,因此就自身而言,SRE 极度鄙视重复性的运维工作,更倾向于使用代码的方式去应对各种重复性的运维操作。因此 SRE 运维体系是一个将自动化和工具化提高到战略高度的运维体系模型,正如书中所言:“SRE 的诞生是因为软件工程师触及了运维。目标是将 50%的时间用于编写代码,30%时间用于与人打交道、20%时间用于应对紧急情况。”
4)预防与事故应对
尽管 Mikey 金字塔七层模型中仍然有监控、事件响度和事件回顾等层次,与当前传统应对型运维体系有近似的地方。但是从整体上,SRE 整个运维体系非常强调预防的重要性。通过事件回顾、测试与发布、容量规划、开发等层次的工作来持续优化应用,提升系统的可靠性。“预防胜于治疗”这句话,在 IT 系统建设和运维领域同样适用。
5)平衡风险
SRE 运维体系首先认定新业务需求和新软件版本的发布无论如何总会引入 bug;与此同时,较长的开发周期与更严密的测试会发现并修正 bug,但是亦会延迟业务需求实现以及新版本发布的时间。快速实现业务需求与由于 bug 引起宕机的风险之间需要得到平衡。SRE 通过制定合理的 SLO 以及错误预算,尝试在系统风险与业务快速迭代之间实现可量化的平衡。
监控
系统监控是整个运维体系的基础,它是最基本的运维工作,监控为企业运维提供了一个数据基础,让我们对事故响应以及容量预测等方面更多使用数据而非凭借以往经验和拍脑袋做出决策。一个企业级的监控系统我认为至少应该包括如下几个特征,
监控特征
1)完备指标采集
2)日志采集能力
3)海量设备支持
4)监控数据存储和分析
从运维意义上讲,“发现问题”的描述 和 “监控”的实现之间的对应关系如下:
发现问题的需求描述 | 监控的实现 |
减少人力发现成本 | 自动监控、多种报警手段 |
及时、准确 | 实时监控、同比、环比、对账 |
防止出错 | 减少误报、同比环比、削峰 |
不遗漏 | 减少漏报,多维监控 |
直观评估影响面 | 对账&统计 |
监控标准化
在以业务系统稳定性为目标的前提下,我们对监控提出了新的要求:
监控对象标准化
监控系统需要与以应用为中心的CMDB打通,监控系统中的监控对象来自于CMDB中标准化管理的应用资源对象,从而具备以应用视角的监控展现和分析能力。
监控指标标准化
每个应用系统所提供的业务功能各不相同,应用系统的架构和资源组成也多种多样,但我们仍可以需要从各个层次、各个维度来抽象出一套相对通用的应用系统可观测性指标(见下图)。
监控的5个维度
监控的四个黄金信号
延迟(Latency)
-
定义:服务处理某个请求所需要的时间。
-
重要性:延迟的增加可能意味着系统性能下降或存在瓶颈。对于微服务架构,快速失败和快速反馈是推荐的做法,因此延迟的监控对于快速定位和解决问题至关重要。
-
监控方法:通常监控服务的响应时间,如:tp99(99%响应时间)等指标,以了解服务的性能状况。
延迟是对完成操作所需时间的度量。具体如何测量取决于组件,但一些常见的类似物是处理时间、响应时间或行程时间。
测量延迟可让您具体衡量完成特定任务或操作所需的时间。捕获各种组件的延迟允许您构建系统不同性能特征的整体模型。这可以帮助您找到瓶颈,了解访问哪些资源需要最多的时间,并注意到操作突然花费的时间比预期的时间长。SRE 一书的作者强调在计算延迟时区分成功和不成功请求的重要性,因为它们可能具有非常不同的配置文件,可能会扭曲服务的平均值。
流量(Traffic)
-
定义:当前系统的数据流入流出的数据统计,用来衡量服务的承载能力。
-
重要性:流量的大小直接反映了系统的负载情况,对于容量规划和资源调配具有重要的参考价值。
-
监控方法:通过统计每秒钟的请求量(TPS)或每秒查询数(QPS)等指标来评估系统的流量。
流量衡量您的组件和系统的“繁忙程度”。这会捕获您的服务的负载或需求,以便您了解您的系统当前正在执行多少工作。
持续的高或低流量数字可能表明服务可能需要更多资源,或者问题阻止流量正确路由。但是,在大多数情况下,流量率对于帮助了解通过其他信号浮出水面的问题最有用。例如,如果延迟增加超过可接受的水平,能够将该时间范围与流量峰值相关联是有帮助的。流量可用于了解可以处理的最大流量以及服务在不同负载阶段如何降级或失败。
错误(Errors)
-
定义:当前系统发生错误请求的数量,通常通过错误率来衡量。
-
重要性:错误率是评估系统稳定性和可靠性的重要指标。高错误率可能意味着系统存在严重问题或设计缺陷。
-
监控方法:除了简单的错误计数外,还需要关注错误的具体类型、来源和原因,以便快速定位和解决问题。
跟踪错误以了解组件的健康状况以及它们未能正确响应请求的频率非常重要。某些应用程序或服务会在干净、现成的界面中暴露错误,但可能需要额外的工作来从其他程序收集数据。
区分不同类型的错误可以更轻松地查明影响应用程序的问题的确切性质。这也为您提供了警报的灵活性。如果出现一种类型的错误,您可能需要立即收到警报,但对于另一种错误,只要比率低于可接受的阈值,您就不会担心。
饱和度(Saturation)
-
定义:饱和度用来衡量当前服务的承载能力,通常使用资源的利用率和空闲率来表示。
-
重要性:饱和度反映了系统资源的利用情况,当资源利用率接近或达到饱和时,系统的性能可能会受到影响。
-
监控方法:通过监控系统的CPU、内存、磁盘、网络等资源的利用率来评估系统的饱和度。当资源利用率达到或接近某个阈值时,可能需要采取扩容或优化措施。
饱和度衡量给定资源的使用量。百分比或分数经常与具有明确总容量的资源一起使用,但对于没有明确定义的最大值的资源,可能需要更具创造性的测量。
饱和度数据提供有关服务或应用程序有效运行所依赖的资源的信息。由于一个组件提供的服务可能会被另一个组件使用,因此饱和度是暴露底层系统容量问题的粘合指标之一。因此,一层中的饱和和延迟问题可能与底层中流量或错误测量的显着增加相对应。
四个黄金指标相互关联、相互影响,共同构成了评估系统稳定性和性能的关键框架。通过对这些指标的监控和分析,可以及时发现和解决系统问题,确保系统的稳定、可靠和高效运行。
我们将研究常见分布式应用程序环境中存在的不同级别的复杂性:
-
单独的服务器组件
-
应用程序和服务
-
服务器集合
-
环境依赖
-
端到端体验
从服务器组件收集哪些数据。
要测量 CPU,以下测量可能是合适的:
-
延迟:CPU 调度程序的平均或最大延迟
-
流量:CPU 利用率
-
错误:特定于处理器的错误事件、故障 CPU
-
饱和度:运行队列长度
对于内存,信号可能如下所示:
-
延迟:(无 - 很难找到一种好的衡量方法且不可操作)
-
流量:正在使用的内存量
-
错误:内存不足错误
-
饱和度:OOM 杀手事件,交换使用
对于存储设备:
-
延迟:读取和写入的平均等待时间(await)
-
流量:读写 I/O 级别
-
错误:文件系统错误、/sys/devices 中的磁盘错误
-
饱和度:I/O 队列深度
网络信号可能如下所示:
-
延迟:网络驱动程序队列
-
流量:每秒传入和传出的字节或数据包
-
错误:网络设备错误、丢包
-
饱和度:溢出、丢包、重传段
对于为客户服务的应用程序,四个黄金信号通常很容易挑选:
-
延迟:完成请求的时间
-
流量:每秒服务的请求数
-
错误:处理客户端请求或访问资源时发生的应用程序错误
-
饱和度:当前正在使用的资源的百分比或数量
服务器集合及其通信的指标将考虑到组成员之间所需的额外协调:
-
延迟:池响应请求的时间,与对等方协调或同步的时间
-
流量:池每秒处理的请求数
-
错误:处理客户端请求、访问资源或到达对等点时发生的应用程序错误
-
饱和度:当前使用的资源量、当前满负荷运行的服务器数量、可用的服务器数量。
应用于外部依赖的黄金信号可能类似于:
-
延迟:从服务接收响应或从提供者提供新资源所需的时间
-
流量:推送到外部服务的工作量,向外部 API 发出的请求数
-
错误:服务请求的错误率
-
饱和度:使用的帐户限制资源量(实例、API 请求、可接受的成本等)
整体功能和端到端体验的指标,最高级别的指标在用户与之交互的最外层组件的上下文中跟踪通过系统的请求。这可能是一个负载均衡器或其他路由机制,负责接收和协调对您的服务的请求。由于这是与您的系统的第一个接触点,因此在此级别收集指标可提供整体用户体验的近似值,设置警报时最重要的指标。
在这里收集的数据的范围和重要性:
-
延迟:完成用户请求的时间
-
流量:每秒用户请求数
-
错误:处理客户端请求或访问资源时发生的错误
-
饱和度:当前正在使用的资源的百分比或数量
由于这些指标与用户请求并行,因此超出这些指标可接受范围的值可能表明对用户有直接影响。不符合面向客户或内部 SLA(服务级别协议)的延迟、指示严重高峰或下降的流量、错误率增加以及由于资源限制而无法处理请求都是相当简单的推理在这个级别。假设指标准确,此处的值可以直接映射到您的可用性、性能和可靠性目标。
事故响应
事故响应是建立在使用监控构建的数据之上,并借助反馈循环,来帮助我们加强对服务的监控。
事故响应通常包括以下几个动作:
-
关注,注意到有些东西不对劲
-
交流,告诉别人哪些东西不对劲
-
恢复,纠正不对劲的东西
告警及时性和准确性
有效的告警意味着:告警及时性,系统有问题需要及时通过告警信息告知运维处理人员及时处理告警;告警准确性,只要有告警信息系统必然出现问题。这意味着,错误报警等同于有问题但没有报出来。因为过多过频繁甚至误报的告警,让运维人员的注意力迷失告警海洋当中。抑制和消除无效的告警,让运维人员不被告警风暴所吞没,也是告警管理中重点建设的内容。
从日常运维实践中,我们往往可以通过整合到监控平台中的各种监控数据,应用趋势预测、短周期检测、间歇性恢复、基线判断、重复压缩等算法和手段实现告警压缩收敛,避免监控信息爆炸,强化告警的有效性。
日常报警数量限制,减少报警的方法,可以采用如下手段:
-
对于系统监控报警,采用范围报警,比如load,设置集群内超过N%且机器数大于M的机器load都升高了才报警。毕竟对于一个集群而言,偶尔一台机器的load抖动,是不需要响应的。
-
对于业务报警,一定要做好同比,不但要同比昨天,还要同比上周,通过对比确认,对于一些流量不是很大的业务来说,这一点尤其重要,有些时候错误高,纯粹是ERROR级别日志过度打印,所以只要相对于昨天和上周没有明显增加,就不用报警。
-
对于qps、rt等服务报警,要注意持续性,一般来说,要考虑持续N分钟,才需要报警,偶尔的抖动,是不用报警的。当然,对于成功率下跌,异常数增加,一般要立即报出来。
-
复合报警,比如一方面要持续N分钟,一方面要同比昨天和上周,这样来减少一些无需报警的情况。
-
根据需要设置报警的阈值,避免设置>0就报警这种,这种报警没有意义,一般来说,如果一个报警,连续重复报10条以上,都没有处理,一般是这个报警的通知级别不够,但是如果一个报警,重复10条以上,经过处理人判断,不需要处理,那就肯定是这个报警的阈值有问题。
健康度的分值
面向一线使用人员的场景,我们又往往根据综合同一个系统或设备的多个监控指标进行综合性建模和分析,汇总成一个健康度的分值,给予一线运维人员系统的基于健康度的系统分层评价体系,真实、直观反映系统运行状态,实现问题快速定界。
故障场景梳理
故障场景梳理,重点在于要把可能出现故障的核心场景、表现、定位方法、应对策略梳理清楚,做到应对人员烂熟于心,为演练、故障应急提供脚本。
业务域 | 关键场景 | 问题表现 | 问题定位 | 止血措施 | 预案执行 | 业务影响 | 上游影响 | 下游影响 | 数据影响(操作人) | 服务侧、业务侧应对策略 | 产品端应对策略 |
相关域,要分别梳理上游和下游 | 服务场景,每行列出一个场景,要列出所有可能的场景 | 逐条列出当前场景的所有可能表现 | 对应前面的问题表现,列出每一个表现的定位方法和指标 | 对每个定位的原因,给出快速止血的措施 | 逐条列出可以执行的预案 | 逐条列出可能导致的业务影响和严重程度、范围 | 逐条列出在上游的影响 | 逐条列出对下游的影响 | 逐条列出数据的影响(qps、rt、单量),以及捞取数据的方法、订正数据的方法 | 列出服务端、业务侧的应对话术和退款、赔付、补偿方案; | 列出产品侧对业务侧的沟通方案、客服话术、产品降级方案; |
通过这种程度的梳理,SRE以及其掌控的故障应对人员,能够快速的明确发生问题的场景,以及场景下的影响、表现、定位方法、应对策略。
对于常见告警信息,我们也往往会对接一些配置化的自动化处理动作,例如,一些特殊的应急处理手段(某个文件系统快满了,清理掉当中没有价值的文件)或者一些关键故障信息采集(出现死锁的数据库,自动采集引起死锁的进程信息)供运维人员进一步分析和确认使用。
故障预防阶段
基于标准化的CMDB和监控告警系统构建容量分析体系,以提前预测发现应用性能瓶颈,避免故障发生。
积累标准化的和应用个性化的应急处置自动化预案,以便于应用在发生故障时可以快速恢复。
根据应用高可用架构标准,自动评估各个应用系统的架构可用性能力。
针对关键的业务系统,构建混沌工程来检验业务系统对故障的自动屏蔽和消除能力,并不断积累通用的混沌工具场景。
故障发现阶段
从Metric、Logging、Tracing三种方式实现应用系统的全方位监控和告警。
基于自动化的能力实现应用系统组件和业务功能的主动健康检查。
故障分析和定位阶段
要实现故障的分析定位,首先,我们得对应用系统故障源有清晰和全面的了解。根据多个行业及客户的调研数据,应用系统的故障一般会有以下几种来源:
A、 基础设施可用性问题
包括域名不可达、网络设备或主机故障、主机磁盘空间爆满、进程卡死或停止等。
B、 基础设施性能问题
包括数据库、中间件、消息队列、负载均衡、操作系统等遇到性能瓶颈等。
C、 应用调用链问题
由一个服务引发了另一个服务的异常。
D、 代码异常问题
业务逻辑设计或代码隐藏缺陷引发的可用性或性能问题,或由于变更更新引发的应用故障。
在标准化的CMDB、监控和流程等运维体系的基础上,我们希望故障分析和定位系统,能够结合以上这些运维经验帮我们排查和定位问题:
从应用视角进行基本可用性分析
从应用视角进行基础资源问题分析
基础资源问题分析展示
从应用视角进行用户体验问题分析
从应用角度进行应用性能问题分析
应用运行日志告警展示
故障影响分析能力 -基于CMDB中应用调用关系、资源关联关系提供故障传播链,展示故障上游受影响组件和下游可能的故障源组件。
容量分析能力 -根据容量分析能力判断当前资源容量是否能够支撑业务访问量或交易量。
近期变更前后关键指标对比分析 -获取近期变更数据,展示和对比变更前后应用系统关键的可用性和性能指标数据。并结合故障时间点进行关联分析。
故障汇总与定位看板 -汇总展示关键指标告警及分析结果。
故障处理阶段
- 提供应用快速启停能力
- 提供灾备切换自动化能力
- 根据应用架构特征,提供快速的限流降级、服务熔断的微服务自动化运维能力
- 最后,在故障复盘阶段,除了分析相关的RPO/MTTR/SLA等指标,还需要通过流程等手段沉淀新故障场景到知识库中,以不断提升故障分析和处置能力。
事后回顾
一旦发生服务中断,那么如何确保问题不会再次发生?
- 为了让大家团结协作,我们希望建立一种无指责、透明的事后文化。个人不应该害怕事故,而是确信如果事故发生,团队将会响应和改进系统。
SRE 的一个关键共识正是承认了系统的不完美性,追求永不停机的系统是不现实的。基于不完美系统,我们无可避免要面对和经历系统故障与失败。所以我们重要的并非找到为这个故障责任的这个人或者那个人,而是更应该创根问底地复盘这个故障和失败的根本原因是什么,以及如何避免再次出现相同的故障。系统可靠性是整个团队共同奋斗的方向,从失败中快速恢复并吸取教训,每个人放心地提出问题,应对停机,并努力改进系统。
事故是我们可以从中学习的东西,而不是让人害怕和羞耻的事情!
在日常运维过程中,出现故障等事故对于我们而言其实是一个很好的复盘学习机会。通过历史监控数据,分析事故其中的根本原因,制定后续应对策略,并且通过运维平台将这些应对策略编辑成标准化、可重用、自动化的运维应用场景,为后续相同问题的处理提供标准且快捷的解决方案。这正是事后回顾这个过程最真实的价值体现。
测试与发布
Mikey 金字塔中第一个专注于预防而不是事后处理的层级。预防是指尝试限制发生的事故数量,并确保在发布新代码时基础架构和服务能够保持稳定。
测试是在成本和风险之间找到适当的平衡活动。如果过于冒险,你们可能就会疲于应付系统失败;反过来说,如果你太保守,你就不能足够快地发布新东西,让企业在市场上生存下来。
基于服务水平目标(SLO)而制定的错误预算(Error Budget)
测试是在成本和风险之间找到适当的平衡活动。
SRE 的一个原则是将一切可以重复性劳动代码化和工具化。
通过自动化发布工具,我们可以构建流水线实现部署的过程中所有的操作(如编译打包、测试发布、生产准备、告警屏蔽、服务停止、数据库执行、应用部署、服务重启等)全部自动化,无需人工手工干预解决以往手工发布存在问题:
整个过程都需要人员参与,占用大量的时间,效率低下
-
上线、更新、回滚速度慢
-
规范化低,存在一定的管理混乱,人为误操作的机率增大
容量规划
第五层是容量规划。关于预测未来和发现系统极限的。容量规划也是为了确保系统可以随着时间的推移得到完善和增强。规划的主要目标是管理风险和期望。对于容量规划,涉及到将容量扩展到整个业务。所关注的期望是人们在看到业务增长时期望服务如何响应。风险是在额外的基础设施上花费时间和金钱来处理这个问题。
容量规划首先是对未来预测性的分析与判断,其预测的基础正是海量的运维数据。因此,容量规划除了有相应的架构和规划团队外,一个全面的运维数据中心是实现系统容量规划的必须设施。
它将综合地从各种运维监控、流程管理等数据源中收集、整理、清洗并结构化地存储各种运维数据,将这些来自于各种工具的运维数据打通融合并且构建各种数据主题。应用这些数据主题的数据用于帮助运维人员对问题进行评估,包括:
-
当前的容量是多少
-
何时达到容量极限
-
应该如何更改容量
-
执行容量规划
运维数据可视化分析:首先,运维平台需要有极强的数据检索能力。其二,平台需要强大的数据可视化能力。
开发新工具和服务
SRE 不仅涉及运营,还涉及软件开发。SRE 工程师将花费大约一半的时间来开发新的工具和服务。这些工具中的一部分将用于自动 化一些手工任务,而其他工具将用于改进 Mikey 金字塔的其余部分。通过编写代码把自己和其他人从重复的工作中解放出来。
SRE 从内心上鄙视重复性的工作,将从原有的人工加被动响应,转变为更高效、更为自动化的运维体系。
构建自动化运维工具,其优势在于:
1)让机器管理机器,有效地降低运维人力资源的投入。
2)运维操作的标准化,提升运维操作的可管理性,减少由于运维人员情绪带来手工误操作。
3)运维经验能力的传承,运维团队积累的经验以代码方式总结为各种运维工具,实现自动化和白屏化的运维操作,减少人员流动带来对工作的影响。
构建自动化运维体系就必须以运维场景为基础,支持多种不同类型的自动化作业配置能力,通过简单的脚本开发、场景配置和可视化定制流程实现更多运维场景的实现。
用户体验
即确保用户获得良好的体验。用户体验的管理是 SRE 的最高层次实现,它实际上正是运维的最终目标。最终形成从业务用户体验数据入手,逐步实现系统运行状态数据、设备运行状态数据链路的打通,让运维体系实现以最终用户体验为中心的目标。
SRE 运维体系更为强调以用户的体验为核心,以自动化和运维数据为手段,实现应用业务连续性保障。与其说是系统运维,不如说是系统运营体系或会更为适当。
B站SRE转型
高可用
先看下整体架构。用户首先从 CDN 层到接入层,接入层有4层 LB/7层 SLB,还有逐渐推广的 API GW。
之后进到服务层,服务侧会有一个 BFF(服务网关),下面是 Service、Job、Admin等。
-
-
中间件主要是 MQ,数据同步 Canal、DTS,消息通知 Notify、缓存;
-
存储层面是关系型数据库、 KV、对象存储、ES等等;
-
再往下是可观测与效率体系;
-
底层是稳定性体系,包括服务分级&SLO、混沌工程/故障演练、多活容灾/预案管理、问题管理/事件分析、容量/降本及活动保障。
-
接入层
这是接入层架构,用户通过 DNS 或降级 HTTP DNS 访问 CDN,CDN 通过机房边缘 POP 点汇聚流量到机房,机房有不同可用区(逻辑概念),每个可用区主要是 SLB 和 API GW。
常见的故障有几种:
- 网络故障:边缘节点回机房(运营商公网故障);
- 机房故障:一般比较少遇到(主要看概率);
- 组件故障:比如 SLB 节点发生故障等;
- 服务故障:SLB/API GW 所代理的服务等;
接入层的高可用方案,比如 DNS 降级 HTTP DNS、多 CDN 节点动态选路、APP边缘节点网络层故障降级第三方CDN重试;多 POP 点做流量汇聚,多线路做源站互备。
如果单可用区 SLB 故障,支持 CDN 从其他可用区跨专线回源。
对于后端服务故障,SLB可发现服务区的所有节点;单可用区服务故障节点可以自动降级。SLB 也支持常见的降级、容灾与限流。
最后是 7.13 故障,SLB重建花了一个小时,故障后对 SLB 初始化重建做了很多优化,现在可以5分钟重建一套SLB。API Gateway 的高可用与 SLB 类似,这里不再重复。
服务层
上面说了南北向(接入层),现在来看看东西向。对 SRE 来说,这一层一定要了解(微服务架构),如果不了解一旦服务出现故障给不出业务故障止损预案。
服务调用是通过内部 Discovery 服务发现组件进行调用,服务部署了多活(可用区A和B),每个机房服务都是多节点部署,不同节点所运行的物理机(比如是CPU型号不一导致单核算力不一,要看 K8s 有没有做算力规划)。
这个过程可能出现问题,比如容器节点算力不一,服务B流量过载、可用区故障等,也有几种高可用能力:
-
服务调用有 P2C 算法,服务A调用服务B,服务B会返回自己节点的 CPU 使用率情况,服务A基于这次响应的 RT(包括服务B每个节点 CPU 使用率/成功率来选择一个最优的节点),虽然服务B不同节点 CPU 算力不一,但最终 CPU 使用率是一样的;
-
熔断,服务B故障时,服务A做一个熔断;
-
降级的场景有两种:
-
一是可用区的降级,当服务B在某可用区故障,服务A调用B可以通过服务发现组件降级到其他可用区;另外是做多活的时候,服务在本可用区没有做部署的情况下降级到其他可用区;
-
内容质量降级,服务B故障服务A可以访问本地缓存/降级服务。在我们场景里,如果播放地址失败会降级到灾备播放地址。B站首页APP推荐可能是动态的,推荐系统故障也会降级给用户热门视频。
-
-
限流有两种,一种是微服务框架侧全局限流,它在框架层面的拦截器,B站内部主要是 Golang,使用 Kratos框架,基于框架做了分布式限流。第二部分是动态限流,不需要预先配置,基于 Google 的 TCP BBR 算法来实现的,会自动分析每个容器节点 CPU 使用率/成功 QPS 等来自适应做一个保护。
中间件
服务还有一种故障场景是中间件的依赖。
看看核心服务对中间件依赖,比如服务写数据,对评论、弹幕数据可以接受最终一致,把写的数据扔到 MQ,用 Job 消费消息队列,写入DB。DB 层面会挂一个 Canal 组件,来消费数据库binlog,将消息写回消息队列,再刷到缓存里。
我们用到最常见的组件就是缓存/MQ/DB。
缓存在生产系统里有三种模式,Redis Cluster、Redis单节点/分布式、Memcache(内部是按这个顺序做推荐建议),每种语言在生产环境 SDK 都出现过各种各样的 Bug。
比如短连接风暴,之前搞拜年纪活动,活动一开始充电服务就故障了。后来发现,Jedis 的并发数量超过配置的 Total 之后,后续连接会变成短链接。redis单线程机制,长连接和和短连接性能相差10倍的数量级,一旦遇到短连接性能就会急剧下降。
我们用过各种语言,连 Redis 之后,往一个节点发一些cluster nodes 或者 slot 风暴这种请求,甚至可能会固定往一个节点发请求,很快把一个节点打死了。
当发生 cluster 风暴,再遇到短连接就会出现雪崩,根本没办法恢复。想恢复只能重建缓存或做一个冷重启。后来我们对缓存做了统一的 proxy 代理(sidecar 模式,或者通过 proxyless sdk),也是为了降本增效,把单容器改成 sdk 模式进行部署访问。
消息队列主要做临时持久化,异步写DB。集中式代理,不用 sidecar 模式部署,我们内部支持 redis 和 gRPC 两种协议。2020年B站做了很多扩圈活动,kafka topic数量急剧增加,当时代理是 kafka 的 Sarama SDK,这个 SDK 也是各种炸,不停出现故障。
数据库层面,内部提供数据库 proxy,用 sidecar 模式部署。对业务做读写分离,对业务透明。对异常SQL做拦截,比如慢SQL。为了降本增效,现在也提供了SDK模式。
前面说了很多架构层面的内容,SRE 一定要了解业务架构,如果不懂架构只能做日常需求(那和配管没区别),不懂业务架构的 SRE 是没有灵魂的。