SpringCloud-Hystrix熔断器

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个请求,所以有一个是降级的是正确的

线程池隔离与信号量隔离区别 

 线程池隔离

信号量隔离

 使用场景

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值