Netflix has created a library called Hystrix that implements the circuit breaker pattern. In a microservice architecture it is common to have multiple layers of service calls.
A service failure in the lower level of services can cause cascading failure all the way up to the user. When calls to a particular service reach a certain threshold (20 failures in 5 seconds is the default in Hystrix), the circuit opens and the call is not made. In cases of error and an open circuit a fallback can be provided by the developer.
Having an open circuit stops cascading failures and allows overwhelmed or failing services time to heal. The fallback can be another Hystrix protected call, static data or a sane empty value. Fallbacks may be chained so the first fallback makes some other business call which in turn falls back to static data.
https://github.com/andyChenHuaYing/spring-cloud-demo
通过tag切换git tag -d v1.0,若想修改,可根据此tag创建新的分支。
与Spring Cloud 之服务发现与调用-Ribbon#2.3 eureka-server-singleton 没有任何区别
与Spring Cloud 之服务发现与调用-Ribbon#2.4 eureka-service 没有任何区别
spring-cloud-starter-netflix-eureka-server
、spring-cloud-starter-netflix-ribbon
、spring-cloud-starter-netflix-hystrix
依赖@EnableHystrix
开启使用Hystrix功能@Bean @LoadBalanced
向Spring容器注入org.springframework.web.client.RestTemplate
实例@Autowired public RestTemplate restTemplate;
获取实例,调用服务提供方提供的方法@HystrixCommand(fallbackMethod = "hiError")
指定回调方法
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-finchley-demoartifactId>
<groupId>org.oscar.scdgroupId>
<version>1.0.0version>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>eureka-service-ribbon-hystrixartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
dependencies>
project>
server:
port: 8766
spring:
application:
name: eureka-service-ribbon-hystrix
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
package org.oscar.scd.eureka.service.ribbon.hystrix;
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.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableHystrix
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaServiceRibbonHystrixApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(EurekaServiceRibbonHystrixApplication.class, args);
}
}
package org.oscar.scd.eureka.service.ribbon.hystrix.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 HelloRibbonHystrixService {
@Autowired
public RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://eureka-service//print?name=" + name, String.class);
}
public String hiError(String name) {
return "Hi " + name + ", sorry, system error.";
}
}
package org.oscar.scd.eureka.service.ribbon.hystrix.controller;
import org.oscar.scd.eureka.service.ribbon.hystrix.service.HelloRibbonHystrixService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ribbon/hystrix")
public class HelloRibbonHystrixController {
@Autowired
public HelloRibbonHystrixService service;
@GetMapping("/print")
public String print(@RequestParam String name) {
return this.service.hiService(name);
}
}
最简单的方式添加一个SpringBoot启动类型的启动类就行。
与8762相同,只是修改 Active profiles 为8763
最简单的方式添加一个SpringBoot启动类型的启动类就行。
EurekaServerSingletonApplication
EurekaServiceApplication-8762
EurekaServiceApplication-8763
、EurekaServiceRibbonHystrixApplication
此时服务都是正常注册状态!
验证Hystrix是否生效,整体步骤
1. 停止端口为8762的服务提供者,观察eureka-server信息界面,服务是否下线以及再次调用服务,观察返回结果是否只有8763端口响应
2. 停止端口为8763的服务提供者,观察eureka-server信息界面,服务是否下线以及再次调用服务,观察返回结果是否是Hystrix服务熔断回调函数返回的结果
3. 若都是,则验证Hystrix功能生效
到这里,基本验证了Hystrix启作用了,但是这只是入门级别的使用,还有几个疑点后续解决。
https://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients
https://github.com/Netflix/hystrix
Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。
解决方式(或者说处理措施,在后续详细使用或者问题整理中会解)