Hystrixs是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务,防止出现级联失败(雪崩)。
主要功能:
- 降级
- 熔断
- 隔离
- 限流
雪崩效应:
微服务化产品线,每一个服务专心于自己的业务逻辑,并对外提供相应的接口,看上去似乎很明了,其实还有很多的东西需要考虑,比如:服务的自动扩充,熔断和限流等,随着业务的扩展,服务的数量也会随之增多,逻辑会更加复杂,一个服务的某个逻辑需要依赖多个其他服务才能完成。一但一个依赖不能提供服务很可能会产生雪崩效应
,最后导致整个服务不可访问。
微服务之间进行rpc
或者http
调用时,我们一般都会设置调用超时
,失败重试
等机制来确保服务的成功执行,看上去很美,如果不考虑服务的熔断和限流,就是雪崩的源头。
假设我们有两个访问量比较大的服务A和B,这两个服务分别依赖C和D,C和D服务都依赖E服务
A和B不断的调用C,D处理客户请求和返回需要的数据。当E服务不能供服务的时候,C和D的超时
和重试
机制会被执行
由于新的调用不断的产生,会导致C和D对E服务的调用大量的积压,产生大量的调用等待和重试调用,慢慢会耗尽C和D的资源比如内存或CPU,然后也down掉。
A和B服务会重复C和D的操作,资源耗尽,然后down掉,最终整个服务都不可访问。
1.降级
类似于try catch,在出现异常或者超时或者服务不可用时返回一些默认处理方案
降级方案可在服务提供方也可在服务调用方
环境搭建:
注册中心这里选用eureka
euerka-server
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangyong</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.application.name=eureka-server #应用名称
eureka.client.fetch-registry=false #是否从注册中心拉取其他服务注册信息
eureka.client.register-with-eureka=false #是否将自己注册到注册中心
启动类
package com.zhangyong.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
eureka客户端
consumer(服务调用方)
pom.xml(consumer依赖)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangyong</groupId>
<artifactId>comsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>comsumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<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-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties(三个服务端口分别为81、82、83)
eureka.client.service-url.defaultZone=http://localhost:8080/eureka
server.port=81
spring.application.name=consumer
feign.hystrix.enabled=true #给feign远程调用开启hytrix支持
启动类
package com.zhangyong.comsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class ComsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ComsumerApplication.class, args);
}
}
订单远程调用
package com.zhangyong.comsumer.api;
import com.zhangyong.comsumer.fallback.OrderFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "xxxooo",fallback = OrderFallback.class)
public interface OrderClient {
@RequestMapping("getOrderList")
String getOrderList();
}
订单服务调用方降级
package com.zhangyong.comsumer.fallback;
import com.zhangyong.comsumer.api.OrderClient;
import org.springframework.stereotype.Component;
@Component
public class OrderFallback implements OrderClient {
@Override
public String getOrderList() {
return "订单列表降级方案";
}
}
商品远程调用
package com.zhangyong.comsumer.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("provider")
public interface ProductClient {
@RequestMapping("getProductList/{id}")
String getProductList(@PathVariable("id") String id);
}
controller
package com.zhangyong.comsumer.controller;
import com.zhangyong.comsumer.api.OrderClient;
import com.zhangyong.comsumer.api.ProductClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private OrderClient orderClient;
@Autowired
private ProductClient productClient;
@RequestMapping("getOrderList")
public String getOrderList() {
return orderClient.getOrderList();
}
@RequestMapping("getProductList/{id}")
public String getProductList(@PathVariable("id") String id) {
return productClient.getProductList(id);
}
}
provider(服务提供方)
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangyong</groupId>
<artifactId>provicer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provicer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
eureka.client.service-url.defaultZone=http://localhost:8080/eureka
server.port=82
spring.application.name=provider
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ProvicerApplication {
public static void main(String[] args) {
SpringApplication.run(ProvicerApplication.class, args);
}
}
controller
package com.zhangyong.provicer.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@RequestMapping("getOrderList")
public String getOrderList() {
return "订单列表";
}
}
package com.zhangyong.provicer.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProductController {
@RequestMapping("getProductList/{id}")
@HystrixCommand(fallbackMethod = "getProductList_fallback")
public String getProductList(@PathVariable("id") String id){
if ("0".equals(id)) {
int i = 1 / 0;
}
return "商品列表";
}
public String getProductList_fallback(@PathVariable("id") String id){
return "商品列表降级方案";
}
}
这里提醒一下,为了方便,我把order降级写在了服务调用方,product降级写在了服务提供方(配置了id传0会触发异常)
看效果:
OrderClient.java中远程调用的服务名“xxxooo”是不存在的,这时候他会降级的(服务调用方降级)
ProductClient.java中 远程调用输入id为0是会降级的(服务提供方降级)
2.熔断
Hystrix熔断机制,用于微服务之间的调用,当失败情况到达预定阈值(默认5秒失败20次),会打开断路器,断路器打开时,所有请求不管成功或者失败都会执行fallback降级方案,直到服务恢复正常为止
如图所示:当断路器打开时,每过5秒钟会呈现一个半开状态,如果失败断路器继续打开,等待下一个5秒钟的半开状态,如果是调用成功,断路器就会关闭(不需要任何操作,hystrix默认实现)
接着上面的product的测试,当我们5秒超过20次id为0的操作(降级20次),他会拒绝所有请求。
可以看到一开始id为1是可以正常获取商品列表的
当5秒连续超过20次id为0的调用,再以一次id为1调用,可以看到不管是不是正常请求同样是返回降级,这就是触发了断路器
熔断的触发条件也可以根据自己的需求进行配置
package com.zhangyong.provicer.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProductController {
@RequestMapping("getProductList/{id}")
@HystrixCommand(fallbackMethod = "getProductList_fallback",commandProperties = {
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),//监控时间
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),//失败次数
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")//失败率
})
public String getProductList(@PathVariable("id") String id){
if ("0".equals(id)) {
int i = 1 / 0;
}
return "商品列表";
}
public String getProductList_fallback(@PathVariable("id") String id){
return "商品列表降级方案";
}
}
3.隔离、限流(隔离的同时达到了限流的效果)
说隔离之前要先知道,当我们要先知道,在不使用隔离之前,我们的所有请求都是从一个线程池(springboot默认集成tomcat)中获取的(如图所示)
这样就会有个问题,当服务C不可用时,并且消耗了所有线程不归还,这样就会直接影响服务A,同时也导致B、C服务也没有可用的线程,也就时上面说的服务雪崩效应
3-1.线程池隔离
顾名思义,线程池隔离就是将多个服务单独用线程池隔离开来,每个服务分配一部分的线程数量
这样的好处就是就是即使C服务出现问题,也不至于影响其他服务 ,还有一点就是,线程池隔离是异步操作的,服务A可以主动超时,并且归还线程
3-2.信号量隔离
信号量隔离与线程池隔离区别,信号量隔离和tomcat用的是同一组线程池里的线程,就好比计数器,给指定服务分配一定的信号量,拿到对应服务信号量才能调用,没拿到信号量配置了队列的,就在队列等待,没配置的直接fallback降级,当请求返回时才会归还信号量,并且是同步的,不能主动超时,也就是说当请求返回时才能判断该请求是否超时
下面看代码实现
增加一个provider2服务
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhangyong</groupId>
<artifactId>provider2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
eureka.client.service-url.defaultZone=http://localhost:8080/eureka
server.port=81
spring.application.name=consumer
#是否开启feign对hystrix支持
feign.hystrix.enabled=false
#最大并发数
server.tomcat.max-threads=10
#接受和处理的最大连接数
server.tomcat.max-connections=10
#初始化时创建的线程数
server.tomcat.min-SpareThreads=10
#可以放到处理队列中的请求数
server.tomcat.acceptCount=10
#远程连接超时时间
ribbon.ConnectTimeout=1000
#远程访问超时时间
ribbon.ReadTimeout=5000
//线程池隔离
@HystrixCommand(groupKey = "user-pool",//服务名称
commandKey = "getUserList",//接口名称,默认使用方法名
threadPoolKey = "user-pool",//线程池名称
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "6"),//线程池大小
@HystrixProperty(name = "maxQueueSize", value = "10"),//队列等待阈值(默认-1)
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),//线程存活时间(默认 1min)
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "10")//超出队列等待阈值执行拒绝策略
},
fallbackMethod = "aaa")
//信号量隔离
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "4")
},fallbackMethod = "bbb")
application.properties
eureka.client.service-url.defaultZone=http://localhost:8080/eureka
server.port=83
spring.application.name=provider2
启动类
package com.zhangyong.provider2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class Provider2Application {
public static void main(String[] args) {
SpringApplication.run(Provider2Application.class, args);
}
}
controller
package com.zhangyong.provider2.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping(value = "getUserList",method = RequestMethod.GET)
public String getUserList() {
return "用户列表";
}
@RequestMapping(value = "getUserInfo",method = RequestMethod.GET)
public String getUserInfo() {
return "用户详情";
}
}
consumer服务需要改造一下
给consumer加入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
给consumer配置文件更新一下
这里为了测试方便,1.给初始线程限定为10,2.关闭feign对hystrix的支持(开启会导致hystrix超时失效) 3.feign底层的ribbon也有超时机制,需要修改ribbon的超时时间
eureka.client.service-url.defaultZone=http://localhost:8080/eureka
server.port=81
spring.application.name=consumer
#是否开启feign对hystrix支持
feign.hystrix.enabled=false
#最大并发数
server.tomcat.max-threads=10
#接受和处理的最大连接数
server.tomcat.max-connections=10
#初始化时创建的线程数
server.tomcat.min-SpareThreads=10
#可以放到处理队列中的请求数
server.tomcat.acceptCount=10
#远程连接超时时间
ribbon.ConnectTimeout=1000
#远程访问超时时间
ribbon.ReadTimeout=5000
consumer 使用hystrix启动类不要忘了加注解
package com.zhangyong.comsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
@EnableCircuitBreaker
public class ComsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ComsumerApplication.class, args);
}
}
给consumer 的 controller 加两个接口 和一个降级方法
package com.zhangyong.comsumer.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import com.zhangyong.comsumer.api.OrderClient;
import com.zhangyong.comsumer.api.ProductClient;
import com.zhangyong.comsumer.api.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private OrderClient orderClient;
@Autowired
private ProductClient productClient;
@Autowired
private UserClient userClient;
@RequestMapping("getOrderList")
public String getOrderList() {
return orderClient.getOrderList();
}
@RequestMapping("getProductList/{id}")
public String getProductList(@PathVariable("id") String id) {
System.out.println(Thread.currentThread().getName());
return productClient.getProductList(id);
}
@HystrixCommand(groupKey = "user-pool",//服务名称
commandKey = "getUserList",//接口名称,默认使用方法名
threadPoolKey = "user-pool",//线程池名称
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "6"),//线程池大小
@HystrixProperty(name = "maxQueueSize", value = "10"),//队列等待阈值(默认-1)
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),//线程存活时间(默认 1min)
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "10")//超出队列等待阈值执行拒绝策略
},
fallbackMethod = "aaa")
@RequestMapping("getUserList")
public String getUserList() {
System.out.println(Thread.currentThread().getName());
return userClient.getUserList();
}
//信号量隔离
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),//超时时间 5秒
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),//信号量隔离
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "4")//分配的信号量数
},fallbackMethod = "aaa")
@RequestMapping("getUserInfo")
public String getUserInfo() {
System.out.println(Thread.currentThread().getName());
return userClient.getUserInfo();
}
public String aaa() {
System.out.println("降级了");
return "aaa";
}
}
给consumer 加个 Userclient.java 用于远程调用 provider2服务
package com.zhangyong.comsumer.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient("provider2")
public interface UserClient {
@RequestMapping(value = "getUserList", method = RequestMethod.GET)
String getUserList();
@RequestMapping(value = "getUserInfo", method = RequestMethod.GET)
String getUserInfo();
}
下面看线程池隔离效果:
getUserList是配置了线程池隔离的
可以看到他们来自不同的线程池,这说明他们隔离开了,其实当加了@HystrixCommand注解后默认也会线程池隔离
信号量隔离效果:
需要借助一下jMeter测试工具
线程组配置的是每秒5次请求循环1次
http请求调用的是getUserInfo接口
我配置的信号量是4个而我一次给了5个请求,所以有一个是降级的是正确的
线程池隔离与信号量隔离区别
线程池隔离
信号量隔离
使用场景