稳定性

二、单服务稳定性



关键字:开关可控、单一职责、服务隔离、异常兜底、监控发现!



对于稳定性来说,抛开整体系统架构设计,单就每个业务域服务的稳定性也是非常的重要。



只有每个业务环节都稳如泰山,才可以保障整个稳定性。单服务的稳定可以从以下几个方面来进行:



1、禁用设计:应该提供控制具体功能是否开启可用的配置,在相应的功能服务出现故障时,快速下线局部功能,以保证整体服务的可用性;



2、必要的缓存:缓存是解决并发的利器,可以有效的提高系统的吞吐量。按照业务以及技术的纬度必要时可以增加多级缓存来保证其命中率;



3、接口无状态性:服务接口应该是无状态的,当前接口访问不应该依赖上层接口的状态逻辑;



4、接口单一职责性:对于核心功能的接口,不应该过多的耦合不属于它的功能。如果一个接口做的事情太多应做拆分,保证单接口的稳定性和快速响应;



5、第三方服务隔离性:任何依赖于第三方的服务(不论接口还是中间件等),都应该做到熔断和降级,不能有强耦合的依赖;



6、业务场景兜底方案:核心业务场景需要做到完整的兜底方法,从前端到后端都应该有兜底措施;



7、服务监控与及时响应:每个服务应该做好对应的监控工作,如有异常应及时响应,不应累积。



三、集群稳定性



关键字:系统架构、部署发布、限流熔断、监控体系、压测机制!



对于集群维度的稳定性来说,稳定性保障会更加复杂。单服务是局部,集群是全局。一个见微知著,一个高瞻远瞩。



1、合理的系统架构:合理的系统架构是稳定的基石;



2、小心的代码逻辑:代码时刻都要小心,多担心一点这里会不会有性能问题,那里会不会出现并发,代码就不会有多少问题;



3、优秀的集群部署:一台机器永远会有性能瓶颈,优秀的集群部署,可以将一台机器的稳定放大无限倍,是高并发与大流量的保障;



4、科学的限流熔断:高并发来临时,科学的限流和熔断是系统稳定的必要条件;



5、精细的监控体系:没有监控体系,你永远不会知道你的系统到底有多少隐藏的问题和坑,也很难知道瓶颈在哪里;



6、强悍的压测机制:压测是高并发稳定性的试金石,能提前预知高并发来临时,系统应该出现的模样;



7、胆小的开发人员:永远需要一群胆小的程序员,他们讨厌bug,害怕error,不放过每一个波动,不信任所有的依赖。



四、稳定性专项



专项指的是针对某些特定场景下的特定问题而梳理出对应的方案。下面是针对一些常见的稳定性专项的概述:



1、预案:分为定时预案和紧急预案,定时预案是大促常规操作对于一系列开关的编排,紧急预案是应对突发情况的特殊处理,都依赖于事前梳理;



2、预热:分为JIT代码预热和数据预热,阿里内部有专门的一个产品负责这块,通过存储线上的常态化流量或者热点流量进行回放来提前预热,



  起源于某年双十一零点的毛刺问题,原因是访问了数据库的冷数据rt增高导致的一系列上层限流,现在预热已经成了大促之前的一个必要流程。



3、强弱依赖:梳理强弱依赖是一个偏人肉的过程,但是非常重要,这是一个系统自查识别潜在风险点并为后续整理开关限流预案和根因分析的一个重要参考,



  阿里内部有一个强弱依赖检测的平台,通过对测试用例注入RPC调用的延迟或异常来观察链路的依赖变化,自动梳理出强弱依赖关系。



4、限流降级熔断:应对突发流量防止请求超出自身处理能力系统被击垮的必要手段;



5、监控告警&链路追踪:监控分为业务监控、系统监控和中间件监控和基础监控,作为线上问题发现和排查工具,重要性不言而喻。



五、稳定性建设



稳定性建设,就和基础技术建设一样,是一个长期迭代和不断调整的过程,业内常见的稳定性建设类型,主要有如下几种:



1、容量规划:个人感觉容量规划在大厂里也并没有做的很好,更多依赖的是业务方自己拍脑袋,然后全链路压测期间验证,不够就再加机器。



2、混沌工程:混沌工程是近几年比较火的名词,通过不断给系统找麻烦来验证并完善系统能力,阿里在这块花了很大的精力建设红蓝军对抗攻防,进行定期和不定期的演练,



  最后以打分的形式来给各个部门系统做排名,除了系统层面的故障演练外还有资金演练,篡改线上sql语句制造资损来测试业务监控纠错的能力,通过制造小错来避免大错。



  跳转门:混沌工程-初识



3、流量调度:通过metric秒级监控和聚类算法实时找出异常单机来降低RPC流量权重,提升集群整体吞吐能力减少异常请求。



4、容灾&异地多活:起源于15年某施工队将光纤挖断带来的支付宝故障,由此出来的三地五中心和单元化架构,异地多活本身的成本比较高,



  然后又存在数据同步的延时问题和切流带来的脏数据问题,对于业务和技术都有比较高的要求。常见的容灾有如下几种:



  1)缓存挂掉,集群重启缓存预热如何处理?本地缓存,多级缓存是否可以替代?



  2)分布式锁,是否有开关一键切换?比如:ZK/ETCD编写的分布式锁;



  3)大促峰值流量,如何防止外部ddos攻击?如何识别流量类型?



  4)资源隔离:资源隔离,服务分组,流量隔离;



  5)高可用思想:避免单点设计!



  6)容错:容错上游,防御下游。容错主要需要注意如下几点:



    6-1:外部依赖的地方都要做熔断,避免雪崩;



   6-2:对于依赖我们的上游要限流,防止上游突发流量超过自己系统能够扛住的最大QPS;



   6-3:对于下游既要评估好接口超时时间,防止下游接口超时异常导致自己系统被拖累;



   6-4:下游的接口要考虑各种异常情况,需要考虑中间状态,通过引入柔性事务,确保数据最终一致。



5、异地多活



异地多活的本质,是数据中心架构的演进。



1)演进:单机房——双机房——异地灾备——异地多活;



2)定义:分多个地域、多个数据中心运行线上的业务,并且每个IDC均提供在线服务;



3)优点:弹性扩展能力、流量就近接入、灵活调度、提升可用性与用户体验、容灾;



4)步骤:



  4-1:基础设施:机房之间专线互联,保证网络质量稳定;



  4-2:持久存储:一主三从,主IDC同步复制,异地IDC异步复制;



  4-3:中间件:DB、MQ、分布式存储;



  4-4:应用部署:根据应用域划分,不同应用部署在不同地域,保持亲缘性;



  4-5:流量接入与调度:网络协议兼容,DNS,动态调度用户就近访问;



  4-6:监控与运维保障:专线实时监控,确保发生故障时可以触发Failover(失效备援)和流量调度。



六、稳定性思考



关键字:阶段工作、角色转变!



稳定性建设是一个演进的阶段性过程,主要分为三个阶段:



1、发现问题解决问题:当问题较多时候就很被动,很多时候我们通过不断完善监控来确保我们来快速定位问题,但仍处于被动的一方;



2、主动寻找问题:混沌工程、破坏性测试、极限压测、红蓝对抗等手段,一方作为创造问题方不断挑战系统极限,另一方见招拆招快速修复。



3、角色转变:这个过程中会积累很多处理问题的经验,不断完善系统健壮性,争取在用户发现问题前消灭于萌芽中。角色转变,变被动为主动



https://www.cnblogs.com/imyalost/p/12952930.html

https://www.infoq.cn/article/z4ssMNkS3w4EbbusTYO1



「JVM-SANDBOX」致力于为服务端稳定性领域提供实时无侵入的字节码增强框架。



https://developer.aliyun.com/article/710863



7.1、依赖治理实践
依赖治理的一些基础概念



依赖模型分为关系、流量、强弱,实际的使用场景有:



依赖关系:线上故障根源查找、系统降级、依赖容量、依赖告警、代码影响范围、系统发布顺序、循环依赖等。
依赖流量:分配流量比、优化调用量、保护大流量。
依赖强弱:线上开关演练,系统改造评估。
关系数据可以通过人工梳理、代码扫描、线上端口扫描的方式获取。流量数据可以通过分析调用日志的方式获取。强弱数据则必须通过故障模拟才能拿到。故障模拟分为调用屏蔽和调用延迟两种情况,分别代表服务不可用和服务响应慢的情况。依赖的级别分为应用级依赖和接口方法级依赖,两个级别的故障模拟手段完全不同,下面分开来描述。



应用级别强弱依赖检测



应用级别故障模拟比较做法有几种,即:修改代码,写开关,远程调试,填错服务的配置项。这几种方式对配置人要求相对较高,并且对应用代码有一定的侵入性,所以没有被我们采用。Linux有一些原生的命令(如iptables、tc)默认就有流量流控功能,我们就是通过控制linux命令来达到模拟故障的效果。命令举例:



iptables -A INPUT -s xxx.xxx.xxx.111 -j DROP
上面的命令表示:当前主机屏蔽掉来自xxx.xxx.xxx.11的网络包。



tc qdisc del dev eth0 root
tc qdisc add dev eth0 root handle 1: prio
tc qdisc add dev eth0 parent 1:1 handle 10: netem delay 6000ms
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip dst xxx.xxx.xxx.111/32 flowid 1:1
命令表示:在网卡eth0上面设置规则,对xxx.xxx.xxx.111的网络包进行延迟,延迟的时间是6000ms。



接口级别强弱依赖检测
理想情况下,我们希望确定任意一次远程方法调用的强弱,确定到接口方法级别的强弱数据。要想达到这个目的,就只能在通信框架和一些基础设施上面做文章。基于这个思路,我们设计了接口级别强弱依赖检测的方案。方案如下:



过滤规则配置组件(服务器端)
过滤规则配置组件提供一个web界面给用户,接受用户配置的屏蔽指令和测试机器IP信息,并把配置信息更新到配置中心组件中去。
配置的规则举例:



client|throw|xxx.ItemReadService:1.0.0.daily@queryItemById~lQA|java.lang.Exception
client|wait|xxx.ItemReadService:1.0.0.daily@queryItemById~lQA|4000
上面的规则分别表示在客户端发起对远程接口xxx.ItemReadService:1.0.0.daily的queryItemById~lQA调用时,在客户端模拟一次异常或延迟4000毫秒后调用。



配置中心组件



配置中心组件的主要作用是接受客户端(过滤规则配置组件)发来的配置信息,持久化配置信息到存储介质中,并实时把配置信息实时推送到配置中心的所有客户端(即每一个故障模拟组件)。此部分功能通过中间件开源产品Diamond实现。



分布式服务调用组件



发生RPC调用时,会传递一些调用信息,如:RPC发起者的IP、当前的方法名称、下一级调用的方法名称。



故障模拟组件



故障模拟组件是一个插件,可以被服务调用组件(HSF)加载。插件可以接受配置中心推送的配置信息,在服务调用组件发生调用前都比对一下据配置信息的内容,当RPC发起者的IP、调用方法都合条件的时候,发生故障模拟行为,从而达到故障模拟的效果。



7.2、容量规划实践
线上容量规划最重要的一个步骤为线上压力测试,通过线上压力测试来得知系统的服务能力,同时暴露一些在高压力场景下才能出现的隐藏系统问题。我们搭建了自己的线上自动压测平台来完成这一工作,线上自动压测归纳起来主要包含4种模式:模拟请求、复制请求、请求引流转发以及修改负载均衡权重。



模拟请求



完全的假请求,可以通过代码或者采用工具进行模拟,常用到的工具有http_load、webbench、apache ab、jmeter、siege等。模拟请求有一个很明显的问题,即如何处理“写请求”?一方面由于“写请求”的场景不大好模拟(一般需要登录),另一方面“写请求”将要面临如何处理一致性场景和脏数据等。模拟请求方式的压测结果准确性我们认为是最低的。



复制请求



可以看成是半真实的假请求。说它半真实,因为它是由复制真实请求而产生。说它是假请求,因为即使复制的真实请求,它的响应是需要被特殊处理的,不能再返回给调用方(自从它被复制的那一刻,它就已经走上了不真实的轨道)。复制请求同样可以通过代码实现(比如我们有通过btrace去复制对服务的调用), 此外也有一些比较好用的工具:比如tcpcopy等。如果想在nginx上做请求复制,可以通过nginx的nginx post_action来实现。“复制请求”模式被压测的那台机器是不能提供服务的,这将是一个额外的成本,此外复制请求模式的压测结果准确性也会由于它的半真实而打上折扣。



请求引流转发



完全真实的压测模型,常用于集群式部署的web环境当中。我们对于apache和nginx的系统基本上都采取这种方式来做线上压力测试。用到的方式主要通过:apache 的mod_jk和 mod_proxy模块;nginx的proxy以及upstream等。这种方式压测的结果准确性高,唯一的不足是这种方式依赖系统流量,如果系统流量很低,就算是将所有的流量引到一台机器上面,仍不足以达到压测目的。请求引流转发模式的压测结果准确性高。



修改负载均衡权重



同样为完全真实的压测模型,可以用于集群部署的web环境中,也可用于集群部署的服务类系统。在web环境中我们通过修改F5或者LVS的机器负载均衡权重来使得流量更多的倾斜到其中的某一台后者某几台机器上;对于服务类系统,我们通过修改服务注册中心的机器负载均衡权重来使得服务的调用更多分配到某一台或者某几台机器上。修改负载均衡权重式的压测结果准确性高。



系统的服务能力我们定义为“系统能力”。在系统机器配置都差不多的情况下,系统能力等于线上压力测试获取的单台服务能力乘以机器数。在得知了系统能力之后,接下来我们需要知道自己的系统跑在怎么样的一个容量水位下,从而指导我们做一些决策,是该加机器了?还是该下掉一些多余的机器?通常系统的调用都有相关日志记录,通过分析系统的日志等方式获取系统一天当中最大的调用频率(以分钟为单位),我们定义为系统负荷;当前一分钟的调用频率我们定义为当前负荷。计算系统负荷可以先把相关日志传到hdfs,通过离线hadoop任务分析;计算当前负荷我们采用storm的流式计算框架来进行实时的统计。



水位公式



系统水位 = 系统负荷 / 系统能力;当前水位 = 当前负荷 / 系统能力。



水位标准



单机房(70%);双机放(40%);三机房(60%)。
单机房一般都是不太重要的系统,我们可以压榨下性能;
双机房需要保障在一个机房完全挂掉的情况下另一个机房能够撑得住挂掉机房的流量;
三机房同样需要考虑挂掉一个机房的场景后剩下两个机房能够撑得住挂掉机房的流量。



机器公式



理论机器数 = (实际机器数 * 系统负荷 * 系统水位)/ (系统能力 * 水位标准)
机器增减 = 理论机器数 – 实际机器数



7.3、稳定性平台双11准备与优化
强弱依赖检测面临的最大挑战就是如何使用户使用方便,接入成本最小,主要需要解决下面两件事情:



如何复用现有的测试用例?
我们开发一个注解包,里面封装与CSP的交互协议。服务器端完成测试环境的管理,测试用例端专注应用系统的验证。这是一种测试平台无关的方式,不需要修改现有的测试代码,只需要配置注解的方式就使测试用例支持了强弱依赖验证的功能。
如何解决故障模拟组件覆盖不全导致的验证局限?
依赖调用一定存在client和server端,很有可能出现一端没有安装故障模拟组件的情况。为此,我们改造了故障描述协议,增加了client和server两种模式,只要client或server有一方安装了故障模拟组件就可以完成强弱依赖校验。



https://developer.aliyun.com/article/25419



混沌工程正是这样一套通过在生产分布式系统上进行实验,主动找出系统中的脆弱环节的方法学。这种通过实证的验证方法显然可以为我们打造更具弹性的系统,同时让我们更透彻的掌握系统运行时的各种行为规律。我们能够在不断打造更具弹性(弹性:系统应对故障、从故障中恢复的能力)系统的同时,树立运行高可用分布式系统的信心。



实践混沌工程可以简单如在生产环境中运行 kill -9 来模拟一个服务节点的突然宕机,也可以复杂到在线上挑选一小部分(但足够代表性)的流量,按一定规则或频率自动运行一系列实验。



Netflix 最早系统化地提出了混沌工程的概念,并出版了混沌工程领域内的首部书籍《混沌工程:Netflix 系统稳定性之道》[1],在本书中提出了混沌工程成熟度模型与应用度模型,并总结了五条高级原则,对于混沌工程的发展具有指导性意义。另外 Netflix 开源了其混沌工程项目 - Chaos Monkey[3]。
阿里巴巴是国内较早开始探索混沌工程并做出开源的公司,其开源项目 ChaosBlade[4]可以结合阿里云进行 chaos 实验。
PingCap 作为国内优秀的数据库领域开源公司,其在混沌工程领域一直有投入,并在最近开源了内部混沌工程实践平台 - Chaos Mesh[5]。
Gremlin 为一家混沌工程商业化公司,该公司提供了一个混沌工程实验平台,通过将其 agent 安装在云主机上触发故障。同时提出了 chaos gameday[2] 的概念。



https://www.6aiq.com/article/1588002031057



https://zhuanlan.zhihu.com/p/150377297



https://dy.163.com/article/D8GHG2760511D3QS.html



https://www.cnblogs.com/ceshi2016/p/11684492.html



https://cloud.tencent.com/developer/news/620931



https://102.alibaba.com/detail?id=302



https://github.com/chaosblade-io/chaosblade
https://github.com/chaos-mesh/chaos-mesh
https://dzone.com/articles/chaos-gamedays-a-step-by-step-guide-to-chaos



https://zhuanlan.zhihu.com/p/79780598


Category web