zoukankan      html  css  js  c++  java
  • 第五章 服务容错保护: Spring Cloud Hystrix

      在微服务架构中, 存在着那么多的服务单元, 若一个单元出现故障, 就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。为了解决这样的问题, 产生了断路器等一系列的服务保护机制

      Spring Cloud Hystrix实现了断路器、 线程隔离等一系列服务保护功能。它也是基于Netflix的开源框架Hystrix实现的, 该框架的目标在于通过控制那些访问远程系统、 服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级、 服务熔断、 线程和信号隔离、 请求缓存、 请求合并以及服务监控等强大功能

    快速入门

    先部署按照以上架构图一些服务:

    • eureka-server工程: 服务注册中心, 端口为1111
    • hello-service工程: HELLO-SERVICE的服务单元, 两个实例启动端口分别为8081和 8082
    • ribbon-consume工程:使用Ribbon 实现的服务消费者, 端口为9000

    在未加入断路器之前, 关闭8081的实例, 发送GET请求到http://localhost:9000/ribbon-consumer, 可以获得输出,接下来开始引入Spring Cloud Hystrix

    在ribbon-consumer工程的pom.xml的dependency节点中引入springcloud-starter-hystrix依赖:

    1 <dependency> 
    2   <groupid>org.springframework.cloud</groupid> 
    3   <artifactid>spring-cloud-starter-hystrix</artifactid> 
    4 </dependency> 

    在ribbon-consumer工程的主类ConsumerApplication中使用@Enable­-CircuitBreaker注解开启断路器功能:

     1  @EnableCircuitBreaker 
     2  @EnableDiscoveryClient 
     3  @SpringBootApplication 
     4  public class ConsumerApplication { 
    5 @Bean 6 @LoadBalanced 7 RestTemplate restTemplate() { 8   return new RestTemplate(); 9 }
    10 public static void main(String[) args) { 11   SpringApplication.run(ConsumerApplication.class, args) 12 } 13 }

    注意:这里还可以使用 Spring Cloud 应用中的@SpringCloudApplication 注解来修饰应用主类, 该注解的具体定义如下所示。 可以看到, 该注解中包含了上述我们所引用的三个注解, 这也意味着—个 Spring Cloud 标准应用应包含服务发现以及断路器

    1 @Target ({ ElementType.TYPE}) 
    2 @Retention(RetentionPolicy.RUNTIME) 
    3 @Documented 
    4 @Inherited 
    5 @SpringBootApplication 
    6 @EnableDiscoveryClient 
    7 @EnableCircuitBreaker 
    8 public interface SpringCloudApplication {
    9 }

    改造服务消费方式, 新增 HelloService 类, 注入 RestTemplate 实例。 然后,将在 ConsumerController中对 RestTemplate 的使用迁移到 helloService函数中, 最后, 在 helloService 函数上增加@HystrixCornrnand 注解来指定回调方法:

     1 @Service 
     2 public class HelloService { 
    3   @Autowired 4   RestTemplate restTemplate;
    5   @HystrixCommand(fallbackMethod = "helloFallback") 6   public String helloService() { 7     return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody(); 9   }
    10   public String helloFallback () ( 11     return "error"; 12   } 13 }

    修改 ConsumerController 类, 注入上面实现的 HelloService 实例, 并在helloConsumer 中进行调用:

    1 @RestController 
    2 public class ConsumerController { 
    3   @Autowired 4   HelloService helloService;
    5   @RequestMapping(value = "/ribbon-consumer", method= RequestMethod.GET) 6   public String helloConsumer () { 7     return helloService.helloService(); 8   } 9 }

    重新启动之前关闭的 8081 端口的 Hello-Service, 确保此时服务注册中心、 两个 Hello-Service 以及 RIBBONCONSUMER 均已启动,访问 http://localhost:9000/ribbon-consumer 可以轮询两个 HELLO-SERV工CE 并返回一些文字信息。 此时我们继续断开 8081 的 HELLO-SERVICE,然后访问 http://localhost:9000/ribbon-consumer, 当轮询到 8081 服务端时,输出内容为 error, 不再是之前的错误内容,Hystrix 的服务回调生效。除了通过断开具体的服务实例来模拟某个节点无法访问的情况之外, 我们还可以模拟一下服务阻塞(长时间未响应)的情况。 我们对 HELLO-SERVICE 的/hello 接口做一些修改

     1 @RequestMapping(value = "/hello", method= RequestMethod.GET) 
     2 public String hello() throws Exception { 
     3   Serviceinstance instance= client.getLocalServiceinstance(); 
     4   //让处理线程等待几秒钟
     5   int sleepTime = new Random() . nextint (3000); 
     6   logger.info("sleepTime:" + sleepTime); 
     7   Thread.sleep{sleepTime); 
     8   logger.info("/hello, host:" + instance.getHost() + ", service id:" + 
     9   instance.getServiceid()); 
    10   return "Hello World";
    11 }
    }

    通过 Thread. sleep ()函数可让/hello 接口的处理线程不是马上返回内容,而是在阻塞几秒之后才返回内容。 由于 Hystrix 默认超时时间为 2000 毫秒, 所以这里采用了 0至3000 的随机数以让处理过程有一定概率发生超时来触发断路器。为了更精准地观察断路器
    的触发,在消费者调用函数中做一些时间记录,具体如下:

    1 @HystrixCommand(fallbackMethod = "helloFallback", commandKey = "helloKey") 
    2 public spring hello() { 
    3 long start = System.currentTimeMillis(); 
    4     //消费服务的逻辑
    5     ···
    6     long end= System.currentTimeMillis(); 
    7     logger.info("Spend time : "+ (end - start)); 
    8     return result.toString(); 
    9 }

    重新启动HELLO-SERVICE和RIBBON-CONSUMER的实例,连续访问http://localhost:9000/ribbon-consumer几次,我们可以观察到,当RIBBON-CONSUMER的控制台中输出的Spend time大于2000的时候,就会返回error, 即 服务消费者因调用的服务超时从而触发熔断请求, 并调用回调逻辑返回结果

  • 相关阅读:
    MySql--密码查看或修改
    javaweb学习--Servlet开发(一)
    javaweb学习--http协议
    Vue.js学习笔记(一)
    javascript事件处理
    javascript时间的相关操作
    代理模式(Proxy)
    单例模式(Singleton)
    ArrayBlockingQueue和LinkedBlockingQueue队列
    自增(++)和自减(--)运算符
  • 原文地址:https://www.cnblogs.com/hzzjj/p/10226770.html
Copyright © 2011-2022 走看看