一、什么是稳定性
对于大型微服务系统,在错综复杂的服务逻辑各种交互情景下,面对各种未知的条件变化, 整体系统依旧能够正常平稳的提供服务,这便是稳定性。
二、为什么会不稳定?
系统稳定性影响因素分为两大类:一类是人为因素、另外一类是自然因素,常见故障如下
三、稳定性的衡量标准
SLA(Service Level Agreement)是服务级别协议的简写,是服务提供商与客户之间就服务质量达成的正式承诺
当我们谈论网站稳定性SLA时,我们通常是指一些关于网站的可用性和性能的度量。以下是一些常见的度量:
2、可用性:网站的正常运行时间与总时间的比率
例如
如果一个服务承诺99.99%的SLA(即4个9),意味着全年服务不可用的时间小于等于 53 分钟(从3个9提升到4个9是一个非常有挑战的过程)
>>> (86400*365*(1-0.9999))/60
52.55999999999421
四、稳定性如何建设
谁应该参与稳定性建设?
1、老板带头支持
2、落地需要开发、测试、运维、安全、产品都参与
3、主导方是:开发、测试、运维4、每个团队都背上一部分OKR指标,
这也是为何老板要支持的原因,因为和绩效考核相关
okr定制见后续内容
如何降低犯错率?
建立规范 1、开发规范 2、提测规范 3、测试规范 4、上线规范 5、复盘规范 规范定制见后续内容
如何提高稳定性意识?
规范有了,如何确保大家知晓? 1、设定合理的奖惩机制(例如没有遵守规范而引发的线上事故要严惩) 2、考试(规范和历史的线上事故整理成考试题,定期考核)
如何定责?
为避免扯蛋,应该引入第三方团队来定责。例如滴滴的星辰花团队,星辰花会撰写定责指南,并制定一些相关流程机制。
如何激励?
如果达成稳定性年度目标,也应该对这些团队进行适当表彰。
给多少钱,提前跟老板沟通好
要想做好稳定性工作,工具必不可少,没有工具,稳定性建设总是低效的,
强大的工具能回答如下 3 个关键问题:
1、我们能做什么? 2、我们能做到什么程度? 3、如何降低稳定性工作成本?
常见的工具和平台包括:
1、日志采集分析检索平台(例如滴滴的 Arius):不用人肉分析日志,可以帮我们迅速定位到问题的具体位置
2、监控告警平台(例如滴滴的 Odin Metrics): 不需要专人时刻盯着日志或大盘
3、分布式追踪系统(例如 Google 的 Dapper、滴滴的把脉平台):请求的整个链路可视化,问题定位会更有效率
4、自动化打包部署平台(例如滴滴的 One Experience):CICD平台
5、服务降级系统(例如滴滴的 SDS):一些故障能自动控制和恢复,而不需要人工去处理,提高系统的稳定性。
补充知识:微服务架构中的限流、熔断和服务降级:https://egonlin.com/?p=11206
6、预案平台(例如滴滴的 911 预案平台):预定义一些故障应对方案,发生相应故障时,能快速执行预设方案,
来尽可能降低故障对业务影响
7、根因定位平台(记录所有故障发生前所有系统变更事件):记录系统中的所有关键变更事件,当发生问题时,
能够进行历史查看和滚动复盘,
以确定问题的根本原因,提供更有效的故障排查支持。
8、放火平台(混沌测试):这是一种模拟故障的平台(类似于混沌测试中的故障注入),用于测试系统的弹性、
可恢复性和稳定性,以让团队更好地前期就预防疏漏的可能性,提前对系统的缺陷有所了解和改进。
混沌测试(Chaos Testing)
定义:
混沌测试是一种通过在生产环境中引入随机故障和异常情况来验证系统弹性和稳定性的测试方法。
它的目的是确保系统在面对不可预期的事件时仍能正常运行。
特点:
1、故障注入:随机地引入故障,如服务器崩溃、网络延迟、服务不可用等。
2、生产环境:通常在生产环境中进行,以真实地测试系统的应对能力。
3、目标:发现系统中的潜在弱点,提高系统的弹性和稳定性。
最后总结:
千万不要吝啬在工具方面的投入,很多开源框架可以拿来用或拿来参考,
工具和平台可以内部进行互通和联动,这样可以建成一站式的稳定性工作平台。
紧急预案是我们在故障发生时的行动指南,预案很重要,完备的预案能降低故障定位和止损的时间,提升协作效率。
完善的紧急预案能回答如下 4 个问题:
1、故障发生时我们该做什么?该通知谁 2、谁来指挥? 3、谁来决策? 4、我们如何善后?
紧急预案一般要包含如下内容:
1、故障可能涉及到多个团队,故障发生时应该通知哪些人或团队。 第一时间通知Leader、团队负责成员展开排查,同时通知客服、上游业务开发等可能的影响方 2、如何选出协调者,什么情况下该选出协调者。 介入的人多了反而解决问题效率会降低,一定要有一个协调者 3、协调者的职责有哪些。 协调者统筹全局,避免介入的同学在做重复工作,甚至需要持续跟客服、上有业务开发等影响方沟通 4、需要操作开关时,谁有权利决策。 对于排查问题和止损的同学来说,要操作某个开关,有可能还要去查代码看开关的名字是什么, 还有可能关掉一个功能需要操作多个开关,这些在紧急时刻都有可能由于慌乱而出错。 而且什么条件下才能操作开关,谁能决定应不应该操作开关,恐怕在当时很难去做最正确的事情, 而这一切,没错,都应该提前写到预案中!!! 5、常见故障以及对应的止损方式。 6、止损的原则是什么,什么是最重要的。善后方案谁来拍板。
有了目标,才能衡量稳定性建设工作的价值的、有没有达标、做的好不好。 稳定性建设工作的价值不仅需要团队所有成员认可,更重要的是需要老板的认可, 没有老板的认可,稳定性建设工作只是团队内部的“小打小闹”,难以去跨团队来体系化运作。 稳定性建设的目标主要用来回答如下 2 个问题: 1、稳定性工作的价值是什么? 2、稳定性工作如何考核? 稳定性建设工作的年度目标可以拿服务可用时长占比来定,也可以拿全年故障等级和次数来定, 像滴滴的星辰花团队会将故障等级分成了 P0 至 P5 六个等级, P0、P1、P2 属于重大事故,是需要消耗服务不可用时长的 (根据全年定的服务可用时长占比指标来计算出某个部门的全年服务不可用总时长), 一旦年底某个部门的全年服务不可用时长超过年初设定的阈值,就会有一定的处罚,并影响部门绩效
OKR:
O-------->Objective(目标) KR------> Key Results(关键成果)
1、不能凭空设定,必须先对公司内部的bug、事故平台(例如腾讯的tapd平台)进行分析、将问题进行归类统计,
例如得出 (1)软件bug引起的系统不可用时间,例如100分钟 (2)平台部署问题、集群架构问题导致的不可用时间,例如50分钟 (3)安全问题导致的不可用时间,例如40分钟 (4)产品需求不合理导致的不可用时间,例如10分钟 2、全年总计不可用时间为200分钟,然后根据各自的时间计算出各个问题的占比,然后依据该占比给各个团队设定指标 开发+测试共同承担: 100 / 200 = 50% -----------》52 * 50%--------》需要将不可用时间减少至26分钟 运维:50 / 200 = 25% -----------》52 * 25%--------》需要将不可用时间减少至13分钟 安全:40 / 200 = 20%-----------》52 * 20%--------》需要将不可用时间减少至10.4分钟 产品:10 / 200 = 5%-----------》52 * 5%--------》需要将不可用时间减少至2.6分钟
开发团队: Objective: 优化软件质量和开发流程,将由于软件bug引起的不可用时间从100分钟减少至15分钟 Key Results 1: 减少bug的数量:例如,每个季度需要减少20%的bug。 2: 提高自动化测试覆盖率:例如,达到90%以上的单元测试覆盖率,80%以上的集成测试覆盖率。 3: 减少部署失败的次数:例如,每个季度需要减少10%的部署失败。 测试团队: Objective: 加强软件测试力度和质量,将由于未发现的软件bug导致的不可用时间减少11分钟。 Key Results: 1、提升自动化测试覆盖率至90% ,更早地捕获可能的软件bug 2、强化对高风险模块的测试深度,提前发现难以检测的bug 3、提高测试报告的质量,更有效地帮助开发团队找到和解冑bug 运维团队: 他们的工作就是确保系统稳定高效的运行,所以提高系统的可用性、减少恢复时间和提高故障预防能力就成了他们的关键结果。 Objective: 提升服务稳定性和运维效率,将不可用时间减少至13分钟。 Key Results: 1、提升系统监控的覆盖率和效率,90%的故障能在1 minute内被检测到 2、建立并优化故障恢复流程,确保70%的故障能在5分钟内开始恢复 3、针对热点问题进行深度排查,减少重复故障发生的几率 安全团队: 他们的主要职责是保障系统和数据安全,所以减少安全事故、提升设备更新速度和完善安全制度就成了他们的关键结果。 Objective: 提高系统安全性,将由于安全问题导致的不可用时间减少至10.4分钟。 Key Results: 1、定期进行系统安全检查,及时修复安全漏洞 2、引进和优化安全工具和软件,提高安全防护和攻击检测率 3、提升全员的安全意识,减少由于人为操作不当引起的安全事件 产品团队:他们需要制定出符合用户需求且高质量的产品策略,所以完整的产品设计、提高需求质量和提高用户满意度就成了他们的关键结果。 Objective: 提高产品设计质量,将由于产品问题导致的不可用时间减少至2.6分钟。 Key Results: 1、提高需求质量:例如,每个季度减少10%的需求修改。 2、提高用户满意度:例如,每个季度用户满意度提升2%。 3、这些只是一些示例,具体比例可能需要根据不同组织的实际情况进行微调。如果您的公司有其它特别的要求或预期,可以针对性地制定相应指标。
编码规范:对外接口命名方式、统一异常父类、业务异常码规范、对外提供服务不可用是抛异常还是返回错误码、统一第三方库的版本、哪些场景必须使用内部公共库、埋点日志怎么打、提供统一的日志、监控切面实现等,编码规范除了能规范开发的编码行为、避免犯一些低级错误和踩一些重复的坑外,另一个好处是让新入职的同学能快速了解公司的编码原则,这点对编码快速上手很重要。
这里再重点说一下为什么要统一异常父类和业务异常码,例如虽然不同模块(这里的模块指的是能独立部署的项目)可能有不同的异常父类,比如订单模块的异常父类是 OrderException、交易支付模块的异常父类是 TradeException,而 OrderException 和 TradeException 的父类是 BizException(当然 BizException 是定义在一个通用共公共库中的),而我们也需要去统一异常码,比如 200 代表正确的返回码,异常的返回码是 6 位数字(前 3 位代表模块,后 3 位代表异常类型),有了统一的异常父类和异常码后,很多切面就都可以由公共库来做了,比如统一的监控、统一的出入口日志打印,统一的异常拦截,压测标识透传、特殊的字段埋点等,千万别小看这些,这些能在未来持续提升研发效率,降低稳定性工作成本。
公共库使用规范:为了能对通用功能进行定制化改造和封装,公司内部肯定会有一些公共库,例如日志库、HTTP 库、线程池库、监控埋点库等,这些库都“久经考验”,已经被证实是有效且可靠的,这些就应该强制使用,当然为了适应业务的发展,这些公共库也应该进行迭代和升级。
项目结构规范:为了贯彻标准的项目结构,一方面我们需要为各种类型项目通过“项目脚手架”来创建标准的项目结构原型,然后基于这个项目原型来进行开发,统一的项目结构一个最显著的好处是让开发能快速接手和了解项目,这种对于团队内维护多个项目很重要,人员能进行快速补位。
数据库规范:数据库连接资源堪比 CPU 资源,现在的应用都离不开数据库,而且通常数据库都属于核心资源,一旦数据库不可用,应用都没有太有效的止损手段,所以在数据库规范里,库名、表名、索引、字段、分库分表的一些规范都必须明确。
这里特别提一点,就是分表数量不要用 2 的幂(比如 1024 张表,很多人认为使用 2 的幂分表数在计算分表时用位运算会更快,但这个开销相比数据库操作其实可以忽略),而应该用质数(比如最接近 1024 的质数应该是 1019),采用质数分表数能让数据分的更均匀。
从大的方面来说,,稳定性技术策略包含:监控,冗余,限流,降级,回滚,重试。
监控可以分为以下几类来进行:
1、流量监控
流量监控包括:PV、 UV、 IP,热门页面,用户响应时间。 这些基本的流量指标就不在这里向大家详细说明了,如果有不太清楚的同学可以自己搜索一下。 在流量监控这块,我们需要注意的是:流量毛刺。流量毛刺往往代表了系统某个风险点或者异常情况的发生。 一个正常业务的流量趋势具备周期一致性特征。 比如说,一个业务每天的流量峰值一般在中午 12:00 和下午 18:00,那么这种峰值在没有特殊情况出现的前提下,应该会遵循该峰值时间规律。 那么流量毛刺是啥呢? 如下图所示:
从图中左侧部分可以看到,8 点钟有流量的突增,这时候我们需要确认为什么会有流量的突增。是业务的正常表现,还是有其他的异常流量进入。 从图中右侧部分可以看到,每条曲线代表了每一天的流量统计,红色曲线相对于其他几天的流量曲线在凌晨 3:00 和早上 8:00 的时候有明显的流量毛刺, 这时候我们就需要确认是什么因素造成流量数据的突变。 通过对于流量毛刺的观察,能够让我们及时了解业务中的风险,及时做好预警与准备。
2、业务监控
业务监控是根据业务属性来定义监控指标,可以用于判定整体业务的运转是否正常。 不同业务类型监控的指标肯定有所不同,比如电商场景、物流场景、游戏场景是完全不同的监控方向。 我们拿一个电商交易业务系统来举例,看看有哪些监控指标?大家可以参考着思考自己目前负责的业务指标。 举例来说针对一个电商交易系统我们可以监控的业务指标有: 1、用户下单监控:秒/分/时 用户下单统计 ; 2、用户支付监控:秒/分/时 用户支付统计; 3、用户退款情况:秒/分/时 用户退款统计; 4、商品库存状态:库存消耗/剩余统计; 5、业务 GMV 监控:业务整体销售额统计; 6、商家在线状态:监控商家在线状态; 7、促销运营监控:监控促销金额与数量。 在业务监控中,还需要重点关注业务转化漏斗概念。 业务转化漏斗,也称为销售漏斗或者营销漏斗,是对一个用户从第一次接触到最终转化成有效行动(如购买、注册、订阅等)的整个过程的模型分析。 监控业务转化漏斗的目的是查看在用户从知晓到最终行动的过程中,哪些步骤最可能导致用户流失。 通过跟踪用户在每个阶段的转化率,我们就能找出问题的关键环节,然后对此进行优化,从而提高整体的业务效果。
3、机器监控
机器监控需要关注的内容,应该是后台研发比较熟悉的部分。 主要监控方向包含下面几个部分:当然在 linux 系统中,也有各种常用指令,来进行该类数据的收集:top、free、ping、iostat、netstat。 对于 Java 系统来说,需要进行 JVM 层面的监控内容,比如说:gc 的情况,线程创建销毁情况,full gc 情况,内存不同模块使用情况等。 JVM 同样也提供了指令集,方便我们进行信息的查找:jstat、jps、stack、jmap、jhat 等。
4、日志记录
在日志的打印过程中,我们需要注意日志的打印规范,日志打印内容应该包含对于问题排查有益的信息,并且日志格式清晰,可解析性高。 日志一般是打印到服务器磁盘上面,但是由于单机磁盘能力有限,并且对于大型分布式系统来说需要整体收集不同服务器模块的日志, 进行统一分析,提高问题排查效率。这时候就需要一个集中式的日志中心。 日志中心的核心能力一般包含:获取日志、存储日志、展示日志、分析日志、报警服务。 相对比较简单的实现方式可以采用ELK快速搭建自己的日志中心。我们利用 kafka 将日志信息,进行异步广播,然后进行日志的解析,存储到 ES 检索系统中,利用 kibana 来进行日志的检索、查看等。进一步提升日志的有效管理。
回归测试:在修改或更新软件后,验证先前正常工作的功能是否仍然正常,确保新改动没有引入新错误。
冒烟测试, 是指在对一个新版本进行系统大规模的测试之前,先验证一下软件的基本功能是否实现,是否具备可测性。所以也叫可测性测试。
冒烟测试(Smoke Testing)的“冒烟”一词来源于硬件测试的术语。在硬件制造过程中,工程师会在设备首次通电时进行快速检查,确保没有明显的故障或冒烟现象。如果设备没有冒烟或发生其他显著问题,才会进行更详细的测试。这个概念引申到软件测试,指的是对新版本软件进行初步的基本功能测试,确保其基本可用性。
五、稳定性建设四个方向
稳定性建设工作重在预防,根据作者多年的工作经验,至少 6 成线上故障都可以在预防工作中消除,我们需要投入 45%的精力来做根基建设,所谓根基建设,就是把开发、测试、上线这三大流程做透!!下面列了几个关键点:
1、Code Review
CR 其实是一个很重要的环节,当一个开发整个编码和提测都可以自己闭环搞定时,时间一长就容易产生懈怠,这时候写隐患代码的几率会大大提高, CR 的过程并不是 diss 的过程,这个一定要在团队内拉齐,相反,CR 是一次很好的团队沟通和塑造自己影响力的机会。 分支合 master 必须要其他人 Review,大于等于 4 人日的项目需要进行小黑屋 CR,最好是作者自己讲解整个过程 CR 还可以让其他成员来检测该代码实现是否遵循了开发规范,毕竟“先污染后治理”的成本太高,记住,CR 一定是一个相互学习的过程。
2、设计评审:
garbage in garbage out 垃圾设计产生垃圾代码,垃圾设计的破坏性极强,所以必须要做设计评审 如果团队内部经常产出“糟糕设计”,设计评审就应该编码之前来做 如果团队成员专业能力和经验都还不错,那么我们允许你再编码之后再做设计评审(设计评审和 CR 可以放在一起做,先评审设计再进行 CR), 而且编码的过程其实也是设计的过程,可以规避提前设计而导致后续编码和设计不一致的问题。 设计评审的原则是,既要讲最终的设计方案,也要讲你淘汰的设计方案!
3、提测标准
写完代码就可以提测了?当然不是,至少得完成补充单元测试、完成自测、完成开发侧的联调、通过测试用例(如果 QA 提前给了测试用例的话)、 补充改动点和影响点(便于 QA 评估测试范围)、补充设计文档(对,现在滴滴的 QA 养成了读代码、看设计的习惯)这些步骤才能说可以提测了。 当然,提测标准理论上是 QA 同学来定义的。
4、测试流程
测试的全流程覆盖最好能做到全自动化,很多测试用例可以沉淀下来,用来做全流程回归,当然这需要系统支持。 我也见过太多由于 QA 没精力进行全流程回归而导致问题没有提前发现而产生的事故, 所以 测试的原则是尽可能自动化和全流程覆盖,让宝贵的人力资源投入到只能人工测试的环节。
5、上线流程
上线也是一个风险很高的操作,我们简单统计了 2019 年全年的上线次数,光我们团队负责的系统就上线了五百多次。 部署平台需要支持灰度发布、小流量发布,强制让开发在发布时观察线上大盘和日志,一旦有问题,能做到快速回滚(当然要关注回滚条件)。 我们这边的做法是先小流量集群灰度(我们把单量少的城市单独做了一套小流量集群),再线上灰度,确保哪怕出问题也能控制影响。
- 沙箱环境:高度隔离,用于高风险或早期阶段的开发和测试。
- 测试环境:模拟生产环境,用于常规功能和性能测试,通常更接近真实的生产环境。
俗话说养兵一日,用兵一时,平日的养兵其实也非常重要,这一方向我们需要投入 30% 的精力,需要我们做到如下几点:
1、人人参与:
稳定性涉及到的团队人人有责,所有人的 OKR 中都有稳定性建设的部分。 做 toC 研发的同学,都养成了带电脑回家的习惯,哪怕是加班到晚上 12 点,当然在外旅游也带着电脑,手机 24 小时保持畅通;
2、持续完善监控告警:
监控告警就是我们发现故障的“眼睛”和“耳朵”,监控告警需要持续的优化,因为 1、大多数监控告警都需要我们手动一个个配置,随着业务的不断迭代,会有很多新接口需要添加监控, 2、一些老的监控的阈值也需要不断调整(否则大量告警会让人麻木)
3、及时消灭线上小隐患:
平日发现的一些问题要及时消灭,很多线上事故在事前都有一定预兆,放任平时的一些小问题不管,到后面只会给未来埋上隐患。
4、跨团队联动:
稳定性肯定不是一个团队的事情,一些降级方案可能涉及多个团队的工作, 所以定期的跨团队的沟通会议是很有必要的,要大伙一起使劲才能把事情做好。
5、复盘机制:
对出过的线上事故一定要及时的进行复盘,通过复盘来发现 1、现有流程、机制是否有问题,让大伙不要踩重复的坑 2、看下次是否能预防此故障,或者是否能更快的定位和止损,不断完善我们的紧急预案。
6、会议机制:
稳定性周会、稳定性月会,我们通过各种定期的会议来总结一些阶段性进展和成果,拉齐大家认知, 这也是大伙日常稳定性工作露出的一个机会,所以非常重要。
我们通常都会忽视预案的作用,因为预案整理起来确实比较麻烦,预案也需要随着功能的迭代而不断更新,否则将很容易过时,而且预案在平日非故障期间也确实没有发挥作用的机会。但我们不得不承认紧急预案相当重要,特别是当我们去定位和止损一个比较复杂的线上问题时。
我们需要在预案的制定和演练上投入 15%的精力,可以从如下三个方面着手:
分场景制定和完善紧急预案:
1、如果我们还没有紧急预案,那第一步就是分类分场景整理下历史上经常发生的线上事故,例如 MySQL 故障预案、MQ 故障预案、发单接口故障预案等。 2、而且预案有可能会被多人查看,一定要清晰易懂,如果某些预案是有损的,需要把副作用也描述清楚。
通过放火平台来验证预案:
借助放火平台和服务降级系统,我们可以通过主动给主流程服务的非核心依赖注入故障,来验证系统在遇到非核心依赖发生故障时,核心服务是否仍旧有效, 如果某些预案无法做成系统自动的(比如某些预案有一定的风险或副作用),也可以在预发布环境来验证该预案是否能达到预期效果,防止真正故障发生时“手生”。 预案就是在这种不断演练过程中来优化和完善的,这样的预案才是动态的,才是活生生有效可靠的!
木桶效应-》一个木桶能装多少水取决于最短的那块板
在分布式系统中也是如此,我们需要摸到分布式系统中的这块“短木板”才能知道整个系统的吞吐量(容量), 如果我们没有这个值,老板问你明年单量要 Double,问你要预算,要规划你凭什么给?
最准确的容量预估方案就是——线上全链路压测
我们应该投入 10%的精力来摸容量、扩容量、水位预警等。 容量也相当重要,根据我的经验,线上有大约 10%的故障和容量有关,当遇到这种问题,最有效的解决方案就是扩容!
关于容量,我们在日常需要做到如下三点:
1、常态化的全链路压测: 线上全链路压测必须定期举行,特别的在有大促活动时,也需要提前进行一次。 因为随着业务的快速迭代,系统老的瓶颈可能消失,新的瓶颈可能出现, 所以之前的全链路压测的结果将失效,我们需要定期去摸这个线上环境的这个阈值。 2、定期进行扩容演练: 在滴滴内部,我们会定期进行弹性云扩容演练,这在紧急情况下很有用,我们就曾经遇到过弹性云扩容比修改阈值重新上线更快解决问题的 case。 3、多活建设: 我们知道多活主要是为了容灾,但其实多活实际上也从整体上增加了系统容量,所以也属于容量扩充的范畴,一旦某个机房遇到瓶颈, 我们可以分流到其他机房。当然多活建设需要一定成本,业务量大到一定程度才需要投入。
注意点:核心就是真实 1、用线上环境压测 2、用真实的用户数据测 3、用多台机器而部署单台来模拟用户并发请求 实现关键: 1、流量模拟 2、流量隔离(流量染色后实现:mock服务隔离关键服务,影子存储隔离存储) 3、流量将空与风险控制
六、总结
稳定性是一个大投入,做稳定性建设一定要结合公司的实际情况,量入为出,最合适的方案才是最好的方案。
结合咱们上述讨论的几点,我们可以画出稳定性建设的房子,如下,希望我们能像建筑师一样,给业务构建一套稳定、可扩展、性价比高的房子!!!