一、简介 http://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients
Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。 在微服务架构中,一个请求需要调用多个服务是非常常见的。
hystrix主要是用来防止服务雪崩效应的。
服务雪崩效应:是一种因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程。
举例:A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的不可用,引起B的不可用,并将不可用逐渐放大C和D时, 服务雪崩就形成了。
如图一个API可能同时调用多个微服务。
较低级别的服务中的服务故障可能导致服务级联故障。当对特定服务的调用达到一定阈值时(Hystrix中的默认值为5秒内的20次故障),断路器打开。
断路打开后,回退可以是另一个Hystrix保护的调用,静态数据或一个正常的空值。
二、Ribbon+Hystrix
依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> application.properties
spring.application.name=hello-consumer-ribbon-hystrix server.port=8041
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/ HelloService
package cn.saytime.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate;
@Service public class HelloService {
@Autowired private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "fallback") public String hello (String name) { return restTemplate.getForEntity("http://HELLO-SERVICE/hello?name=" + name, String.class).getBody(); }
public String fallback (String name) { return "hello, hystrix === fail name:" + name; }
} application
package cn.saytime;
import cn.saytime.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; 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.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;
@SpringBootApplication @EnableDiscoveryClient @EnableHystrix @RestController public class HelloConsumerRibbonHystrixApplication {
public static void main(String[] args) { SpringApplication.run(HelloConsumerRibbonHystrixApplication.class, args); }
@Bean @LoadBalanced public RestTemplate restTemplate () { return new RestTemplate(); }
@Autowired private HelloService helloService;
@RequestMapping("hello") public String hello (String name) { return helloService.hello(name); }
} 测试:
启动eureka-server:8001, hello-service:8012,8002,hello-consumer-ribbon-hystrix:8041
访问:http://localhost:8041/hello?name=ribbon_hystrix
hello, ribbon_hystrix 访问正常,接下来我们把hello-service服务停了,再次访问:
hello, hystrix === fail name:ribbon_hystrix 成功触发熔断。
然后我们再次启动hello-service服务,然后访问:
hello, ribbon_hystrix 没有触发熔断,正常。
同样我们测试访问超时触发熔断的情况,我们在hello-service接口加上线程等待1s
@RequestMapping("hello") public String hello (String name) throws InterruptedException { Thread.sleep(1000); System.out.println("hello, " + name); return "hello, " + name; } 访问,发现同样触发熔断,因为hystrix默认超时1s触发熔断,我们可以通过修改属性来改变超时时间。
这里我们把超时时间修改为2s
@HystrixCommand(fallbackMethod = "fallback", commandProperties = { @HystrixProperty(name= "execution.isolation.thread.timeoutInMilliseconds", value="2000") }) public String hello (String name) { return restTemplate.getForEntity("http://HELLO-SERVICE/hello?name=" + name, String.class).getBody(); } 再次访问,发现没有触发熔断。
三、Feign With Hystrix Feign默认是自带Hystrix的,所以依赖Jar的时候无需再依赖hystrix
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> application.properties
spring.application.name=hello-consumer-feign-hystrix server.port=8051
eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
## 开启hystrix feign.hystrix.enabled=true
## hystrix熔断触发默认超时时间 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000 HelloService
package cn.saytime.service;
import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "hello-service", fallback = HelloServiceFallBack.class) public interface HelloService {
@RequestMapping("hello") String hello(@RequestParam(value = "name") String name) ; } 熔断触发类HelloServiceFallBack
package cn.saytime.service;
import org.springframework.stereotype.Component;
@Component public class HelloServiceFallBack implements HelloService{
@Override public String hello(String name) { return "hello, hystrix == fail name : " + name; } } 启动类
package cn.saytime;
import cn.saytime.service.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @RestController public class HelloConsumerFeignHystrixApplication {
public static void main(String[] args) { SpringApplication.run(HelloConsumerFeignHystrixApplication.class, args); }
@Autowired private HelloService helloService;
@RequestMapping("hello") public String hello(String name){ return helloService.hello(name); } } 测试:
启动eureka-server:8001, hello-service:8011,hello-consumer-feign-hystrix:8051
访问:http://localhost:8051/hello?name=feign_hystrix
hello, feign_hystrix 访问成功
接下来关闭hello-service服务,再次访问:
hello, hystrix == fail name : feign_hystrix 成功触发熔断
将hello-service服务重新启动,访问正常,没有触发熔断。
将hello-service服务接口加上线程等待3s,重启hello-service服务,再次调用
同样成功触发熔断
修改application.properties里面熔断超时时间为4s,再次调用,没有触发熔断。
四、Hystrix Dashboard (Hystrix 仪表盘) ribbon-hystrix 与 feign-hystrix 两个项目的pom文件都添加以下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency> 启动类都加上如下注解:
@EnableHystrixDashboard 然后访问
http://localhost:8041/hystrix http://localhost:8051/hystrix
输入链接:http://localhost:8041/hystrix.stream
同理,如果是feign-hystrix项目,输入 http://localhost:8051/hystrix.stream
点击Monitor Stream
然后我们访问一下 http://localhost:8041/hello?name=ribbon_hystrix
会出现如下监控界面:
具体监控界面内容情况,就不详细描述了