Hystrix基本使用
Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。
在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等。我们要构建稳定、可靠的分布式系统,就必须要有这样一套容错方法
熔断触发降级
- 熔断的目的是为了起到保护作用
- 降级
- 主动降级,大促的时候关闭非核心服务。
- 被动降级,熔断降级、限流降级
降级
熔断是一种降级策略
一. 添加pom依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
二. 在启动类上添加 @EnableCircuitBreaker注解,开启Hystrix熔断
@EnableCircuitBreaker
@ComponentScan(basePackages = {
"com.gxedu.example.controller",
"com.gxedu.example.sourceloader",
"com.gxedu.example",
"com.gxedu.springcloud.clients"})
@EnableFeignClients(basePackages = "com.gxedu.springcloud.clients")
@SpringBootApplication
public class UserServiceProviderApplication {
public static void main(String[] args) {
SpringApplication springApplication=new SpringApplication(UserServiceProviderApplication.class);
Map<String,Object> map=new HashMap<>();
map.put("key","value");
springApplication.setDefaultProperties(map);
springApplication.run(args);
}
}
三. application.yml
spring:
application:
name: user-service
# kafka:
# bootstrap-servers: 192.168.216.128:9092
# consumer:
# group-id: user-service
cloud:
bus:
enabled: false
server:
port: 9999
management:
endpoints:
web:
exposure:
include: refresh,hystrix.stream
feign:
hystrix:
enabled: true # 开启feign的hystrix支持,默认是false
hystrix:
command:
default: #全局配置, (针对方法配置)feignclient#method(param)
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 1000 #命令执行超时时间,默认1000ms,调接口响应时间超1S执行降级,不管提供者是否挂机还是延迟超过时间就走降级
OrderServiceFeignClient#orders():
execution:
isolation:
strategy: SEMAPHORE
semaphore:
maxConcurrentRequests: 10
OrderServiceFeignClient#insert():
execution:
isolation:
strategy: THREAD
threadpool:
order-service:
coreSize: 2
maxQueueSize: 1000
queueSizeRejectionThreshold: 800
ribbon:
ReadTimeout: 10000
ConnectTimeout: 10000
四. Hystrix降级
Hystrix中的三种降级方案,fallback-> 回退方案(降级处理方案)
熔断触发降级
在HystrixCommandProperties
这个类中查询我们需要配置的参数
@RestController
public class HystrixController {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value ="true"),
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "5"),
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
},fallbackMethod = "fallback",
groupKey = "",threadPoolKey = "order-service")
@GetMapping("/hystrix/order/{num}")
public String queryOrder(@PathVariable("num")int num){
if(num%2==0){
return "正常访问";
}
//restTemplate默认有一个请求超时时间
return restTemplate.getForObject("http://localhost:8082/orders",String.class);
}
//配置降级的fallback方法,参数要和请求的方法参数一致
public String fallback(int num){
return "请求被降级";
}
}
-
熔断开启之后,后续的正常请求也无法发送过去.
-
如何触发熔断?“判断阈值”
10s钟之内,发起了20次请求,失败率超过50%。 熔断的恢复时间(熔断5s),从熔断开启 到后续5s之内的请求,都不会发起到远程服务端.
-
熔断会有一个自动恢复。
@HystrixProperty(name=“circuitBreaker.enabled”,value =“true”), --开启状态
@HystrixProperty(name=“circuitBreaker.requestVolumeThreshold”,value = “5”), --最小请求次 数
@HystrixProperty(name=“circuitBreaker.sleepWindowInMilliseconds”,value = “5000”), --5s 熔断的时间
@HystrixProperty(name=“circuitBreaker.errorThresholdPercentage”,value = “50”) -百分比(50%)
开启熔断,在5s之内发起5次请求,失败率超过50%,自动触发熔断,5s之后会自动恢复
请求超时触发降级
/**
* 如果配置了超时时间,就使用自己的超时时间,execution.isolation.thread.timeoutInMilliseconds,3s超时
结果: 正常访问返回
*/
@HystrixCommand(fallbackMethod ="timeoutFallback",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
})
@GetMapping("/hystrix/timeout")
public String queryOrderTimeout(){
return restTemplate.getForObject("http://localhost:8082/orders",String.class);
}
/**
* 如果没有配置超时时间,就使用默认的全局配置的超时时间,在application.yml中配置,2s超时
* hystrix:
command:
default: #全局配置, feignclient#method(param)
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 2000
结果: 超时被降级
*/
@HystrixCommand(fallbackMethod ="timeoutFallback")
@GetMapping("/hystrix/timeout1")
public String queryOrderTimeout1(){
return restTemplate.getForObject("http://localhost:8082/orders",String.class);
}
public String timeoutFallback(){
return "超时被降级";
}
/**
* 调用http://localhost:8082/orders
*
*/
@RestController
public class OrderServiceImpl implements OrderService{
@Override
public String orders() {
try {
//伪代码,睡眠2s
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Return All Orders";
}
@Override
public int insert(OrderDto dto) {
return 1;
}
}
修改接口超时间时间可以在user调用方修改yml 文件:
hystrix:
command:
default: #全局配置, feignclient#method(param)
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 1000 #命令执行超时时间,默认1000ms,调接口响应时间超1S执行降级,不管提供者是否挂机还是延迟超过时间就走降级
资源隔离触发降级
线程池隔离(默认是线程池隔离)
@HystrixCommand(
groupKey="order-service",
commandKey = "queryOrder",
threadPoolKey="order-service",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),//线程池大小
@HystrixProperty(name = "maxQueueSize", value = "100"),//最大队列长度
@HystrixProperty(name = "keepAliveTimeMinutes", value ="2"),//线程存活时间
@HystrixProperty(name = "queueSizeRejectionThreshold", value= "15")//拒绝请求
},
fallbackMethod = "fallback")
信号量隔离
/**
* 信号量隔离实现
* 不会使用Hystrix管理的线程池处理请求。使用容器(Tomcat)的线程处理请求逻辑。
* 不涉及线程切换,资源调度,上下文的转换等,相对效率高。
* 信号量隔离也会启动熔断机制。如果请求并发数超标,则触发熔断,返回fallback数据。
* commandProperties - 命令配置,HystrixPropertiesManager中的常量或字符串来配置。
* execution.isolation.strategy - 隔离的种类,可选值只有THREAD(线程池隔离)和 SEMAPHORE(信号量隔离)。
* 默认是THREAD线程池隔离。
* 设置信号量隔离后,线程池相关配置失效。
* execution.isolation.semaphore.maxConcurrentRequests - 信号量最大并发数。默认值是10。常见配置500~1000。
* 如果并发请求超过配置,其他请求进入fallback逻辑。
*/
@HystrixCommand(fallbackMethod="semaphoreQuarantineFallback",
commandProperties={
@HystrixProperty(
name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,value="SEMAPHORE"), // 信号量隔离
@HystrixProperty(
name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,value="100") // 信号量最大并发数
}
在配置文件中配置单个接口的信号量隔离和线程池隔离
hystrix:
command:
default: #全局配置, feignclient#method(param)
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 3000 #命令执行超时时间,默认1000ms,调接口响应时间超过2S就执行降级,不管提供者是否挂机还是延迟超过时间就走降级
OrderServiceFeignClient#orders():
execution:
isolation:
strategy: SEMAPHORE
semaphore:
maxConcurrentRequests: 10
OrderServiceFeignClient#insert():
execution:
isolation:
strategy: THREAD
threadpool:
order-service:
coreSize: 2
maxQueueSize: 1000
queueSizeRejectionThreshold: 800
五. Fegin集成Hystirx
HystrixFeignController
@RestController
public class HystrixFeignController {
@Autowired
OrderServiceFeignClient orderServiceFeignClient;
@GetMapping("/hystrix/feign/order")
public String queryOrder(){
return orderServiceFeignClient.orders();
}
@PostMapping("/hystrix/feign/order")
public String insertOrder(){
OrderDto orderDto=new OrderDto();
orderDto.setOrderId("GP0001");
return orderServiceFeignClient.insert(orderDto)>0?"SUCCESS":"FAILED";
}
}
OrderServiceFeignClient
在@FeignClient注解里边配置fallback接口的降级方法
@FeignClient(value = "order-service",fallback = OrderServiceFeignClient.OrderServiceFeignClientFallback.class)
public interface OrderServiceFeignClient extends OrderService{
@Component
class OrderServiceFeignClientFallback implements OrderServiceFeignClient{
@Override
public String orders() {
System.out.println("查询订单失败,请稍候重试");
return "查询订单失败,请稍候重试";
}
@Override
public int insert(OrderDto dto) {
System.out.println("insert失败");
return -1;
}
}
}
public interface OrderService {
@GetMapping("/orders")
String orders();
@PostMapping("/order")
int insert(OrderDto dto);
}
@RestController
public class OrderServiceImpl implements OrderService{
@Override
public String orders() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Return All Orders");
return "Return All Orders";
}
@Override
public int insert(OrderDto dto) {
return 1;
}
}
application.yml
hystrix:
command:
default: #全局配置, feignclient#method(param)
execution:
timeout:
enable: true
isolation:
thread:
timeoutInMilliseconds: 2000 #命令执行超时时间,默认1000ms,调接口响应时间超过2S就执行降级,不管提供者是否挂机还是延迟超过时间就走降级
OrderServiceFeignClient#orders(): # 单独配置 feignclient#method(param)
execution:
isolation:
strategy: SEMAPHORE # 信号量隔离
semaphore:
maxConcurrentRequests: 10
OrderServiceFeignClient#insert():
execution:
isolation:
strategy: THREAD # 线程池隔离
threadpool:
order-service:
coreSize: 2
maxQueueSize: 1000
queueSizeRejectionThreshold: 800
信号量隔离测试
用Jmeter压测,1s中发送50个请求
在Order-service中只有10个请求是成功的,其他都走降级策略