一、 什么是灾难性的雪崩效应
微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服务将处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
![1df1b8dac5d208b5b5c9eb8a7fbca6a4.png](https://i-blog.csdnimg.cn/blog_migrate/f61e8baaea61b1469fe6903a5329f011.jpeg)
![7c8a868adbc3cca98ccc511623e1fe6f.png](https://i-blog.csdnimg.cn/blog_migrate/b45790cf6b78d322394027f22e58a537.jpeg)
![7289d9d7186354f25b3cbe490cac588a.png](https://i-blog.csdnimg.cn/blog_migrate/4b7205eba8d8acf741174031fcbca890.jpeg)
![97303dd3cb1172cf12554845f080f5de.png](https://i-blog.csdnimg.cn/blog_migrate/c9c3da0466075f07c43f1d93abd42d81.jpeg)
造成雪崩原因可以归结为以下三个:
1.服务提供者不可用(硬件故障,程序Bug,缓存击穿,用户大量请求)
2.重试加大流量(用户重试,代码逻辑重试)
3.服务调用者不可用(同步等待造成的资源耗尽)
最终的结果就是一个服务不可用,导致一-系列服务的不可用,而往往这种后果往往无法预料的。
二、如何解决灾难性雪崩效应
降级
超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。实现-一个fallback方法,当请求后端服务出现异常的时候,可以使用fallback方法返回的值.
隔离(线程池隔离和信号量隔离)
限制调用分布式服务的资源使用,某--个调用的服务出现问题不会影响其他服务调用。
熔断
当失败率(如因网络故障/超时造成的失败率高)达到阀值自动触发降级,熔断器触发的快
速失败会进行快速恢复。
缓存
提供了请求缓存。
请求合并
提供请求合并。
三、降级
对服务进行降级处理
创建项目
![6d27a467c812290ace1d5d91a22c934e.png](https://i-blog.csdnimg.cn/blog_migrate/13bcc3182514a8ac697d643019268b58.jpeg)
修改pom文件添加hystrix的坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
修改全局配置文件
spring.application.name=eureka-consumer-ribbon-hystrix
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
修改启动器开启熔断器
@EnableCircuitBreaker //开启熔断器 (断路器)
@EnableEurekaClient
@SpringBootApplication
public class SpringcloudEurekaConsumerhystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaConsumerhystrixApplication.class, args);
}
}
在项目中添加Product实体
public class Product {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Product(Integer id, String name) {
this.id = id;
this.name = name;
}
public Product() {
}
}
修改ProductService
@Service
public class UserService {
@Autowired
private LoadBalancerClient balancerClient;//ribbon 负载均衡器
@HystrixCommand(fallbackMethod = "fallback")
public List<Product> getUser(){
//选择调用的服务的名称
//ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.balancerClient.choose("ego-product-provider");
//拼接访问服务的URL
StringBuffer sb = new StringBuffer();
//http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
//springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {};
//ResponseEntity封装了返回值的信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET,null,type);
List<Product> list = response.getBody();
return list;
}
//返回拖地数据的方法
public List<Product> fallback(){
List<Product> list = new ArrayList<>();
list.add(new Product(-1,"我是托底数据"));
return list;
}
}
正常情况下
![845412eb6c5a1bece81fcdc5d25eb30a.png](https://i-blog.csdnimg.cn/blog_migrate/0a1ae9645ebd6ffaf8ae5df7f18de6f5.jpeg)
provider宕机了
![34d304dd08cd7b781c95ab62c7c9d5f2.png](https://i-blog.csdnimg.cn/blog_migrate/b9941df626d247d43495e1b2533b9ccf.jpeg)
以下四种情况将触发getFallback调用
(1)方法抛出非Hystrix BadRequestException异常。
(2)方 法调用超时
(3)熔断器开启拦截调用
(4)线程池/队列/信号量是否跑满
四、请求缓存
Hystrix为了降低访问服务的频率,支持将--个请求与返回结果做缓存处理。如果再次
请求的URL没有变化,那么Hystrix 不会请求服务,而是直接从缓存中将结果返回。这样可
以大大降低访问服务的压力。
Hystrix自带缓存。有两个缺点:
(1)是一个本地缓存。在集群情况下缓存是不能同步的。
(2)不支持 第三方缓存容器。Redis, memcache 不支持的。
可以使用spring 的cache.
安装Redis并启动
创建项目
![11b6ece15ce0b14444369f33293e2a97.png](https://i-blog.csdnimg.cn/blog_migrate/a515433372dec1ce0ff177de3ae7583c.jpeg)
修改pom文件添加springCache坐标
<?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>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sxt</groupId>
<artifactId>springcloud-eureka-consumer-ribbon-cache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-eureka-consumer-ribbon-cache</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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-hystrix</artifactId>
</dependency>
<!--springCache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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>Dalston.SR5</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>
在配置文件中配置Redis链接信息
spring.application.name=eureka-consumer-ribbon-cache
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
# Redis
spring.redis.database=0
#Redis服务器地址
spring.redis.host=192.168.226.128
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(负值表示没有限制)
spring.redis.pool.max-active=100
#连接池最大阻塞等待时间(负值表示没有限制)
spring.redis.poo1.max-wait=3000
#连接池最大空闭连接数
spring.redis.pool.max-idle=200
#连接汉最小空闲连接数
spring.redis.pool.min-idle=50
#连接超时时间(毫秒)
spring.redis.pool.timeout=600
修改启动类开启缓存
@EnableCaching
@EnableEurekaClient
@SpringBootApplication
public class SpringcloudEurekaConsumerhystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaConsumerhystrixApplication.class, args);
}
}
修改ProductService
@CacheConfig(cacheNames = "com.sxt.ego.product")
@Service
public class ProductService {
@Autowired
private LoadBalancerClient balancerClient;//ribbon 负载均衡器
@HystrixCommand(fallbackMethod = "fallback")
public List<Product> getUser(){
//选择调用的服务的名称
//ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.balancerClient.choose("ego-product-provider");
//拼接访问服务的URL
StringBuffer sb = new StringBuffer();
//http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
//springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {};
//ResponseEntity封装了返回值的信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET,null,type);
List<Product> list = response.getBody();
return list;
}
//返回拖地数据的方法
public List<Product> fallback(){
List<Product> list = new ArrayList<>();
list.add(new Product(-1,"我是托底数据"));
return list;
}
//根据ID查询商品
@Cacheable(key = "'product'+ #id")
public Product getProductById(Integer id){
System.out.println("========GET======="+id);
return new Product(id,"新的商品");
}
//根据ID删除商品
@CacheEvict(key = "'product'+ #id")
public void delProductById(Integer id){
System.out.println("========DEL======="+id);
}
}
修改ProductController
@RestController
public class CacheController {
@Autowired
private ProductService userService;
@RequestMapping("/consumer")
public List<Product> getUsers(){
return this.userService.getUser();
}
@RequestMapping(value = "/get",method = RequestMethod.GET)
public Product get(Integer id){
return this.userService.getProductById(id);
}
@RequestMapping(value = "/del",method = RequestMethod.GET)
public void del(Integer id){
this.userService.delProductById(id);
}
}
![c163b4083090faad5549472d812d5543.png](https://i-blog.csdnimg.cn/blog_migrate/fa80c43c632d1859c4af07528c3e31ec.jpeg)
![40dd20d2364e085f232187655bd6d5a0.png](https://i-blog.csdnimg.cn/blog_migrate/bbee456e6ebf78d8eae193bc29b46e1b.png)
删除操作
![ef154a10c69461e1fc2d6e92dad2c08b.png](https://i-blog.csdnimg.cn/blog_migrate/99b0122317e4d644dcb3eb5e81591e6a.png)
五、请求合并
Hystrix中的请求合并,就是利用一个合并处理器,将对同一个服务发起的连续请求合并成一个请求进行处理(这些连续请求的时间窗默认为10ms)
没合并的请求
![da8e3468e4b3d88be8453dc1a074a9bc.png](https://i-blog.csdnimg.cn/blog_migrate/5e5f610830e36811727add202f57af4f.jpeg)
请求合并
![cbbb2ef1a05096c91cfd46b0b9dd9c47.png](https://i-blog.csdnimg.cn/blog_migrate/58a238fddfdfaaf1595002d744b8b3b4.jpeg)
什么情况下使用请求合并
在微服务架构中,我们将--个项目拆分成很多个独立的模块,这些独立的模块通过远程调用来互相配合工作,但是,在高并发情况下,通信次数的增加会导致总的通信时间增加,同时,线程池的资源也是有限的,高并发环境会导致有大量的线程处于等待状态,进而导致响应延迟,为了解决这些问题,我们需要来了解Hystrix的请求合并。
请求合并的缺点
设置请求合并之后,本来一个请求可能5ms就搞定了,但是现在必须再等10ms看看还有没有其他的请求一起的, 这样一个请求的耗时就从5ms增加到15ms了,不过,如果我们要发起的命令本身就是一一个高延迟的命令,那么这个时候就可以使用请求合并了,因为这个时候时间窗的时间消耗就显得微不足道了,另外高并发也是请求合并的一个非常重要的场景。
创建项目
![38e0d4959f70effe8be40d10a1125e4b.png](https://i-blog.csdnimg.cn/blog_migrate/2ad772ad8383d4d9b7100a471c49760f.png)
修改pom文件添加hystrix坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
修改全局配置文件
spring.application.name=eureka-consumer-ribbon-batch
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
修改ProductService
@Service
public class UserService {
//利用 hystrix 合并请求
@HystrixCollapser(batchMethod = "batchProduct", scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
//请求时间间隔在 20ms 之内的请求会被合并为一个请求,默认为 10ms
@HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
//设置触发批处理执行之前,在批处理中允许的最大请求数。
@HystrixProperty(name = "maxRequestsInBatch", value = "200"),
})
//consumer 的 controller 调用的方法 该方法返回值必须要返回Future 类型
public Future<Product> getProduct(Integer id){
System.out.println("========"+id+"===============");
return null;
}
//调用provider服务的方法
@HystrixCommand
public List<Product> batchProduct(List<Integer> ids){
for (Integer id:ids){
System.out.println(id);
}
//假设是调用Provider服务后返回的list
List<Product> list = new ArrayList<>();
list.add(new Product(1,"电视"));
list.add(new Product(2,"电脑"));
list.add(new Product(3,"冰箱"));
list.add(new Product(4,"洗衣机"));
list.add(new Product(10,"list.........."));
System.out.println("dddddddddddddddddd");
return list;
}
}
修改 Controller
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/consumer")
public void getUsers() throws Exception{
Future<Product> p1 = this.userService.getProduct(1);
Future<Product> p2 = this.userService.getProduct(2);
Future<Product> p3 = this.userService.getProduct(3);
System.out.println(p1.get().toString());
System.out.println(p2.get().toString());
System.out.println(p3.get().toString());
}
}
![94d064cd674aec47c66721c11d586498.png](https://i-blog.csdnimg.cn/blog_migrate/7b707b37c8e447a1a8bafc107f52ab92.jpeg)
请求参数介绍
![df9ed59902f936198db179eaa6afdee7.png](https://i-blog.csdnimg.cn/blog_migrate/1c5a108c0c9a7c44e8d0c0d45ee2eeb9.jpeg)
六、服务熔断
熔断机制相当于电路的跳闸功能。
例如:我们可以配置熔断策略为当前请求错误比例在10s内>50%时,该服务将进入熔断状态,后续请求都会进入fallback。
![c014322375ed69d5e989becc84d73c5a.png](https://i-blog.csdnimg.cn/blog_migrate/22dd30b1a639945bc94f80f6c0d068e8.jpeg)
创建项目
![ad5cf9a21384bef137fc80119ab2bc16.png](https://i-blog.csdnimg.cn/blog_migrate/cfc3cabe6615ea22c9d6a24bfdab7b7d.jpeg)
修改pom文件添加hystrix坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
修改全局配置文件
spring.application.name=eureka-consumer-ribbon-breaker
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
启动类
@EnableCircuitBreaker //开启熔断器 (断路器)
@EnableEurekaClient
@SpringBootApplication
public class SpringcloudEurekaConsumerhystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaConsumerhystrixApplication.class, args);
}
}
修改ProductService
@Service
public class UserService {
@Autowired
private LoadBalancerClient balancerClient;//ribbon 负载均衡器
@HystrixCommand(fallbackMethod = "fallback",
commandProperties = {
//默认 20 个;10s 内请求数大于 20 个时就启动熔断器,当请求符合熔断条件时将触发 getFallback()。
@HystrixProperty(name= HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,
value="10"),
//请求错误率大于 50%时就熔断,然后 for 循环发起请求,当请求符合熔断条件时将触发 getFallback()。
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,
value="50"),
//默认 5 秒;熔断多少秒后去尝试请求
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,
value="5000"),
})
public List<Product> getUser(int flag){
System.out.println(flag);
if (flag==1){
throw new RuntimeException();
}
//选择调用的服务的名称
//ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.balancerClient.choose("ego-product-provider");
//拼接访问服务的URL
StringBuffer sb = new StringBuffer();
//http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
//springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {};
//ResponseEntity封装了返回值的信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET,null,type);
List<Product> list = response.getBody();
return list;
}
//返回拖地数据的方法
public List<Product> fallback(int flag){
List<Product> list = new ArrayList<>();
list.add(new Product(-1,"我是托底数据"));
return list;
}
}
修改 ProductController
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/consumer")
public List<Product> getUsers(@RequestParam("flag") Integer flag){
return this.userService.getUser(flag);
}
}
![371279f2b6edc6849f2fd69cb39e7042.png](https://i-blog.csdnimg.cn/blog_migrate/2cf451e35a9be2bae0ef05c8872b6a0f.jpeg)
![f97546cc2937dc5340275d1fb9d4c522.png](https://i-blog.csdnimg.cn/blog_migrate/15d9df479b0e87226d4fcc635228910c.jpeg)
![106fb98d4fabd1b67f1922cd362eec3b.png](https://i-blog.csdnimg.cn/blog_migrate/3e7c6547ec6c78201d6f470972f1f11d.jpeg)
熔断参数
![3470a13e922ca8058467d1b1b6456532.png](https://i-blog.csdnimg.cn/blog_migrate/a3c5c4b56cc37fb32e43f57b0473d968.jpeg)
七、隔离
线程池隔离
![8155ae49b40a057a997432be63b9ebea.png](https://i-blog.csdnimg.cn/blog_migrate/a8daefc5ca6b985cc8dcefbd1b5a2339.jpeg)
![d7d4a7866fde43add1666220167615bf.png](https://i-blog.csdnimg.cn/blog_migrate/8209e974ab1d887c2e16f76d4a85b56b.jpeg)
![43d392a980346f3fefcc8f675eddec75.png](https://i-blog.csdnimg.cn/blog_migrate/99c3f7485f91510a73d2bd76e2f8092e.jpeg)
![0ef67d79635bbfcd7d941342339c15de.png](https://i-blog.csdnimg.cn/blog_migrate/f1c1ef66321cb9d04259b13d0e65e2b0.jpeg)
线程池隔离的优缺点:
优点:
1、使用线程池隔离可以完全隔 离依赖的服务(例如图中的A. B、C服务), 请求线程可以快速放回。
2、当线程池出现问题时 ,线程池隔离是独立的,不会影响其他服务和接口。
3、当失败的服务再次变得可用时,线程池将清理并可立即恢复,而不需要一 一个长时间的复。
4、独立的线程池提高了并发性。
缺点:
线程池隔离的主要缺点是它们增加计算开销(CPU).每个命令的执行涉及到排队、调度和上下文切换都是在一个单独的线程上运行的。
创建项目
![ef4f2d6ed82ec18c584f82a2eec5b693.png](https://i-blog.csdnimg.cn/blog_migrate/5c3dc7daa2b438a775ff82c91db26d6d.jpeg)
修改pom文件添加hystrix坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
修改配置文件
spring.application.name=eureka-consumer-ribbon-threadpool
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
修改启动类
@EnableCircuitBreaker //开启熔断器 (断路器)
@EnableEurekaClient
@SpringBootApplication
public class SpringcloudEurekaConsumerhystrixApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaConsumerhystrixApplication.class, args);
}
}
修改ProductService
@Service
public class UserService {
@Autowired
private LoadBalancerClient balancerClient;//ribbon 负载均衡器
@HystrixCommand(groupKey="ego-product-provider",
commandKey = "getUsers",
threadPoolKey="ego-product-provider",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value ="30"),//线程池大小
@HystrixProperty(name = "maxQueueSize",value = "100"),//最大队列长度
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),//线程存活时间
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")//拒绝请求
},
fallbackMethod = "fallback")
public List<Product> getUser(){
System.out.println(Thread.currentThread().getName());
//选择调用的服务的名称
//ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.balancerClient.choose("ego-product-provider");
//拼接访问服务的URL
StringBuffer sb = new StringBuffer();
//http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
//springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {};
//ResponseEntity封装了返回值的信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET,null,type);
List<Product> list = response.getBody();
return list;
}
//返回拖地数据的方法
public List<Product> fallback(){
System.out.println(Thread.currentThread().getName());
List<Product> list = new ArrayList<>();
list.add(new Product(-1,"我是托底数据"));
return list;
}
public void showThread(){
System.out.println(Thread.currentThread().getName());
}
}
修改 ProductController
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/consumer")
public List<Product> getUsers(){
return this.userService.getUser();
}
@RequestMapping("/consumer1")
public void getUsers1(){
this.userService.showThread();
}
}
![eaf4bf475957b6f4ae02902a24d9e9e3.png](https://i-blog.csdnimg.cn/blog_migrate/9ef489588a3e2be473bb9cbf7dfb9f10.jpeg)
线程池隔离参数
![b3913f29679898d343b3676a766223e5.png](https://i-blog.csdnimg.cn/blog_migrate/7c0277235e9d11bf28a1a031a1428c5a.jpeg)