zoukankan      html  css  js  c++  java
  • Spring Cloud Hystrix

     Spring Cloud Hystrix 

    https://blog.csdn.net/weixin_40470497/article/details/83957364

          Spring Cloud Hystrix 
    Hystrix 产生背景
    在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册 与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问 题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因 等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。

    举个例子,在一个电商网站中,我们可能会将系统拆分成用户、订单、库存、积分、评论等一系列服务单元。用户创建一个订单的时候,客户端将调用订单服务的创建订单接口,此时创建订单接口又会向库存服务来请求出货(判断是否有足够库存来出货)。此时若 库存服务因自身处理逻辑等原因造成响应缓慢,会直接导致创建订单服务的线程被挂起,以等待库存申请服务的响应,在漫长的等待之后用户会因为请求库存失败而得到创建订单失败的结果。如果在高并发情况之下,因这些挂起的线程在等待库存服务的响应而未能释放,使得后续到来的创建订单请求被阻塞,最终导致订单服务也不可用。

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

    断路器模式源于 Martin Fowler 的 Circuit Breaker 一文。“断路器”本身是一种开关装置,用于在电路上保护线路过载,当线路中有电器发生短路时,“断路器”能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。

    在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间用不释放,避免了故障在分布式系统中的蔓延。针对上述问题,SpringCloudHystrix实现了断路器、线程隔离等一系列服务保护功能。 它也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服 务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。接下来,我们就从一个简单示例开始对Spring Cloud Hystrix的学习与使用。

    快速入门
    在开始使用SpringCloud HyStrtix 实现断路器之前,我们先用之前实现的一些内容作为基础,构建一个如下图所示的服务调用关系。

    我们在这里需要启动的工程有如下一些。

    springcloud-eureka集群:服务注册中心,端口号分别为1111,2222,3333。
    springcloud-provider,springcloud-provider2两个服务提供者:两个实例的启动端口分别为8080,8081。
    springcloud-consumer服务的消费者:使用 Ribbon 实现的服务消费者,端口为8989。在未加入熔断器之前,关闭8081服务实例,发送 GET 请求到 http://localhost:8989/springcloud-consumer/testHystrix 可以在控制台看出:java.net.ConnectException: Connection refused: connect
    下面我们开始引入Spring Cloud Hystrix。
    在springcloud-consumer工程中的pom.xml中的 dependency 节点中引入 spring-cloud-starter-hystrix依赖:
    <!--熔断器-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    在springcloud-consumer工程的主类 SpringcloudConsumerApplication 中使用 @EnableCircuitBreaker 注解开启断路器功能:
    @EnableEurekaClient
    @EnableCircuitBreaker//该注解是开启断路器功能
    @SpringBootApplication
    public class SpringcloudConsumerApplication {
    public static void main(String[] args) {
    SpringApplication.run(SpringcloudConsumerApplication.class, args);
    }
    }
    改造服务的消费方式,新增HalloService 类,注入RestTemplate 实例。最后在queryAll函数上增加@HystrixCommand(fallbackMethod = "hellowFallback")注解来指定回调方法:
    @RestController
    public class HallowController {
    private final String url = "http://springcloud-provider";
    //使用restTemplate对rest接口进行调用 封装的对象
    //RestTemplate对象提供了多种便捷访问远程http服务的方法 是一种简单便捷的restful服务模板类,是spring提供的用于访问rest服务的客户端模板类
    @Autowired
    private RestTemplate restTemplate;

    //调用服务端的查询所有的服务
    @RequestMapping(value = "/testHystrix")
    @HystrixCommand(fallbackMethod = "hellowFallback",commandKey = "queryAllKey")//熔断器指定操作的方法
    public Object queryAll(){
    System.out.println("==========进入访问方法============");
    List forObject = restTemplate.getForObject(url+"/queryAll", List.class);
    return forObject;
    }

    //熔断器方法 建议把熔断方法放在service中去处理
    public String hellowFallback(){
    return "error";
    }
    }
    下面我们来验证一下通过断路器实现的服务回调逻辑,重新启动之前关闭的 8081 端口的服务提供者,确保测试注册中心、两个服务提供者一个服务消费者均已启动,访问 http://localhost:8989/springcloud-consumer/testHystrix ,当轮询到两个服务提供者并返回结果。此时我们继续断开 8081 的服务提供者,然后访问 http://localhost:8989/springcloud-consumer/testHystrix,当轮询到8081服务端时,输出的内容为 “error”,不再是之前的错误内容,Hystrix的服务回调生效。除了通过断开具体的服务实例来模拟某个节点无法访问的情况之外,我们还可以模拟一下服务阻塞(长时间未响应)的情况。我们对两个服务的提供者做一些修改,具体如下:
    //@GetMapping("/queryAll") 等于下面的注解
    @RequestMapping(value = "/queryAll",method = RequestMethod.GET,produces = "application/json; charset=utf-8")
    public Object queryAll(){
    List<User> users = userService.queryAll();
    //测试熔断 模拟服务阻塞的情况(长时间未响应)
    //让线程等待几秒钟
    int i = new Random().nextInt(3000);
    System.out.println("等待的时间为 :~~~~~~~~~~~~~~~~~"+i);
    try {
    Thread.sleep(i);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    return users;
    }
    通过Thread.sleep()函数可以让/queryAll 接口的处理线程不是马上返回内容,而是在阻塞几秒之后才返回内容。由于Hystrix默认的超时时间为2000毫秒,所以这里采用了0至3000的随机数以让处理过程有一定的概率发生超时时间来触发断路器。为了更精准地观察断路器的触发,在消费者调用函数中做一些事件记录,具体如下:
    private final String url = "http://springcloud-provider";

    //使用restTemplate对rest接口进行调用 封装的对象
    //RestTemplate对象提供了多种便捷访问远程http服务的方法 是一种简单便捷的restful服务模板类,是spring提供的用于访问rest服务的客户端模板类
    @Autowired
    private RestTemplate restTemplate;

    //调用服务端的查询所有的服务
    @RequestMapping(value = "/testHystrix") //,commandKey = "queryAllKey"
    @HystrixCommand(fallbackMethod = "hellowFallback",commandKey = "queryAllKey")//熔断器指定操作的方法
    public Object queryAll(){
    System.out.println("==========进入访问方法============");
    long l1 = System.currentTimeMillis();
    List forObject = restTemplate.getForObject(url+"/queryAll", List.class);
    long l2 = System.currentTimeMillis();
    System.out.println("调用服务的时间为:"+(l2-l1));
    return forObject;
    }

    //熔断器方法 建议把熔断方法放在service中去处理
    public String hellowFallback(){
    return "error";
    }
    重新启动服务的提供者,消费者的实例,连续访问 http://localhost:8989/springcloud-consumer/testHystrix 几次,我们可以观察到,地方消费者的控制台输出时间大于2000的时候,就会返回 “error”,即服务消费者因调用的服务超时从而触发熔断请求,并调用回调逻辑返回结果。
    ---------------------
    作者:狗蛋1024
    来源:CSDN
    原文:https://blog.csdn.net/weixin_40470497/article/details/83957364
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    【Leetcode_easy】720. Longest Word in Dictionary
    【Leetcode_easy】717. 1-bit and 2-bit Characters
    【Leetcode_easy】709. To Lower Case
    【Leetcode_easy】707. Design Linked List
    【Leetcode_easy】706. Design HashMap
    第38课 栈和队列的相互转化
    第7章 网络层协议(4)_IGMP协议
    第7章 网络层协议(3)_ARP协议
    第33课 双向循环链表的实现
    第32课 Linux内核链表剖析
  • 原文地址:https://www.cnblogs.com/handsome1013/p/10938418.html
Copyright © 2011-2022 走看看