1.熔断
在微服务领域,熔断机制是从消费端保护微服务提供者的措施,当微服务的运行质量低于某个临界值时,启动熔断机制,暂停微服务调用一段时间,以保障后端的微服务不会因为持续过负荷而宕机。
2.降级
服务降级主要包括容错降级和屏蔽降级
屏蔽降级:1)throw null 不发起远程调用,直接返回空
2)throw exception 不发起远程调用,直接抛出指定异常
3)execute bean 不发起远程调用,直接执行本地模拟接口实现
服务降级是可逆操作,当系统压力恢复到一定值不需要降级服务时,要重新发起远程调用,服务状态改为正常
容错降级:非核心服务不可调用时,可以对故障服务做业务放通,保证主流程不受影响
1)RPC异常:通常指超时、消息解码异常、流控异常、系统拥塞保护异常等
2)Service异常 eg登录校验异常、数据库操作失败异常等
容错降级和屏蔽降级的区别在于:
1)触发条件不同:屏蔽降级往往是人工根据系统的运行,手动设置
容错降级是根据服务调用返回的结果,结合当前的服务级别,自动匹配触发
2)作用不同:容错降级是服务不可用时,让消费者执行业务放通
屏蔽降级主要目的是将原属于降级业务的资源调配出来供核心业务使用
3)调用机制不同,一个发起远程服务调用,一个只做本地调用
3.流量控制
当资源成为瓶颈时,服务框架需要对消费者做限流,启动流控保护机制。流量控制有多种策略,比较常用的有:针对访问速率的静态流控、针对资源占用的动态流控等。
在实践中,各种流量控制策略需要综合使用才能起到较好的效果。
动态流控
动态流控的最终目标是为了保命,并不是对流量或者访问速度做精确控制。当系统负载压力非常大时,系统进入过负载状态,可能是CPU、内存资源已经过载,也可能是应用进程内部的资源几乎耗尽,如果继续全量处理业务,可能会导致消息严重积压或者应用进程宕机。
动态流控检测的资源包括:
- CPU使用率。
- 内存使用率(对于Java,主要是JVM内存使用率)。
- 队列积压率。
静态流控
静态流控主要针对客户端访问速率进行控制,它通常根据服务质量等级协定(SLA)中约定的QPS做全局流量控制,例如计费服务的静态流控阈值为200 QPS,则无论集群有多少个计费服务实例,它们总的处理速率之和不能超过200 QPS。
由于微服务具备弹性伸缩、动态上线和下线等特性,因此集群中某个微服务实例的节点个数是动态变化的,采用传统的平均分配制无法做到精准的控制。
在实践中,比较成熟的集群静态流控策略是动态配额申请制,它的工作原理如下:
- 系统部署的时候,根据微服务节点数和静态流控QPS阈值,拿出一定比例的配额做初始分配,剩余的配额放在配额资源池中。
- 哪个微服务节点使用完了配额,就主动向服务注册中心申请配额。配额的申请策略:如果流控周期为T,则将周期T分成更小的周期T/N(N为经验值,默认值为10),当前的服务节点数为M个,则申请的配额为 (总QPS配额 - 已经分配的QPS配额)/M * T/N。
- 总的配额如果被申请完,则返回0配额给各个申请配额的服务节点,服务节点对新接入的请求消息进行流控。
用户自定义流控机制
不同的业务,存在不同的流控策略,例如基于微服务优先级的流控、基于节假日的流控、基于业务字段的流控等。底层的服务框架无法实现所有业务级的定制流控策略,因此,过于业务化的流控往往由业务通过自定义流控机制定制实现。
服务框架提供服务调用入口的拦截点和切面接口,由业务实现自定义流控。也可以提供基础的流控框架,供业务实现流控条件判断、流控执行策略等,简化业务的定制工作量。
4.隔离
由于大部分微服务采用同步接口调用,而且多个领域相关的微服务会部署在同一个进程中,很容易发生“雪崩效应”,即某个微服务提供者故障,导致调用该微服务的消费者、或者与故障微服务合设在同一个进程中的其它微服务发生级联故障,最终导致系统崩溃。
为了避免“雪崩效应”的发生,需要支持多种维度的依赖和故障隔离,以实现微服务的HA。
通信链路隔离
由于网络通信本身通常不是系统的瓶颈,因此大部分服务框架会采用多线程+单个通信链路的方式进行通信,原理如下所示:
多线程-单链路P2P通信模式
正如前面章节所述,由于微服务使用异步非阻塞通信,单个I/O线程可以同时并发处理多个链路的消息,而且网络读写都是非阻塞的,因此采用多线程+单链路的方式进行通信性能本身问题不大。但是从可靠性角度来看,只支持单链路本身又存在一些可靠性隐患,我们从下面的案例中看下问题所在。
某互联网基地微服务架构上线之后,发现在一些时段,经常有业务超时,超时的业务没有固定规律。经定位发现当有较多的批量内容同步、语音和视频类微服务调用时,系统的整体时延就增高了很多,而且存在较突出的时延毛刺。由于这些操作获取的消息码流往往达到数M到数十兆,微服务之间又采用单链路的方式进行P2P通信,导致大码流的传输影响了其它消息的读写效率,增大了微服务的响应时延。
问题定位出来之后,对微服务之间的通信机制做了优化,节点之间支持配置多链路,每个链路之间还可以实现不同策略的隔离,例如根据消息码流大小、根据微服务的优先级等策略,实现链路级的隔离,优化之后的微服务通信机制:
支持多链路隔离
调度资源隔离
微服务之间隔离
当多个微服务合设运行在同一个进程内部时,可以利用线程实现不同微服务之间的隔离。
对于核心微服务,发布的时候可以独占一个线程/线程池,对于非核心微服务,则可以共享同一个大的线程池,在实现微服务隔离的同时,避免线程过于膨胀:
图3-3 微服务之间故障隔离
假如非核心服务3发生故障,长时间阻塞线程池1的工作线程,其它与其共用线程池消息队列的非核心服务1和服务2只能在队列中排队等待,当服务3释放线程之后,排队的服务1和服务2可能已经超时,只能被丢弃掉,导致业务处理失败。
采用线程池隔离的核心服务1和服务2,由于各自独占线程池,拥有独立的消息队列,它的执行不受发生故障的非核心服务1影响,因此可以继续正常工作。通过独立线程池部署核心服务,可以防止故障扩散,保障核心服务的正常运行。
第三方依赖隔离
在微服务中通常会调用第三方中间件服务,例如分布式缓存服务、分布式消息队列、NoSQL服务等。只要调用第三方服务,就会涉及跨网络操作,由于客户端SDK API的封装,很多故障都是隐性的,因此,它的可靠性需要额外关注。
整体而言,第三方依赖隔离可以采用线程池 + 响应式编程(例如RxJava)的方式实现,它的原理如下所示:
1) 对第三方依赖进行分类,每种依赖对应一个独立的线程/线程池。
2) 微服务不直接调用第三方依赖的API,而是使用异步封装之后的API接口。
3) 异步调用第三方依赖API之后,获取Future对象。利用响应式编程框架,可以订阅后续的事件,接收响应,针对响应进行编程。
利用Netflix开源的hystrix + RxJava,可以快速实现第三方依赖的隔离,后续章节我们会详细介绍下如何使用。
进程级隔离
对于核心的微服务,例如商品购买、用户注册、计费等,可以采用独立部署的方式,实现高可用性。
容器隔离
微服务鼓励软件开发者将整个软件解耦为功能单一的服务,并且这些服务能够独立部署、升级和扩容。如果微服务抽象的足够好,那么微服务的这一优点将能够提升应用的敏捷性和自治理能力。
利用Docker容器部署微服务,可以带来如下几个优点:
- 高效:Docker容器的启动和停止不需要几分钟,只要几百毫秒就足够了。使用Docker部署微服务,微服务的启动和销毁速度非常快,在高压力时,可以实现秒级弹性伸缩。
- 高性能:Docker容器的性能接近裸的物理机,比VM平均高20%+。
- 隔离性:利用Docker,可以实现0.1 core的隔离。基于细粒度的资源隔离机制,可以实现高密度的部署微服务,同时实现它们之间的资源层隔离,保障微服务的可靠性。
- 可移植性:在基于虚拟机的解决方案中,应用的可移植性通常来说会受到云提供商所提供的虚拟机格式限制。如果应用程序需要部署到不同类型的虚拟机中,需要针对特定的虚拟机格式做镜像文件,新增很多额外的开发和测试工作量。Docker容器的设计理念是“一次编写,到处运行”,这可以使开发者避免上面这种限制。
基于Docker容器部署微服务,实现物理资源层隔离示意图如下所示:
图3-4 基于Docker容器的微服务隔离
VM隔离
除了Docker容器隔离,也可以使用VM对微服务进行故障隔离,相比于Docker容器,使用VM进行微服务隔离存在如下优势:
- 微服务的资源隔离性更好,CPU、内存、网络等可以实现完全的资源隔离。
- 对于已经完成硬件虚拟化的遗留系统,可以直接使用已有的VM,而不需要在VM中重新部署Docker容器。
开源:
1.Hystrix - Latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
2. Resilient HTTP - A smart HTTP client with super powers like fault tolerance, dynamic server discovery, auto balancing and reactive recovery, designed for distributed systems.
参考文献:
【1】http://www.infoq.com/cn/articles/micro-service-reliability-design