概述
上一章,SrpingCloud 服务与消费 初识Eureka Consumer Ribbon_剑风偏冷的博客-CSDN博客 服务与消费 初识Eureka Consumer Ribbon。
在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。为了解决这样的问题,产生了断路器等一系列的服务保护机制。
“断路器” 本身是一种开关装置,用于在电路上的保护线路过载,当线路中有电器发生短路时,“断路器”能够及时切断故障电路,防止发生过载、发热甚至起火等严重后果。
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
针对上述问题,Spring Cloud Hystrix 实现了断路器、线程隔离等一系列服务保护功能。它也是基于 Netflix 的开源框架 Hystrix 实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。 Hystrix 具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
快速入门
启动如下工程
- eureka-server 工程:服务注册中心,端口为 1111。
- hello-server 工程:两个实例启动端口分别为8081 和 8082。
- ribbon-consumer 工程:使用 Ribbon 实现的服务消费者,端口为 9000。
在未加入熔断器之前,关闭 8081 的实例,发送 GET 请求到 http://localhost:9000/ribbon-consumer ,会报错。
下面开始引入 Spring Cloud Hystrix。
- 在 ribbon-consumer 工程的 pom.xml 中引入 hystrix 依赖。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.9.RELEASE</version> </dependency>
- 在 ribbon-consumer 工程的主类中使用 @EnableHystrix 注解开启断路器功能
@EnableHystrix @EnableDiscoveryClient @SpringBootApplication public class RibbonConsumerApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(RibbonConsumerApplication.class, args); } }
- 改造服务消费方式,新增 HelloService 类,注入 RestTemplate 实例。然后将在 ConsumerController 中对 RestTemplate 的使用迁移到 helloService 函数中,最后,在 helloService 函数上增加 @HystrixCommand 注解来指定回调方法:
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class HelloService { private final Logger logger = Logger.getLogger(getClass()); @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "helloFallback", commandKey = "helloKey") public String hello() { long start = System.currentTimeMillis(); String result = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody(); long end = System.currentTimeMillis(); logger.info("Spend time: " + (end - start)); return result; } public String helloFallback() { return "error"; } }
- 修改 ConsumerController 类,注入上面实现的 HelloService 实例,并在 helloConsumer 中进行调用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
public String helloConsumer() {
return helloService.helloService();
}
}
下面来验证一下通过断路器实现的服务回调逻辑,确保此时服务注册中心、两个 Hello-Service 以及 RIBBON-CONSUMER 均已启动,访问 http://localhost:9000/ribbon-consumer 可以轮询两个 HELLO-SERVICE 并返回一些文字信息。
此时继续断开 8081 的 HELLO-SERVICE,然后访问 http://localhost:9000/ribbon-consumer ,当轮询到 8081 的服务端时,输出内容为 error ,不再是之前的错误内容, Hystrix 的服务回调生效。
还可以模拟一下服务阻塞(长时间未响应)的情况。对 HELLO-SERVICE 的 /hello 接口做一些修改:
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() throws InterruptedException {
ServiceInstance instance = null;
String serviceId = registration.getServiceId();
List<ServiceInstance> instanceList = client.getInstances(serviceId);
if (instanceList != null && instanceList.size() > 0) {
int localPort = Integer.parseInt(environment.getProperty("local.server.port"));
for (ServiceInstance serviceInstance : instanceList) {
if (serviceInstance.getPort() == localPort) {
instance = serviceInstance;
break;
}
}
}
// 让处理线程等待几秒钟
int sleepTime = new Random().nextInt(3000);
logger.info("sleepTime:" + sleepTime);
Thread.sleep(sleepTime);
logger.info("/hello, host:" + instance.getHost() + ", service_id:" + instance.getServiceId());
return "Hello World";
}
通过 Thread.sleep() 函数可以让 /hello 接口的处理线程不是马上返回内容,而是在阻塞几秒之后才返回内容。由于 Hystrix 默认超时时间为 2000 毫秒,所以这里的随机数可以让处理过程有一定概率发生超时来触发断路器。
为了更精准低观察断路器的触发,在消费者调用函数中做一些时间记录:
@HystrixCommand(fallbackMethod = "helloFallback", commandKey = "helloKey")
public String hello() {
long start = System.currentTimeMillis();
String result = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
long end = System.currentTimeMillis();
logger.info("Spend time: " + (end - start));
return result;
}
重新启动 HELLO-SERVICE 和 RIBBON-CONSUMER 的实例,连续访问几次,可以观察到,当 RIBBON-CONSUMER 的控制台中输出的 Spend time 大于 2000 的时候,就会返回 error 。即服务消费者因调用的服务超时从而触发熔断请求,并调用回调逻辑返回结果。
最后
以上就是现代翅膀为你收集整理的Spring cloud 服务容错保护:Spring Cloud Hystrix的全部内容,希望文章能够帮你解决Spring cloud 服务容错保护:Spring Cloud Hystrix所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复