scservers(五) 服务调用——安全,熔断,限流,降级

前言

服务调用是分布式系统基础,因为微服务的理念,不管粒度如何划分,系统功能间交互调用都会复杂起来,基础服务不管什么原因挂掉,容易就造成整个系统的不可用,这就是雪崩效应。原因是服务不可用,不断重试,造成服务调用者因为同步等待造成的资源耗尽也不可用,扩大后就造成所有服务都不可用了。

解决的策略基本有如下几种:

  • 限流

    按照漏斗模型,从前向后的限流

    • 用户交互限流
    • 网关限流
    • 服务调用关闭重试
  • 改进缓存
    • 缓存预加载
    • 同步改异步刷新
  • 服务自动扩容
    • 可以在docker 容器层面解决
  • 降级

    服务调用者降级服务

    • 资源即调用服务的线程池的隔离
    • 熔断,通过阈值设置失败的服务不再继续请求
    • 快速失败:通过超时机制, 熔断器 进行快速失败
    • 快速失败根据分类可以是应答错误也可以是应答缓存or默认数据

在上述策略中,微服务系统框架可以做的主要:

  • 可用情况下预防:超时处理,进行限流,资源隔离,分类,将不重要业务降级。
  • 不可用情况下直接隔离,熔断,降级等的操作。

而Springcloud 就为我们提供了Hystrix来保护我们的系统,可以将请求隔离,针对服务限流,当服务不可用时能够熔断并降级,防止级联故障。

Hystrix处理策略

当我们使用了Hystrix时,Hystrix将所有的外部调用都封装成一个HystrixCommand或者HystrixObservableCommand对象,这些外部调用将会在一个独立的线程中运行。我们可以将出现问题的服务通过熔断、降级等手段隔离开来,这样不影响整个系统的主业务。

  • 资源隔离

    通过线程池来实现资源隔离。通常在使用的时候我们会根据调用的远程服务划分出多个线程池。例如调用产品服务的 Command 放入 A 线程池,调用账户服务的 Command 放入 B 线程池。这样做的主要优点是运行环境被隔离开了。这样就算调用服务的代码存在 bug 或者由于其他原因导致自己所在线程池被耗尽时,不会对系统的其他服务造成影响。
  • 超时机制

    如果我们加入超时机制,例如2s,那么超过2s就会直接返回了,那么这样就在一定程度上可以抑制消费者资源耗尽的问题

  • 服务限流

    通过线程池+队列的方式,通过信号量的方式。比如商品评论比较慢,最大能同时处理10个线程,队列待处理5个,那么如果同时20个线程到达的话,其中就有5个线程被限流了,其中10个先被执行,另外5个在队列中

  • 服务熔断

    这个熔断可以理解为我们自己家里的电闸。

    当依赖的服务有大量超时时,在让新的请求去访问根本没有意义,只会无畏的消耗现有资源,比如我们设置了超时时间为1s,如果短时间内有大量请求在1s内都得不到响应,就意味着这个服务出现了异常,此时就没有必要再让其他的请求去访问这个服务了,这个时候就应该使用熔断器避免资源浪费

  • 服务降级

    有服务熔断,必然要有服务降级。

    所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。 例如:(备用接口/缓存/mock数据),这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景

Hystrix配置使用

  • hystrix & ribbon

    • 配置

      依赖:

       <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>

      属性设置:

    • 注解式使用

      • step1:使用注解 @EnableHystrix 启用豪猪断路器功能。
      • step2:在需要降级的接口上添加注解,并添加参数类型相同的降级函数,返回自定义信息

        @HystrixCommand(fallbackMethod = "ribbonfallback")
        @RequestMapping("/test/ribbon")
        public String testconfigrpc(String name) {
        return "RestTemplate+Ribbon get username <<==>> "+restTemplate.getForObject("http://center-demo/test/config/username",String.class);
        }
        public String ribbonfallback(String name) {
        return "ribbonFallback default name :ribbonFallback";
        }
    • 监控

      host:port/hystrix

      此处只是简单的单个应用监控,显然不适合大规模集群监控,后续的多个客户端监控放到后面专门的监控章节去讲吧。

  • hystrix & feign

    • 配置

      依赖

      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
      </dependency>

      属性配置

      feign: 
        hystrix:
      enabled: true
    • 注解式使用

      • step1: 引入注解 @EnableFeignClients,其已经包含启用断路器注解
      • step2:在ribbon中我们使用注解降级函数,在feign中我们使用注解降级类

        @FeignClient( name = "center-demo", path = "/test", decode404 = true,fallback = DemoFallbackFeign.class)
        public interface DemoFeignclient {  @GetMapping("/config")
        String selectconfigByName(@RequestParam String name);
        @GetMapping("/token/back")
        String gettokenback();
        }
        @Component
        public class DemoFallbackFeign implements DemoFeignclient {
        @Override
        public String selectconfigByName(String name) {
        // TODO Auto-generated method stub
        return "FeignFallbackName";
        }
        @Override
        public String gettokenback() {
        // TODO Auto-generated method stub
        return "FeignFallbackToken";
        }
        }
  • 源码

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>