01 基础环境准备
02 一文读懂Eureka
03 Zookeeper注册中心
04 Consule注册中心
05 Ribbon
06 OpenFegin
07 Hystrix全面解析
08 Gateway全面解析
09 Config配置中心
10 Bus消息总线
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
左图中的请求需要调用A,P,H,I 四个服务,如果一切顺利则没有什么问题,关键是如果I服务超时会出现什么情况呢?
(2) 雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出"。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。所以通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
Hystrix是个用于处理分布式系统的延迟和容错的开源库,在分布式奈统里,许多依赖不可避免的会调用失败,比如超时、异常等。Hystrix能够保证在一个依赖出问题的情況下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回个符合预期的、可处理的备选响应( Fallback),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
(1) 服务降级
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。
使用场景:服务异常、超时、服务熔断触发服务降级、线程池/信号量打满也会导致服务降级
(2) 服务熔断
高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。股票交易中,如果股票指数过高,也会采用熔断机制,暂停股票的交易。同样,在微服务架构中,熔断机制也是起着类似的作用。当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
(3) 服务限流
限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务(定向到错误页或告知资源没有了)、排队或等待(比如秒杀、评论、下单)、降级(返回兜底数据或默认数据,如商品详情页库存默认有货)。
(1) pom
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.zrs.springcloud</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
(2) application.yml
server:
port: 7004
spring:
application:
name: provider-hystrix
eureka:
client:
#是否将自己注册到EurekaServer
register-with-eureka: true
#是否从EurekaServer获取已有的注册服务
fetch-registry: true
#注册地址
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
instance-id: provider-hystrix
prefer-ip-address: true
(3) 主启动类
@SpringBootApplication
@EnableEurekaClient
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class);
}
}
(4) Controller
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello(){
return "Hello Thread:"+Thread.currentThread().getName();
}
@GetMapping("/threeseconds")
public String threeseconds(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
}
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--oepn fegin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.zrs.springcloud</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
server:
port: 8004
spring:
application:
name: customer-hystrix
eureka:
client:
#是否将自己注册到EurekaServer
register-with-eureka: true
#是否从EurekaServer获取已有的注册服务
fetch-registry: true
#注册地址
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
instance-id: customer-hystrix
prefer-ip-address: true
@SpringBootApplication
@EnableFeignClients
public class HystrixCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixCustomerApplication.class);
}
}
@Component
@FeignClient("PROVIDER-HYSTRIX")
@RequestMapping("/hystrix")
public interface FeginService {
@GetMapping("/hello")
String hello();
@GetMapping("/threeseconds")
String threeseconds();
}
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
}
(1) 修改HystrixController
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello(){
return "Hello Thread:"+Thread.currentThread().getName();
}
/**
* fallbackMethod 降级方法
* timeoutInMilliseconds: 2秒为正常响应,超过两秒调用降级方法
*
*/
@HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
public String fallbackMethod(){
return "服务器正忙,请稍后访问。Thread:"+Thread.currentThread().getName();
}
}
(2) 修改启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class);
}
}
(1) application.yml添加配置文件
#开启降级
feign:
hystrix:
enabled: true
(2) 修改主启动类
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class HystrixCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixCustomerApplication.class);
}
}
(3) 修改HystrixController
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
public String fallbackMethod(){
return "服务器正忙,请稍后访问。Thread:"+Thread.currentThread().getName();
}
}
(1) DefaultProperties作用:全局降级方法。修改customer-hystrix的HystrixController
/**
* @Description: @DefaultProperties全局降级方法
* @Auther: zhurongsheng
* @Date: 2020/3/14 22:32
*/
@RequestMapping("/customer")
@RestController
@DefaultProperties(defaultFallback = "commonfallbackMethod")
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
public String commonfallbackMethod(){
return "服务器正忙,请稍后访问。Thread:"+Thread.currentThread().getName();
}
}
(1) FeginService
@FeignClient(value = "PROVIDER-HYSTRIX",fallback = FeginFallbackService.class,path = "/hystrix")
@Service
public interface FeginService {
@GetMapping("/hello")
String hello();
@GetMapping("/threeseconds")
String threeseconds();
}
(2) 接口实现类,FeginFallbackService
@Service
public class FeginFallbackService implements FeginService{
@Override
public String hello() {
return "FeginFallbackService invoke hello";
}
@Override
public String threeseconds() {
return "FeginFallbackService invoke threeseconds";
}
}
(3) 修改Controller,HystrixController
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
}
服务熔断:在一定周期内,服务异常次数达到设定的阈值或百分比,则触发熔断,熔断后,后面的请求将都走默认处理方法defaultFallback
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello() {
return "Hello Thread:" + Thread.currentThread().getName();
}
/**
* fallbackMethod 降级方法
* timeoutInMilliseconds: 2秒为正常响应,超过两秒调用降级方法
*/
@HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
public String fallbackMethod() {
return "服务器正忙,请稍后访问。Thread:" + Thread.currentThread().getName();
}
/**
* =====================熔断配置=======================
* circuitBreaker.enabled: 启动熔断
* circuitBreaker.requestVolumeThreshold:请求次数
* circuitBreaker.errorThresholdPercentage: 失败率达到多少启动熔断
*/
@HystrixCommand(fallbackMethod = "circuitBreakerFallback",commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value = "true"),
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "10"),
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
@GetMapping("/{id}")
public String circuitBreaker(@PathVariable("id") Integer id) {
if (id<0){
throw new RuntimeException("id ="+id+",不能为负数");
}
return "调用成功,O(∩_∩)O~ id=" + id;
}
public String circuitBreakerFallback(@PathVariable("id") Integer id) {
return "id =" + id + ", 不能为负数,o(╥﹏╥)o~ ";
}
}
除了隔离依赖服务的週用以外, Hystrix还提供了往实时的调用监控( Hystrix Dashboard), Hystrix:会持续地记录所有通过 Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。 Netflix 通过hystrix- metrics- event- stream项目实现了对以上指标的监控。 Spring Cloud也提供了 Hystrix Dashboard的整合,对监控内容转化成可视化界面。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
server:
port: 9001
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashbordApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashbordApplication.class);
}
}
@Configuration
public class HystrixConfig {
@Bean
public ServletRegistrationBean myServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
http://localhost:7004/hystrix.stream
#分支 Hystrix-enviroment-release-v1.0
https://github.com/zhurongsheng666/spring-cloud-hoxton