前言
在上一篇博客中为大家介绍了一下Eureka的用法(大聪明教你学Spring Cloud核心组件 | 第一篇:Eureka),看完后可能会有小伙伴寻思,那如果我在访问注册中心的某个方法时,这个方法不可用了怎么办?出现了连锁故障(雪崩效应)怎么办呢?那么这个时候就该断路器(Hystrix)闪亮登场了。
什么是断路器?
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免地会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。(以上内容来自百度)
当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个符合预期的、可处理的备选响应(Fallback),而不是长时间的等待或者抛出调用方无法处理的异常,这样就是保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
还是说点大白话吧,大家可以把断路器(Hystrix)理解成电路中“电闸”。
假如你想点亮一个灯泡A(把需要调用的服务比作灯泡),于是你对电流(把电流比作相应的请求)说:你们快去找灯泡A,给我点亮它!!
电流接收到你的命令后就背上行囊去点亮灯泡了,电流走到一半发现前面的电闸没有闭合(断路器生效了),电流走不过去了。
于是电流问道:大哥,前面过不去了吗?
电闸(断路器):灯泡A坏掉了,这条路走不通了,赶紧回去把这个消息告诉主人吧,就说此路不通(“此路不通”就是一个符合预期的、可处理的备选响应),等明天灯泡修好了就让你们过去了。
电流们就灰头土脸的回去告诉你:这条路走不通了,得换条路线了...
这时候你也就能知道这条路走不通,灯泡A点不亮了,于是你就可以赶紧去想别的办法,而不是傻 fu fu 的在原地等着灯泡A被点亮。
看了这个小故事大家是不是可以更简单的去理解断路器了呢?下面上代码,通过代码的方式为大家讲解一下断路器。
断路器
咱们把在上篇博客新建的项目重新打开(Eureka-Server服务注册中心、Eureka-Client客户端、Eureka-Consumer消费者),启动这些项目(这次咱们只需要启动一个客户端即可),启动后咱们可以看到Eureka-Server服务注册中心出现了两条注册信息,分别是Eureka-Client客户端和Eureka-Consumer消费者的注册信息。
这时候咱们访问一下消费者的地址,可以看到方法是可以正常被请求的。
接下来对消费者的代码进行一个小小的改造...
首先是在pom.xml文件中新增一个依赖
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
然后我们再把启动类稍稍修改一下
package com.consumer1.consumer1;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@RestController
@EnableEurekaClient
@SpringBootApplication
@EnableHystrix
public class Consumer1Application {
@Autowired
RestTemplate restTemplate;
public static void main(String[] args) {
SpringApplication.run(Consumer1Application.class, args);
}
/**
* 实例化RestTemplate
* @return
*/
@LoadBalanced
@Bean
public RestTemplate rest() {
return new RestTemplate();
}
/**
* 使用RestTemplate发起http请求,然后得到数据返回给前端
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "hiError")
@GetMapping(value = "/request")
@ResponseBody
public Map<String,Object> getUser(@RequestParam Integer id){
Map<String,Object> data = new HashMap<>();
RestTemplate restTemplate = rest();
data = restTemplate.getForObject("http://service-provider/getUser?id="+id,Map.class);
return data;
}
public Map<String,Object> hiError(Integer id) {
Map<String,Object> map = new HashMap<>();
map.put("id",id);
map.put("message","出错啦!!!");
return map;
}
}
我们改动的地方有三处,第一处就是启动类上新增了一个@EnableHystrix注解,开启了断路器;第二处是在getUser方法上新增了一个@HystrixCommand(fallbackMethod = "hiError")注解,这个注解的含义是对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法(就是当getUser方法访问出现异常时,去执行hiError熔断方法);第三处就是新增了一个hiError熔断方法。
需要注意的是,增加了@HystrixCommand(fallbackMethod = "XXX")的方法必须要和XXX方法的参数值相同且返回值类型一致,也就是说Hystrix的原方法和异常方法一定要完全相似
接下来我们模拟一下方法出现异常的情况,我们可以直接停止Eureka-Client客户端,此时我们再访问客户端地址时就会出现“无法访问此网站”
那么我们去访问消费者的地址,看看断路器有没有生效呢?
我们可以看到断路器生效了,由于客户端被我们停掉,导致了客户端去访问对应方法时出现了异常,从而执行了fallbackMethod熔断方法,返回了错误信息,而不是等待响应超时,这很好的控制了容器的线程阻塞。
结语
分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况,也就是服务雪崩效应。为了应对服务雪崩,一种常见的做法是手动服务降级,而Hystrix的出现,也给我们提供了另一种选择。
本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇
希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)
如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。
爱你所爱 行你所行 听从你心 无问东西