完整源码:https://gitee.com/wan-lianglin/springcloud-test
-
什么是Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
能干嘛
服务降级
服务熔断
熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
服务限流
接近实时的监控
官网:Home · Netflix/Hystrix Wiki (github.com)
-
来简单测试一下服务熔断
- 新建一个模块springcloud-provider-dept-hystrix-9001(直接复制springcloud-provider-dept-8001后修改一下启动类)
2.导入依赖
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
3.配置application.yml文件
server:
port: 9001
#mybatis配置
mybatis:
type-aliases-package: com.wll.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
#spring配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: root
#Eureka配置
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#info配置
info:
app.name: wll-springcloud
company.name: wll.com
4.controller层写方法
package com.wll.springcloud.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.wll.springcloud.pojo.Dept;
import com.wll.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/dept/get/{id}")
@HystrixCommand(fallbackMethod = "hystrixGet")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("id=>"+id+",不存在该用户,或者信息无法找到~");
}
return dept;
}
//备选方法
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept()
.setDeptno(id)
.setDname("id=>"+id+"没有对应信息,[email protected]")
.setDb_source("no this database in MySQL");
}
}
在controller层写了get和hystrixGet两个方法,其中hystrixGet方法为备用方法。当get方法出错,就通过@HystrixCommand(fallbackMethod = "hystrixGet")注解来使用hystrixGet方法。
5.在启动类中添加对熔断的支持
package com.wll.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//启动类
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient //使服务发现生效
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_9001.class);
}
}
6.启动注册中心,启动服务提供者(DeptProviderHystrix_9001),启动消费者
id为1查询成功
id为8,没有这个id,查询失败,并成功调用了备用方法
补充:
7.我们修改消费者的负载均衡算法,修改为轮询(不使用我们自定义的算法)
package com.wll.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WllRule {
@Bean
public IRule myRule(){
return new RoundRobinRule(); //轮询
}
}
3.服务降级
1.在springcloud-api服务中编写DeptClientServiceFallbackFactory类:客户端降级时返回的具体方法,内容
package com.wll.springcloud.service;
import com.wll.springcloud.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
//降级
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("id=>"+id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭")
.setDb_source("没有数据~");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public boolean addDept(Dept dept) {
return false;
}
};
}
}
2.在springcloud-api服务的DeptClientService类的@FeignClient注解中使用fallbackFactory
package com.wll.springcloud.service;
import com.wll.springcloud.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@GetMapping("/dept/get/{id}")
public Dept queryById(Long id);
@GetMapping("/dept/list")
public List<Dept> queryAll();
@GetMapping("/dept/add")
public boolean addDept(Dept dept);
}
3.在消费者spring-consumer-dept-feign服务的配置文件application.yml中开启降级feign.hystrix
server:
port: 8003
# 开启降级feign.hystrix
feign:
hystrix:
enabled: true
#Eureka配置
eureka:
client:
register-with-eureka: false #不向Eureka注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
4.启动注册中心(,springcloud-eureka-7001),开启降级的消费者(spring-consumer-dept-feign),服务提供者(springcloud-provider-dept-8001):
可以正常访问
当我们关闭服务提供者后,再访问:
可以看到返回了我们设置的降级消息。
总结:
按我的理解:服务降级主要是用于客户端,服务熔断是用于服务端。
服务熔断:服务端 某个服务超时或者异常。引起熔断~,调用备用方法,让客户端看不见报错信息,相当于保险丝。
服务降级:客户端 从整体网站请求负载考虑~,当某个服务熔断或者关闭之后,服务将不再被调用~此时在客户端,我们可以准备一个FallbackFactory,返回一个默认的值(缺省值)。
服务降级是我们资源紧张时,主动关闭某个服务器,释放资源。让服务不再被调用,当客户端继续请求这个已经关闭的服务器时,就直接在消费者返回我们设置的内容,提示此服务已关闭。
而服务熔断是在多个服务器链路中,突然有个服务器出错,宕机。为了不使整个服务链路跟着出错,甚至于引发更多连锁错误。我们使用服务熔断,直接返回备用方法。这些都配置在服务端,是被动防止服务器出错。同时还配置了负载均衡算法。
4.dashboard流监控
1.新建一个消费者模块springcloud-consumer-hystrix-dashboard
2.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>springcloud</artifactId>
<groupId>com.wll</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-hystrix-dashboard</artifactId>
<!--实体类web-->
<dependencies>
<!--Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--hystrix-dashboard依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.wll</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
3.yml文件
server:
port: 9002
4.启动类
package com.wll.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard //开启Dashboard
public class DeptConsumerDashboard_9002 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashboard_9002.class,args);
}
}
注意,既然要监控,那么服务端就要有监控相关的依赖,我们看看我的服务端springcloud-provider-dept-8001的依赖中是否有:
可以看到有。
5.启动9002,访问http://localhost:9002/hystrix
成功进入监控页面
6.监控服务提供者springcloud-provider-dept-hystrix-9001
(1)在springcloud-provider-dept-hystrix-9001pom文件中导入Hystrix依赖
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
(2)在springcloud-provider-dept-hystrix-9001启动类中增加一个servlet
package com.wll.springcloud;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
//启动类
@SpringBootApplication
@EnableEurekaClient //在服务启动后自动注册到Eureka中
@EnableDiscoveryClient //使服务发现生效
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_9001.class);
}
//增加一个servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
7.启动注册中心,服务提供者和dashboard监控
访问9001端口(localhost:9001/actuator/hystrix.stream):
接着监控此服务,点击按钮Monitor Stream进行监控
调用服务提供者(9001端口)的get方法,可看到监控变化。
图解:
一圈
实心圆:有两种含义,他通过颜色的变化代表了实例的健康程度
它的健康程度从绿色<黄色<橙色<红色递减
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大,该实心圆就越大,所以通过该实心圆的展示,就可以在大量的实例中快速发现故障实例和高压力实例。
一线
曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势!
所有springcloud入门相关(建议从上到下依次阅读):
(14条消息) Spring Cloud Eureka 入门_万1999的博客-CSDN博客
(6条消息) Spring Cloud Ribbon 入门_万1999的博客-CSDN博客
(14条消息) Spring Cloud Hystrix 入门_万1999的博客-CSDN博客
(14条消息) Zuul路由网关_万1999的博客-CSDN博客
(14条消息) SpringCloud config分布式配置_万1999的博客-CSDN博客