SpringCloud 熔断器 Hystrix 实现
背景:在实际的微服务系统中,是有众多的服务的,并且经常一个服务需要依赖另一个服务,例如大的电商系统中,切分的订单服务和支付的服务就会有互相依赖的情况,而如果其中一个服务挂掉了,另一个服务一直请求,是肯定拿不到返回的,这样长时间的请求就会堆积,造成服务的崩溃,这样造成整个系统的瘫痪,这样的架构相较于传统架构更加不稳定。而为了解决和应对这个问题就出现了熔断器Hystrix。
目录
(一)简介
Netflix的创造了一个调用的库Hystrix实现了熔断器图案。在微服务架构中,通常有多层服务调用。
较低级别的服务中的服务故障可能导致用户级联故障。当对特定服务的呼叫达到一定阈值时(Hystrix中的默认值为5秒内的20次故障),电路打开,不进行通话。在错误和开路的情况下,开发人员可以提供后备。
开放式电路会停止级联故障,并允许不必要的或失败的服务时间来愈合。回退可以是另一个Hystrix保护的调用,静态数据或一个正常的空值。回退可能被链接,所以第一个回退使得一些其他业务电话又回到静态数据。
(二)实现方式
springCloud中可以通过Ribbon和Feign两种方式实现熔断器,下面的依旧是基于之前的工程:eureka实现,Ribbon实现,feign实现
1.Ribbon
在之前Ribbon项目pom.xml中加入Hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在ribbon启动类上加上hystrix注解@EnableHystrix
package com.cloud.ribbonservice;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class RibbonserviceApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonserviceApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new RandomRule(); //这里配置策略,和配置文件对应
}
}
然后再调用方法上加上@HystrixCommand(fallbackMethod = "portFallback")注解,并加上断路之后的回调方法portFallback。
package com.cloud.ribbonservice.service;
import com.cloud.ribbonservice.controller.Controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@Service
public class RibbonService implements IRibbonService {
private static final Logger logger = LoggerFactory.getLogger(IRibbonService.class);
@Autowired
RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
@HystrixCommand(fallbackMethod = "portFallback")
public String port() {
this.loadBalancerClient.choose("SPRING-CLIENT-01");
String info = restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
return restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
}
private String portFallback()
{
logger.error("The service is Down");
System.err.println("The service is Down");
return "Service down";
}
}
这样基础就配置好了。
然后启动注册中心,SPRING-CLIENT-01服务,ribbon服务。
在浏览器或者postman中输入
http://localhost:11000/getInfo/hellol
关闭 SPRING-CLIENT-01服务,刷新浏览器
触发熔断成功。
2.使用feign的方式
1.在之前的feign工程中pom.xml中加入Hystrix依赖
2.feign的配置文件application.properties文件中打开Hystrix的开关 feign.hystrix.enabled=true
server.port = 10010
eureka.client.serviceUrl.defaultZone= http://localhost:12345/eureka/
spring.application.name= SPRING-FEIGN-SERVICE
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testmysql
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
feign.hystrix.enabled=true
在调用接口中加入一个熔断的类,这个类要实现之前调用其他服务的接口
package com.springcloudfeign.feign.service;
import org.springframework.stereotype.Component;
@Component
public class ErrorHystrix implements FeignDemoService {
@Override
public String getPort() {
return "sorry, it's error!";
}
@Override
public String getPortTwo() {
return "sorry, it's also error!";
}
}
然后再FeignDemoService接口注解中加入熔断回调的类的注解@FeignClient(value = "SPRING-CLIENT-01" ,fallback = ErrorHystrix.class)
package com.springcloudfeign.feign.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(value = "SPRING-CLIENT-01" ,fallback = ErrorHystrix.class)
public interface FeignDemoService {
@RequestMapping(value = "port" , method = RequestMethod.GET)
String getPort();
@RequestMapping(value = "getInfo/show" , method = RequestMethod.GET)
String getPortTwo();
}
这样就可以了。
SPRING-SERVICE-01没有关调用feign中接口的方式和返回是:
浏览器中输入:
http://localhost:10010/getInfoTwo
返回:
断开 SPRING-SERVICE-01服务,刷新浏览器返回:
说明熔断器调用成功。
以上代码github地址: 源码地址