安全是产品的底座,是体验的基础,也是企业的一项核心竞争力。安全生产是一项系统性的工作,同时也是一件比较琐碎的事,需要做方方面面的考虑尽一切可能保障系统安全稳定运行。个人之前一直负责商品的稳定性工作,在这方面有比较多的经历和实践。
记得在18年的时候,我们做商品发布的组件化改造,当时正好碰上网站刚开始类目调整,一度连续3个月每个月都有故障,当时稳定性的压力很大。当然那也是一个契机,商品的稳定性建设也是从那个时候开始起步,然后逐步的完善。
安全生产建设大致上可以分为这三个阶段:
事前:故障预防,这里需要考虑的就是怎么通过预先的设计,最大限度的保证质量,降低风险,提升稳定性。
事中:应急处置,出了问题以后怎么处理,快恢手段有哪些,流程是什么。
事后:复盘改进,事后肯定要总结经验,举一反三解决同类的问题,不要被同一棵石头绊倒两次。
魏文王问扁鹊:你医术为啥这么好?
扁鹊说:我医术在我三兄弟里面算差的。最好的是我大哥,还没有任何症状就扑灭了,次好是我二哥,一点点轻微的症状就解决了。再次就是我,出了严重的问题我才开始医治,所以虽然我名满天下,但是我医术可比我的大哥二哥差得远啦。
做个类比,故障预防做的好的就是大哥,应急处置做的好的就是二哥,总结复盘做的好的就只能是扁鹊了。所以预防生产事故的发生是最重要的,也是最基础的。
架构设计
单个技术点在绝大部分时候都可以正常工作,但是当规模和复杂度达到一定程度的时候,失败其实无处不在。--《安全生产指南》
面向失败设计是应对安全生产最重要的方法论和指导方针。只有对各种失败场景有提前的布防才可以在出问题的时候有效应对。那么面向失败设计具体有哪些方式方法?
冗余设计避免单点
冗余最早是航空器常用的技术术语,飞机设计最显著的一个特点就是冗余,比如一般大型客机都会有两套甚至四套引擎,类似的还有两套基本同质的主副驾驶系统。为什么要这么设计,还有额外的成本,根本原因还是因为冗余设计可以在一套出现问题时另一套依然能保障系统正常运行。
在ICBU的场景中中美新容灾就是我们最主要的冗余设计,也是稳定性保障最核心的手段。商品是ICBU内第一个构建起中美异地容灾能力的业务场景,也正是因为有了这个能力帮助商品避免了不少的故障发生。
自动化运维管控
最好的处理是不需要处理。
编码开发
防御编程
批量容错:比如一个列表肯定不能因为某一行有问题而导致整个列表出不来。同样的同步任务也不能因为某一个任务异常而堵塞整个任务队列。所以需要对这些场景做好容错处理,其实还是在强调隔离风险。像商品的引擎同步任务、质量分计算任务都有独立的在线实时队列、实时重试队列、离线队列,目的就是为了不影响实时增量任务的正常执行。
简化代码
越简单东西的越可靠,越复杂的东西容错性越低。把简单的事情想复杂,把复杂的事情做简单。
少用同步锁:系统设计和编码尽量使用无锁实现,避免引起不必要的死锁问题。商品同样因为同步锁的原因出现过线上问题:
慎用线程池:其实跟同步锁类似,它是一个比较危险的操作,要做好测试和验证。
容灾防护
过载保护
过载保护是保障系统整体可用的重要手段之一,设计过载保护可以有效避免因为流量问题导致的系统不可用。所以我们的应用要具备自我防护的能力,web型应用接入流量清洗系统,服务型应用做好服务限流。
依赖降级
当前大部分的业务系统都比较复杂,特别是在分布式架构中,一个请求可能依赖多个系统支撑共同完成。调用链路中的任何一个节点都可能影响整体稳定性。所以一方面我们要保证自身服务的稳定性,另外一方面也要考虑在依赖服务出现问题后怎么保证主链路的可用。而依赖降级的前提是先理清依赖关系:
1、弱依赖就自动降级比如校验类的。
2、有一些是强依赖但可以异步处理的就降级后异步重试。
这其中超过95%都从来没有使用过。安全生产的建设就是这样,很多稳定性保障措施大部分时候都默默无闻,但是真正使用到的时候却都是关键的时刻。
监控预警
预警有效性
报警分层:另外可以根据监控场景对报警分层, 通过报警分层一定程度上可以兼顾召回和免打扰。重要的业务系统监控推送到核心预警群,非故障场景或者辅助定位的监控报警可以推送到其他普通预警群。同样也需要对报警通知方式做分层,比如成本率下跌2%可能是钉钉通知,下跌5%就需要电话通知。
测试回归
测试回归是质量保障很重要的一个环节。
单测是代码的照妖镜,我们会发现通常单测很难跑起来的往往就是代码设计不合理,耦合过多,单测可以帮助自己优化代码。
压测
新的服务上线前需要评估流量和性能情况,根据预估对服务进行压测以验证是否能够满足需求。同时整个链路能够支撑的QPS上限也需要通过压测确定,帮助我们合理的评估系统水位。
变更发布
回过头去分析会发现其实我们大部分问题都是变更引入的。商家技术部三规九条里有规定变更发布三原则 “可灰度、可监控、可回滚”。发布之前要做好发布计划和评审,检查是否满足这三个要素。
灰度分为功能灰度和发布灰度,功能灰度可以根据自己的团队情况设计。发布灰度首先从流程上建议增加小流量灰度环境,部分流量可以劫持到小流量环境,一些重大的问题可以在小流量环境提前发现。另外有条件的应用也建议分单元/分区域分开部署,短时间内模拟蓝绿部署,为容灾切流创造条件。
对于回滚,切记要做回滚验证,不要一股脑不暂停回滚完。因为之前碰到过一个案例,越回滚问题越严重,原因是当时的问题是远程缓存异常导致应用启动后出现数据异常,回滚重启后又导致已发布机器本地缓存失效放大了影响面。
故障预防是降低问题发生的概率,不是消灭问题。根据墨菲定律,只要存在可能就一定会发生。所以应急处置就是我们的兜底手段,是保证高可用性的重要一环。
容灾切流
出现故障我们首先需要做的不是定位原因,而是及时止血和快速恢复,而容灾切流往往是快恢的首选,时效性最高。
变更回滚
出现线上问题的时候,如果无法通过容灾切流的手段解决就要看一下有没有变更发布,判断如果可能跟变更有关就先回滚,重要的还是要做好回滚验证。
扩容重启
遇到突发流量、下游系统慢或本身资源容量不足都可能导致应用自身负载承压。在遇到资源瓶颈的时候快速扩容就是首选,这个时候考验的是系统的弹性能力。当前也有一些可行的方案:
KPA:基于流量/响应水平弹性,据称是CSE的替代者,猜测应该可以通过回放内存镜像来实现快速扩容。
当无法扩容的时候,重启是解决系统性能问题的另一个重要手段。据不科学的统计,90%的暂不明原因的性能问题可以通过重启暂时解决或一定程度上缓解。
限流降级
面对容量问题,除了扩容以外另一个选择就是限流和降级,可以根据重要程度优先对边缘应用和非核心场景做限制。
根据资源占用分层:像商品场景存在品量非常多的商家,这部分用户的某些操作可能对系统资源占用比较大,比较常见的就是引起数据热点或者数据偏移,而这些都是影响性能的因素,所以对资源占用大户也要有对应的处置措施,比如禁读禁写。
应急公告
如果短时间内无法恢复(参考1-5-10标准),那么就需要挂应急公告减少用户进线,每个业务场景的应急公告应该预先编制完成,在有需要时一键执行。
应急参考
应急处置的方案有很多,但是在处理线上问题时应该是有优先级的,先做什么其次做什么最后做什么。下图是整理的一份应急处置SOP参考文档。它不是操作手册,不能在出问题时再去查阅,而是每个人脑子里应该有这样一张图,对于线上应急处理流程烂熟于胸。
故障演练
所有的安全生产的措施都做好了,那么怎么验证它可以正常工作,故障演练是很好的手段。一方面可以检验稳定性保障措施的可用性,另外一方面也可以锻炼技术人员的应急处理能力。我看到过不止一次有人在处理故障时很紧张手都在抖。所以常态化的故障演练,特别是突袭演练可以让更多人参与到应急处理的过程中去,多实践才可以在真正发生问题的时候有条不紊。
归纳总结
出问题不可怕,重要的是分析这个过程中存在什么问题,流程机制上有什么漏洞,从而帮助我们做的更好。商品的稳定性措施就是在一次次面对各种问题的过程中总结和实践的。
经验分享
归纳总结是利己,避免自己再犯相同的错误。经验分享是利他,帮助别人不要掉到同样的坑里。另外技术风险防控平台里的大部分故障都是公开的,可以看看自己的应用有没有同样的风险。
风险意识:做好稳定性最重要的是要有风险意识,对生产保持敬畏之心。有风险意识才会在产研的全流程中关注稳定性的事情。比如新引入了一个依赖,就会考虑它异常了对于自己有什么影响,有没有容灾方案,能不能降级等等。另外有风险意识也会慢慢的形成一些良好的习惯,比如定期Review系统水位,我个人每天早上刚到公司做的第一件事就是看一下监控和报警。
减少损失:应急处置的第一原则是把损失降到最低,先恢复,再定位。
风险自愈:安全生产建设最终的目的应该是具备自愈能力,在系统出现问题时能够及时介入并自动恢复。
向人体学习,他拥有一套三重的免疫系统,这是一个百年的相当稳定的系统。-- 鲁肃
所以事前要有风险意识,事中要及时止损,事后查漏补缺构建风险自愈的能力。更重要的是秉持长期主义的精神,相信最终能够做好安全生产的事情。
推荐阅读
云上业务稳定性保障实践白皮书
随着客户云上业务规模越来越大,迭代速度越来越快,系统复杂度越来越高,如何保障云上业务稳定性这个话题也变的愈发重要。本文将从理论概念出发、围绕故障管理体系和变更管控体系展开,并根据各行业客户稳定性实践经验,对云上业务稳定性体系建设进行多角度的讲解。
点击阅读原文查看详情。