在微服务架构中,我们将系统拆分成了一个个的服务单元,各单元应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会出现因等待出现故障的依赖方响应而形成任务积压,线程资源无法释放,最终导致自身服务的瘫痪,进一步甚至出现故障的蔓延最终导致整个系统的瘫痪。如果这样的架构存在如此严重的隐患,那么相较传统架构就更加的不稳定。为了解决这样的问题,因此产生了断路器等一系列的服务保护机制。(引用地址:http://blog.didispace.com/spring-cloud-starter-dalston-4-1/)
新建一个SpringBoot工程,命名为hystrix。pom.xml添加如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
配置文件
server.port=8081
spring.application.name=hystrix
#指定服务注册中心的地址,这样才能将我们的应用注册到服务注册中心
eureka.client.serviceUrl.defaultZone: http://localhost:8080/eureka/
新建一个HystrixController
@RestController
public class HystrixController {
@HystrixCommand(fallbackMethod = "fallback")
@GetMapping("/hystrixTest")
public Object hystrixTest() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject("http://localhost:8083/msg",String.class);
}
private Object fallback() {
return "太拥挤了,请稍后再试!";
}
}
假设http://localhost:8083/msg为服务B的一个接口,内容如下:
@RestController
public class ProductController {
@GetMapping("/msg")
public String msg(){
return "这里是服务B的信息";
}
}
现在就可以测试啦
将hystrix和服务B启动
(1)
在浏览器中输入:http://localhost:8081/hystrixTest,
返回内容:这里是服务B的信息
(2)
把服务B停止,在浏览器中输入:http://localhost:8081/hystrixTest,
返回内容:太拥挤了,请稍后再试!
(3)
修改服务B的/msg接口,并启动服务B
@RestController
public class ProductController {
@GetMapping("/msg")
public String msg(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "这里是服务B的信息";
}
}
在浏览器中输入:http://localhost:8081/hystrixTest,
返回内容:太拥挤了,请稍后再试!
原因:由于服务B的/msg延时了两秒,而Hystrix的默认超时时间为1秒,解决方法如下
#(1)设置Hystrix全局的超时方法
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
#(2)为某个方法(hystrixTest)设置超时时间
hystrix.command.hystrixTest.execution.isolation.thread.timeoutInMilliseconds=5000
#(3)用于禁用Hystrix的超时时间
hystrix.command.default.execution.timeout.enabled: false
HystrixController还可以写成这样,
@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {
@GetMapping("/hystrixTest")
@HystrixCommand
public Object hystrixTest() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject("http://localhost:8083/msg",String.class);
}
private Object defaultFallback() {
return "【默认】太拥挤了,请稍后再试!";
}
}
这样就不需要在每个方法上都写一个fallbackMethod方法了
在Feign中使用Hystrix
在前面的hystrix基础上加上如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
配置文件加上如下配置
feign.hystrix.enabled=true
用法如下
@FeignClient(name = "product", fallback = ProductClientFallback.class)
public interface ProductClient {
@GetMapping("/msg")
public String msg();
}
@Component
public class ProductClientFallback implements ProductClient {
@Override
public String msg() {
return "服务错误";
}
}