一、雪崩效应

  在微服务架构中,由于服务和服务之间可以互相调用,一项工作的完成可能会依赖调用多个微服务模块,但由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪;再加上服务和服务之间的依赖性,瘫痪会迅速传播,给整个微服务系统造成严重的后果,这就是服务故障的“雪崩”效应。

服务雪崩效应形成的阶段

1、服务提供者不可用

  • 硬件故障。硬件损坏导致服务器主机宕机,或网络硬件故障造成服务提供者的不可访问。
  • 程序Bug
  • 缓存击穿。一般发生在缓存应用重启,所有缓存被清空时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端,造成服务提供者超负荷运行,引起服务不可用。
  • 用户大量请求

2、重试加大流量

  • 用户重试
  • 代码逻辑重试

3、服务调用者不可用

  • 同步等待造成资源耗尽。同步调用时,产生大量的等待线程占用系统资源。

二、服务雪崩的应对措施

针对造成服务雪崩的不同原因,可以采用不同的应对措施。

1、流量控制

  • 网关限流
  • 用户交互限流,例如:1.采用加载动画,提高用户的忍耐等待时间。2.提交按钮添加强制等待机制等。
  • 关闭重试

2、改进缓存模式

  • 缓存预加载
  • 同步改为异步刷新

3、服务自动扩容

  • AWS的auto scaling

4、服务调用者降级服务

  • 资源隔离。主要是对调用服务的线程池进行隔离。
  • 对依赖服务进行分类。根据具体业务,将依赖服务分为强依赖和弱依赖,强依赖服务不可用会导致当前业务中止,弱依赖服务不可用则不会。
  • 不可用服务的调用快速失败。一般通过 超时机制熔断器 和熔断后的 降级方法 来实现。

三、使用Hystrix预防服务雪崩

3.1、Hystrix的设计原则包括:

  • 资源隔离(不把鸡蛋放在一个篮子里)
  • 熔断器(及时止损)
  • 命令模式

资源隔离

  在一个高度服务化的系统中,一个业务逻辑经常需要依赖多个服务模块,例如下图左,查看商品详情业务需要依赖商品介绍、价格查询、商品评价三个服务模块,调用三个依赖服务会共享商品详情服务的线程池,如果其中某个模块不可用,线程池所有的线程都会因为等待响应而被阻塞,从而造成服务雪崩;

  Hystrix通过为每个依赖服务分配独立的线程池进行资源隔离,从而避免整个服务雪崩。如下图右,即便某个服务模块出错,只会导致分配给它的线程处于等待状态,而不影响其他依赖服务的调用。

  这样做带来的代价就是维护多个线程池需要额外的性能开销。

熔断器

  熔断器模式定义了熔断器打开关闭的转换。

  定义一个服务模块的健康状况=请求失败数/请求总数。

  熔断器工作原理,需要设定一个对于服务健康状况的阈值:

  1. 熔断器开关关闭,此时请求可以直接通过熔断器到达后台;
  2. 如果当前服务健康状况高于设定阈值,开关保持关闭,否则,开关转变为打开状态;
  3. 当熔断器开关打开时,请求被禁止通过熔断器,直接返回失败;
  4. 当熔断器开关打开一段时间(熔断器时间窗)后,自动进入半开状态,此时允许一个请求通过,当该请求调用成功,熔断器恢复关闭状态,若该请求失败,继续保持打开状态。

  熔断器的开关能保证服务调用者在调用服务异常的时候,快速返回结果,避免了造成客户端大量的同步等待以及大量无效请求影响系统吞吐量,并且熔断器能在一段时间后自动探测请求执行结果,从而有了恢复服务调用的可能。

命令模式

  Hystrix使用命令模式(继承自HystrixCommand类)来包裹具体的服务调用逻辑(run方法),并在命令模式中添加了服务调用失败后的降级逻辑(getFallback),同时也可以在Command的构造方法中定义当前服务线程池和熔断器的相关参数。

3.2、Hystrix的应对措施

  • 把每个依赖进行隔离,对依赖的调用全部包装成HystrixCommand或者HystrixObservableCommand
  • 对依赖的调用耗时设置阈值,超过阈值直接判定超时
  • 对每个依赖维护一个连接池,如果连接池满直接拒绝访问
  • 评估服务模块的健康状态,超过指定的阈值的话直接熔断处理,对依赖的请求访问直接fallback处理(由开发者自己实现)
  • 熔断生效后,时间窗后放出一个请求探测,决定是否要恢复服务
  • 近乎实时生效

3.3、Hystrix的内部处理逻辑

  1. 构建Hystrix的Command对象, 调用执行方法.
  2. Hystrix检查当前服务的熔断器开关是否开启, 若开启, 则执行降级服务getFallback方法.
  3. 若熔断器开关关闭, 则Hystrix检查当前服务的线程池是否能接收新的请求, 若超过线程池已满, 则执行降级服务getFallback方法.
  4. 若线程池接受请求, 则Hystrix开始执行服务调用具体逻辑run方法.
  5. 若服务执行失败, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
  6. 若服务执行超时, 则执行降级服务getFallback方法, 并将执行结果上报Metrics更新服务健康状况.
  7. 若服务执行成功, 返回正常结果.
  8. 若服务降级方法getFallback执行成功, 则返回降级结果.
  9. 若服务降级方法getFallback执行失败, 则抛出异常