服务的隔离、降级和熔断

上一篇 <<<后端服务的雪崩效应及解决思路
下一篇 >>>服务限流之计数器方式


1.服务隔离、降级和熔断的产生背景

tomcat底层都会共享一个线程池(自己创建的例外),当某个方法(服务)访问非常慢造成响应延迟,会造成大多数线程阻塞,导致整个线程池被占用甚至拖垮。
线程名定义:线程池名称+线程ID

2.服务隔离解决思路

2.1 线程池隔离

不同的http服务使用不同的线程池,当自己的资源用完,直接返回失败而不是占用别人的资源
优点:可提高并发性
缺点:增加CPU调度开销
使用场景:第三方应用或接口;并发量大

2.2 信号量隔离

原子计数器方式记录当前运行的线程数,超过则拒绝,不超过则+1,返回则-1
使用场景:内部应用或中间件;并发需求不大

区别:信号量可动态调整,但线程池不可以调整

3.服务降级

当服务不可用(服务正在等待、链接超时、网络延迟、服务器响应慢等),客户端一直等待时,调用fallback方法给客户端返回一个错误提示,不让客户端继续等待。
目的:提高用户体验,防止雪崩效应。

4.服务熔断

熔断和保险丝一样,当访问请求过多的时候,达到一个阈值(自己设置)就直接拒绝访问,可以保护当前服务,让服务不会被挂掉,需要和服务降级一起使用。


    
        com.netflix.hystrix
        hystrix-metrics-event-stream
        1.5.12
    
    
        com.netflix.hystrix
        hystrix-javanica
        1.5.12
    


public class OrderHystrixCommand extends HystrixCommand {
   @Autowired
   private MemberService memberService;

   public OrderHystrixCommand(MemberService memberService) {
      super(setter());
      this.memberService = memberService;
   }
   @Override
   protected JSONObject run() throws Exception {
      JSONObject member = memberService.getMember();
      System.out.println("当前线程名称:" + Thread.currentThread().getName() + ",订单服务调用会员服务:member:" + member);
      return member;
   }

   /**
    * 使用线程池方式解决隔离
    * @return
    */
   private static Setter setter() {
      // 服务分组
      HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("members");
      // 服务标识
      HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("member");
      // 线程池名称
      HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("member-pool");
      // #####################################################
      // 线程池配置 线程池大小为10,线程存活时间15秒 队列等待的阈值为100,超过100执行拒绝策略
      HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(10)
            .withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);
      // ########################################################
      // 命令属性配置Hystrix 开启超时
      HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
            // 采用线程池方式实现服务隔离
            .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
            // 禁止
            .withExecutionTimeoutEnabled(false);
      return HystrixCommand.Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
            .andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

   }

   /**
    * 服务降级
    * @return
    */
   @Override
   protected JSONObject getFallback() {
      // 如果Hystrix发生熔断,当前服务不可用,直接执行Fallback方法
      System.out.println("系统错误!");
      JSONObject jsonObject = new JSONObject();
      jsonObject.put("code", 500);
      jsonObject.put("msg", "系统错误!");
      return jsonObject;
   }
}

使用:
/**
 * 线程池方式解决
 * @return
 * @throws InterruptedException
 */
@RequestMapping("/orderIndexHystrix")
public Object orderIndexHystrix() throws InterruptedException {
   return new OrderHystrixCommand(memberService).execute();
}
信号量方式 和线程池方式也就setter方法不一致,其他的均一致
/**
 * 使用信号量解决隔离
 * @return
 */
private static Setter setter() {
   // 服务分组
   HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("members");
   // 命令属性配置 采用信号量模式
   HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
         .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
         // 使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数
         // 器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返 回成功后计数器-1。
         .withExecutionIsolationSemaphoreMaxConcurrentRequests(50);
   return HystrixCommand.Setter.withGroupKey(groupKey).andCommandPropertiesDefaults(commandProperties);
}

推荐阅读:
<<<高并发架构的整体思路
<<<一个网站访问慢的真正原因
<<<高并发情况下,接口的代码会存在哪些问题
<<<压缩静态资源减少带宽传输的方式
<<<动静分离架构模式
<<<缓存策略汇总
<<<后端服务的雪崩效应及解决思路
<<<服务限流之计数器方式
<<<服务限流之滑动窗口计数
<<<服务限流之令牌桶算法
<<<服务限流之漏桶算法
<<<漏桶算法和令牌桶算法的区别
<<<自定义封装限流算法
<<<应用级限流
<<<接入层限流

你可能感兴趣的:(服务的隔离、降级和熔断)