1. 引言
什么是SRE呢?SRE全称为:Site Reliability Engineering,意为:站点可靠性工程师。
SRE这个概念来自Google,Systems Engineer, Site Reliability Engineering是Google招聘给出的职位描述,我们具体看看这个岗位的要求:
职位简介:
Site Reliability Engineering (SRE) combines software and systems engineering to build and run large-scale, massively distributed, fault-tolerant systems. SRE ensures that Google's services—both our internally critical and our externally-visible systems—have reliability, uptime appropriate to users' needs and a fast rate of improvement. Additionally SRE’s will keep an ever-watchful eye on our systems capacity and performance. Much of our software development focuses on optimizing existing systems, building infrastructure and eliminating work through automation.
On the SRE team, you’ll have the opportunity to manage the complex challenges of scale which are unique to Google, while using your expertise in coding, algorithms, complexity analysis and large-scale system design.
SRE's culture of diversity, intellectual curiosity, problem solving and openness is key to its success. Our organization brings together people with a wide variety of backgrounds, experiences and perspectives. We encourage them to collaborate, think big and take risks in a blame-free environment. We promote self-direction to work on meaningful projects, while we also strive to create an environment that provides the support and mentorship needed to learn and grow.To learn more: check out our books on Site Reliability Engineering, watch a recorded Hangout on Air to meet some of our SREs, or read a career profile about why a Software Engineer chose to join SRE.
Behind everything our users see online is the architecture built by the Technical Infrastructure team to keep it running. From developing and maintaining our data centers to building the next generation of Google platforms, we make Google's product portfolio possible. We're proud to be our engineers' engineers and love voiding warranties by taking things apart so we can rebuild them. We keep our networks up and running, ensuring our users have the best and fastest experience possible.
Google SRE是目前最稳定性领域的最佳实践,在引入了微服务、容器,以及其他的分布式技术和产品之后,复杂架构的系统稳定性很难得到保证。这时候就需要 SRE 。
2. 什么是SRE
一位从业者的回答:
DevOps核心是做全栈交付,SRE的核心是做稳定性保障,关注业务的所有活动,两者的共性是:都是用软件工程解决问题;DevOps的诞生是由于互联网商业市场竞争加剧,企业为了减少试错成本,往往推出最小可行产品,产品需要不断且高频迭代来满足市场需求,抢占市场(产品迭代是关乎一整条交付链的事),高频的迭代则会促使研发团队使用敏捷模式,敏捷模式下对运维的全栈交付能力要求更严格,则运维必须开启DevOps来实现全栈交付;因为不断的迭代交付(也就是俗称的变更)是触发故障,非稳定性根源,而互联网产品、服务稳定性缺失会造成用户流失,甚至流到竞争对手那里,因此关注业务稳定性也变得十分重要,SRE由此诞生。
2.1 如何理解SRE
通过一张图来理解SRE团队的日常工作:
从职能分工上来说,SRE的体系结构不是单个岗位或者单个部门就能独立完成的,必须依赖高效的跨团队组织协作才可以。
如果从之前提到的Google的职位要求来说的话,SRE对岗位要求非常高,从服务的启动到部署的整个生命周期都需要参与。
2.2 如何做好SRE
做好SRE的最重要的目的的是什么呢?很明显,提升稳定性。
业界对于稳定性有通用的衡量标准,有两个非常关键的指标:
- MTBF : Mean Time Between Failure , 平均故障时间间隔
- MTTR : Mean Time To Repair , 故障平均修复时间
从SRE稳定性保障规划图中,我们把软件的整个运行周期按照这两个指标分成了两段,通俗的说:MTBF指示了系统运行的正常阶段,而MTTR则意味着系统故障状态的阶段。
针对提升稳定性的问题,就可以从两个方向来实现:
- 提升MTBF:也就是说减少故障发生的次数,提升故障发生间隔时长
- 降低MTTR:故障不可避免,那就提升故障处理效率,减少故障影响时长
从SRE稳定性保障规划图中,可以把MTTR细分为四个指标:MTTI、MTTK、MTTF、MTTV
对于SRE来说,做任何一件事情、开发任何一套系统、引入任何一个理论和方法论,有且只有一个目标,就是“提升MTBF,降低MTTR”,即提升故障发生间隔时长,减少故障影响时长。
3. 系统可用性
衡量系统可用性的两种方式:
- 时间维度:Availability = Uptime / (Uptime + Downtime)
- 请求维度:Availability = Successful request / Total request
时间维度,是从故障角度出发对系统稳定性进行评估。
按照时间维度统计的可用性生成的对照表,如图所示:
当一个系统中,因为网络抖动,每次都有短暂的几秒钟、十几秒钟,或者几分钟异常,但是后面系统自己恢复了,按照时长维度,这并不算做是系统故障,但是这样的抖动次数增多了,可能不是故障,但肯定是不稳定了。
所以,采用这种时长维度来衡量系统稳定性的方式,主要缺点是粒度不够精细。
如何衡量的更精细呢?那就需要用到第二种衡量方式,从请求维度来衡量系统可用性。
用一句话说,请求维度,是从成功请求占比的角度出发,对系统的稳定性进行评估。
请求维度的系统可用性同样包括三个关键要素:
- 请求成功率
- 衡量目标:成功率达到95%才算系统运行正常
- 统计周期:我们统计一个周期内(一天、一周、一个月等等)计算整体状况,而不是看单次的
这里,我们就总结出了一条至关重要的经验了:故障一定意味着不稳定,但是不稳定,并不一定意味着一定有故障发生。
设定系统稳定性目标要考虑的3个因素:
-
成本因素
理论上来说,越多的9稳定性越好,但是付出的成本和代价也会更高。为了更高的可靠性,需要有更多的冗余资源投入,甚至需要做主备、双活甚至多活。并不是所有公司都需要付出那么多的成本,而是首先需要考虑ROI(回报率),这时候就需要看企业自身对于成本压力的承担情况了。
-
业务容忍度
根据系统的核心与非核心,业务的容忍度也不尽相同。
-
系统当前的稳定性状态
结合当前系统的实际情况,定一个合理的标准比定一个更高的标准会更重要。
SRE更多采用的是请求维度的统计方式,因为SRE关注的稳定性是系统的整体运行状态,而不仅仅只关注故障状态下的稳定性,在系统运行过程中任何异常,都会被纳入稳定性的评估范畴中。
4. SRE的切入点
SRE中更多采用的是请求维度的统计方式,一般不看单次请求的成功与否,而是看整体情况,所以通常我们会把请求的占比设定为一个可以接受的目标,也就是我们平常说的“99.9%”和“99.99%”这样可以量化的数字。
那么,这个“确定成功请求条件,设定达成占比目标”的过程,在SRE中就是设定稳定性衡量标准的SLI和SLO过程。
4.1 SLI和SLO是什么?
SLI就是我们要监控的指标,SLO就是这个指标对应的目标。
4.2 哪些系统指标适合SLI?
关于SLI指标的两大原则:
- 原则一:选择能够标识一个主体是否稳定的指标,如果不是这个主体本身的指标,或者不能标识主体稳定性的,就要排除在外
- 原则二:针对电商这类有用户界面的业务系统,优先选择与用户体验强相关或用户可以明显感知的指标
快速识别SLI指标的方法:VALET
-
Volume 容量
Volume是指服务承诺的最大容量是多少。比如一个应用集群的QPS、TPS、会话数以及连接数等等,如果我们对日常设定一个目标,就是日常容量的SLO,对双11这样的大促设定一个目标,就是大促SLO。
-
Availablity 可用性
Availablity 可用性代表服务是否正常,比如前面说的请求调用的非5xx状态码成功率,就可以归于可用性
-
Latency 时延
Latency 时延是说响应是否足够快,这是一个会直接影响用户访问体验的指标,对于任务类的作业,我们会看每个任务是否在规定时间内完成了。
-
Errors 错误率
4.3 如何通过SLO计算可用性?
-
第一种,直接根据成功的定义来计算
Successful = (状态码非5xx)& (时延 <= 80ms)
-
第二种,SLO计算方式
- SLO1:99.5%状态码成功率
- SLO2:90% Latency <= 80ms
- SLO3:99% Latency <=200ms
直接用公式表示:
Availability = SLO1 & SLO2 & SLO3
只有当这三个SLO同时达标时,整个系统稳定性才算达标,有一个不达标就不算达标,这样就可以很好的将SLO设定的合理性与最终可用性结合起来。
Google 的 SLI 和 SLO 设定模板链接:https://landing.google.com/sre/workbook/chapters/slo-document
5. 错误预算:达成稳定性目标的共识机制
5.1 错误预算
当SLO目标制定好了之后,很具体,但是实施起来不直观,我们通常反过来看,即制定一个允许犯错的次数标准。
这个概念叫做Error Budget ——错误预算。
错误预算最大的作用是“提示你还有多少次犯错的机会”,并且,错误预算的警示效果比看成功率这种统计数据更直观,感官冲击力更强。
从图中的数字可以看出,错误预算的计算很简单,但是起到的警示效果又很强烈,所以在SLO落地实践时,我们通常就把SLO转换为错误预算,以此来推进稳定性目标达成。
5.2 如何应用Error Budget?
-
稳定性燃尽图
当错误预警消耗达到一定比例的时候,如80%或90%的时候,就要开始预警了,控制各种变种,或者投入精力去解决影响稳定性的问题。
-
故障定级
在《运维体系管理课中》,蘑菇街将故障等级定为P0~P4这5个等级,P0为最高,P4为最低。
在实际情况中,还要根据实际业务情况和容忍度来制定。
-
稳定性共识机制
-
第一,剩余预算充足或未消耗完之前,对问题的发生要有容忍度。
-
第二,剩余预算消耗过快或即将消耗完之前,SRE有权中止和拒绝任何线上变更。
可以看到,这里涉及跨团队沟通共识机制。从推行的角度来讲,建立稳定性共识机制一定是Top-Down,也就是自上而下,至少要从技术VP或CTO角度去推行,而且当有意见不一致的情况出现时,还要逐步上升,直至CTO角度来做决策。关于这一点,你需要特别注意,一定要自上而下推进周边团队或利益方达成共识。
-
-
基于错误预算的告警
5.3 如何衡量SLO的有效性?
衡量SLO及错误预算策略是否有效,其实就是看实际运行后,是否真能达到我们的期望。我们可以从下面三个关键维度来看:
- SLO达成情况:我们用达成(Met),或未达成(Missed)来表示
- “人肉”投入程度:泛指需要大量人工投入、重复、繁琐且没有太多价值的事情。我们用投入程度高(High)和低(Low)来表示
- 用户满意度:可以理解为用户感受和体验如何。这个信息可以通过真实和虚拟渠道获得。真实渠道如客服投诉、客户访谈和舆情监控获取;虚拟渠道如真机摸你拨测。我们用满意度高(High)和低(Low)来表示
总共3个维度,每个维度2种情况,组合起来就是8种情况,通过Google给出的图表和建议。
针对这8种情况,我们分别给出对应的策略,总结一下,应对方式可以分为3类。
-
第一类,收紧SLO
这个时候就是目标设定的太低了,比如SLO达成(Met),但是用户不满意(Low)。这就表示我们的SLO设定的太容易达成,没有反馈真实的运行情况。
-
第二类,放宽SLO
与第一类相反,目标设定的太高,总是达不成(Missed),但用户反馈确很不错(High),这种就会造成错误预算提前消耗完,导致很多变更暂停,产品延期,甚至会做一些无谓的优化,这时就可以适当松松绑。
-
第三类,保持现状,对有问题的维度采取有针对性的优化措施
比如表格的第一行,是我们期望的最理想状态,SLO能达成,人肉投入又低,客户满意度又很高,也没有特别优化的优化空间,这时我们就可以增加发布和变更的次数,更大程度的释放生产力。
6. 落地SLO时还需要考虑哪些因素?
通过电商系统案例的基础情况,框定接下来要讨论的内容范围。
一般来说,电商系统一定有一个或几个核心服务,比如要给用户提供商品选择、搜索和购买的服务等。但我们知道,大部分用户并不是上来就购买,而是会有一个访问的过程,他们会先登录,再搜索,然后访问一个或多个商品详情介绍,决定是放到购物车候选,还是选择物流地址后直接下单,最后支付购买。
这条从登录到购买的链路,我们一般称之为系统的核心链路(Critical Path),系统或网站 就是依靠这样一条访问链路,为用户提供了购买商品的服务能力。
至于电商系统的其它页面或能力,比如网站政策、新手指导、开店指南等等,这些对用户购买服务不会造成太大影响的,相对于核心链路来说,它的重要性就相对低一些。
我们要给电商系统设定 SLO,大的原则就是先设定核心链路的 SLO,然后根据核心链路进 行 SLO 的分解。
面对这样复杂的应用关系,是无法下手的,通过精简也就是区分哪些是核 心应用,哪些是非核心应用。这是要根据业务场景和特点来决定的,基本上需要对每个应用 逐个进行分析和讨论。这个过程可能要投入大量的人工来才能完成,但这个是基础,虽然繁 琐且费时费力,也一定要做。
比如用户访问商品详情的时候,会同时展现商品评价信息,但是这些信息不展现,对于用户选择商品也不会造成非常大影响,特别是在双十一大促这样的场景中,用户在这个时刻的目的很明确,就是购买商品,并不是看评价。所以类似商品评价的应用是可以降级的,或者短时间不提供服务。那这种不影响核心业务的应用就可以归为非核心应用。
相反的,像商品 SKU 或优惠券这样的应用,直接决定了用户最终的购买金额,这种应用在 任何时刻都要保持高可用。那这种必须是高可用的应用就是核心应用。
就这样,我们需要投入一些精力一一来看,确定哪些是核心应用,哪些是非核心应用。梳理完成后,针对电商系统,我们大概可以得到一个类似下图的简化拓扑关系(当然了,这里仍然是示例,相对简化,主要是保证效果上一目了然)。
这张图就呈现出一条典型的电商交易的关键路径,其中绿色部分为核心应用,蓝色部分为非核心应用。这个时候,我们又要进行关键的一步了,就是确认强弱依赖。
核心应用之间的依赖关系,我们称之为强依赖,而其它应用之间的依赖关系,我们称之为弱 依赖,这里就包含两种关系,一种是核心应用与非核心应用之间的依赖,另一种是非核心应 用之间的依赖。
好了,至此,我们就确定了这个电商系统的核心应用和强弱依赖关系,也就是找到了这个系 统的核心链路。那我们就可以设定这条核心链路的 SLO 了,并基于此设定其他的 SLO。这 时应该遵循哪些原则呢?
6.1 设置SLO有哪些原则?
针对核心和非核心应用,以及强弱依赖关系,我们在设定 SLO 时的要求也是不同的,具体 来说,可以采取下面 4 个原则。
第一,核心应用的 SLO 要更严格,非核心应用可以放宽。 这么做,就是为了确保 SRE 的 精力能够更多地关注在核心业务上。
第二,强依赖之间的核心应用,SLO 要一致。 比如下单的 Buy 应用要依赖 Coupon 这个 促销应用,我们要求下单成功率的 SLO 要 99.95%,如果 Coupon 只有 99.9%,那很显 然,下单成功率是达不成目标的,所以我们就会要求 Coupon 的成功率 SLO 也要达到 99.95% 。
第三,弱依赖中,核心应用对非核心的依赖,要有降级、熔断和限流等服务治理手段。 这 样做是为了避免由非核心应用的异常而导致核心应用 SLO 不达标。
第四,Error Budget 策略,核心应用的错误预算要共享,就是如果某个核心应用错误预算 消耗完,SLO 没有达成,那整条链路,原则上是要全部暂停操作的,因为对于用户来说, 他不会判断是因为哪个应用有问题,导致的体验或感受不好。所以,单个应用的错误预算消 耗完,都要停止变更,等问题完全解决再恢复变更。当然,也可以根据实际情况适当宽松, 如果某个核心应用自身预算充足,且变更不影响核心链路功能,也可以按照自己的节奏继续 做变更。这一点,你可以根据业务情况自行判断。
6.2 如何验证核心链路的SLO?
6.2.1 容量压测
我们先来看容量压测。容量压测的主要作用,就是看 SLO 中的 Volume,也就是容量目标 是否可以达成。对于一般的业务系统,我们都会用 QPS 和 TPS 来表示系统容量,得到了容 量这个指标,你就可以在平时观察应用或系统运行的容量水位情况。比如,我们设定容量的 SLO 是 5000 QPS,如果日常达到 4500,也就是 SLO 的 90%,我们认为这个水位状态 下,就要启动扩容,提前应对更大的访问流量。
容量压测的另一个作用,就是看在极端的容量场景下,验证我们前面说到的限流降级策略是否可以生效。
我们看上面电商交易的关键路径图,以 Detail(商品详情页)和 Comment(商品评论) 这两个应用之间的弱依赖关系为例。从弱依赖的原则上讲,如果 Comment 出现被调用次 数过多超时或失败,是不能影响 Detail 这个核心应用的,这时,我们就要看这两个应用之 间对应的降级策略是否生效,如果生效业务流程是不会阻塞的,如果没有生效,那这条链路 的成功率就会马上降下来。
另外,还有一种场景,如果某个非核心应用调用 Detail 的次数突然激增,对于 Detail 来 说,它自身的限流保护机制要发挥作用,确保自己不会被外部流量随意打垮。
其实类似上述这两种场景,在分布式系统中仅仅靠分析或画架构图是无法暴露出来的,因为业务变更每天都在做,应用之间的调用关系和调用量也在随时发生变化。这时候就需要有容量压测这样的手段来模拟验证,进而暴露依赖关系问题。并且,有些问题必须要在极端场景下模拟才能验证出问题,比如各种服务治理措施,只有在大流量高并发的压力测试下,才能被验证出是否有效。
6.2.2 Chaos Engineering- 混沌工程
我们知道,现在混沌功能非常流行,因为它可以帮助我们做到在线上模拟真实的故障,做线上应急演练,提前发现隐患。很多公司都很推崇这种方法并在积极学习落地中。
其实,刚才我们讲容量压测也提到,容量压测是模拟线上真实的用户访问行为的,但是压测过程中,如果我们模拟极端场景,可能也会造成异常发生,但这时的异常是被动发生的,不过从效果上来讲,其实跟混沌工程就很相似了。只不过,混沌工程是模拟故障发生场景,主动产生线上异常和故障。
那我们怎么把混沌工程应用在 SRE 中呢?一般来说,故障发生的层面不同,我们采取的方式也会不同。
这里我简单介绍一下,比如对于机房故障,有些大厂会直接模拟断电这样的场景,看机房是否可以切换到双活或备用机房;在网络层面,我们会模拟丢包或网卡流量打满;硬件和系统层面,可能故意把一块磁盘写满,或者把 CPU 跑满,甚至直接把一个服务器重启;应用层 面,更多地会做一些故障注入,比如增加某个接口时延,直接返回错误异常,线程池跑满, 甚至一个应用集群直接下线一半或更多机器等。
其实混沌工程也是一个非常复杂的系统化工程,因为要在线上制造故障,或多或少都要对线上业务造成影响,如果模拟故障造成的真实影响超过了预估影响,也要能够快速隔离,并快速恢复正常业务。即使是在稳定性体系已经非常完善的情况下,对于混沌工程的实施也要极为谨慎小心。对于一个模拟策略上线实施,一定是在一个隔离的环境中经过了大量反复验证,包括异常情况下的恢复预案实施,确保影响可控之后,在经过多方团队评审或验证,才最终在线上实施。
从这个角度来讲 SRE 和混沌工程是什么关系,就非常清晰了,**混沌工程是 SRE 稳定性体系 建设的高级阶段,**一定是SRE 体系在服务治理、容量压测、链路跟踪、监控告警、运维自 动化等相对基础和必需的部分非常完善的情况下才会考的。
所以,引入混沌工程手段要非常慎重,我建议大可不必跟风过早引入,还是优先一步步打好基础再做考虑。
6.3 什么时候做系统验证?
参考Google给出的建议:
核心就是错误预算充足就可以尝试了,尽量避开错误预算不足的时间段。因为在正常业务下,我们要完成SLO已经有很大的压力了,不能再给系统稳定性增加新的风险。
同时,还要评估故障模拟带来的影响,如果造成的业务影响很大,那就要把引入方案进行粒度细化,分步骤,避免造成不可预估的损失。
通常的做法,就是选择凌晨,业务量相对较小的情况下做演练。
这样即使出现问题,影响面也可控,而且会有比较充足的时间执行恢复操作,同时,在做较大规模的全站演练前,比如全链路的压测,会做单链路和单业务的单独演练,只有单链路全部演练通过,才会执行更大规模的多链路和全链路同时演练。
总之,生产系统的稳定性在任何时候,都是最高优先级要保证的,决不能因为演练导致系统异常或故障,这也是不被允许的。所以,一定要选择合适的时机,在有充分准备和预案的情况下实施各类验证工作。这样即使出现问题,影响面也可控,而且会有比较充足的时间执行恢复操作,同时,在做较大规模的全站演练前,比如全链路的压测,会做单链路和单业务的单独演练,只有单链路全部演练通过,才会执行更大规模的多链路和全链路同时演练。
总之,生产系统的稳定性在任何时候,都是最高优先级要保证的,决不能因为演练导致系统异常或故障,这也是不被允许的。所以,一定要选择合适的时机,在有充分准备和预案的情况下实施各类验证工作。
Q.E.D.