【Spring Cloud Alibaba】Hystrix 服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
1 Hystrix 三种模式
Hystrix的断路器模式和后备策略模式
Hystrix的舱壁模式
可以通过为各个服务分别指定线程池
2 熔断使用
2.1 注解的方式
编写测试服务OrderServiceImpl ,睡眠被调用功能
package cn.flowboot.e.commerce.service.impl;
import cn.flowboot.e.commerce.service.OrderService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <h1></h1>
*
* @version 1.0
* @author: Vincent Vic
* @since: 2022/03/06
*/
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
/**
* 订单列表
* 测试
* @return
*/
@Override
public List<Map<String, Object>> list() {
Map<String, Object> map = Maps.newHashMap();
map.put("orderNo","1234567890");
log.info("now time : {}", LocalDateTime.now());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("now time : {}", LocalDateTime.now());
return Lists.newArrayList(map);
}
}
编写用于测试熔断的的中间服务,使用@HystrixCommand 注解,
package cn.flowboot.e.commerce.hystrix;
import cn.flowboot.e.commerce.service.OrderService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* <h1> 使用 HystrixCommand 注解 </h1>
*
* @version 1.0
* @author: Vincent Vic
* @since: 2022/03/06
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UseHystrixCommandAnnotation {
private final OrderService orderService;
@HystrixCommand(
// 用于对 Hystrix 命令进行分组, 分组之后便于统计展示于仪表盘、上传报告和预警等等
// 内部进行度量统计时候的分组标识, 数据上报和统计的最小维度就是 groupKey
groupKey = "OrderService",
// HystrixCommand 的名字, 默认是当前类的名字, 主要方便 Hystrix 进行监控、报警等
commandKey = "OrderService",
// 舱壁模式
threadPoolKey = "OrderService",
// 后备模式
fallbackMethod = "listFallback",
// 断路器模式
commandProperties = {
// 超时时间, 单位毫秒, 超时进 fallback
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500"),
// 判断熔断的最少请求数, 默认是10; 只有在一定时间内请求数量达到该值, 才会进行成功率的计算
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
// 熔断的阈值默认值 50, 表示在一定时间内有50%的请求处理失败, 会触发熔断
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"),
},
// 舱壁模式
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),
@HystrixProperty(name = "maxQueueSize", value = "101"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
// 在时间窗口中, 收集统计信息的次数; 在 1440ms 的窗口中一共统计 12 次
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
// 时间窗口, 从监听到第一次失败开始计时
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
}
)
public List<Map<String,Object>> list() {
log.info("use hystrix command annotation to order list: [{}]",
Thread.currentThread().getName());
return orderService.list();
}
/**
* <h2>list的兜底策略 - Hystrix 后备模式</h2>
* */
public List<Map<String,Object>> listFallback() {
log.warn("trigger hystrix fallback: [{}]",
Thread.currentThread().getName());
return Collections.emptyList();
}
}
编写Controller测试
@Autowired
private UseHystrixCommandAnnotation useHystrixCommandAnnotation;
@GetMapping("/list")
public List<Map<String,Object>> list(){
log.info("Hystrix Command test");
return useHystrixCommandAnnotation.list();
}
由于服务中休眠3秒而熔断策略中限制在1.5s,所以请求会触发后备策略
2.2 编程的方式
OrderService 实现包装-线程池的方式
package cn.flowboot.e.commerce.hystrix;
import cn.flowboot.e.commerce.service.OrderService;
import com.netflix.hystrix.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* <h1> OrderService 实现包装</h1>
* Hystrix舱壁模式:
* 1。线程池
* 2.信号量 : 有限信号机
* @version 1.0
* @author: Vincent Vic
* @since: 2022/03/06
*/
@Slf4j
@Service
public class OrderHystrixCommand extends HystrixCommand<List<Map<String,Object>>> {
private final OrderService orderService;
protected OrderHystrixCommand(OrderService orderService) {
super(Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey("OrderService"))
.andCommandKey(HystrixCommandKey.Factory.asKey("OrderHystrixCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("OrderClientPool"))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD) //线程池隔离策略
.withFallbackEnabled(true)
.withCircuitBreakerEnabled(true)
)
);
//可以配置信号量隔离策略
// Setter semaphore = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("OrderService"))
// .andCommandKey(HystrixCommandKey.Factory.asKey("OrderHystrixCommand"))
// .andCommandPropertiesDefaults(
// HystrixCommandProperties.Setter()
// .withCircuitBreakerRequestVolumeThreshold(10)
// .withCircuitBreakerSleepWindowInMilliseconds(5000)
// .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
// );
this.orderService = orderService;
}
/**
* Implement this method with code to be executed when {@link #execute()} or {@link #queue()} are invoked.
*
* @return R response type
* @throws Exception if command execution fails
*/
@Override
protected List<Map<String, Object>> run() throws Exception {
log.info("hystrix command to Get Order List: [{}]",
Thread.currentThread().getName());
return orderService.list();
}
/**
* If {@link #execute()} or {@link #queue()} fails in any way then this method will be invoked to provide an opportunity to return a fallback response.
* <p>
* This should do work that does not require network transport to produce.
* <p>
* In other words, this should be a static or cached result that can immediately be returned upon failure.
* <p>
* If network traffic is wanted for fallback (such as going to MemCache) then the fallback implementation should invoke another {@link HystrixCommand} instance that protects against that network
* access and possibly has another level of fallback that does not involve network access.
* <p>
* DEFAULT BEHAVIOR: It throws UnsupportedOperationException.
*
* @return R or throw UnsupportedOperationException if not implemented
*/
@Override
protected List<Map<String, Object>> getFallback() {
log.warn("trigger hystrix fallback: [{}]",
Thread.currentThread().getName());
return Collections.emptyList();
}
}
测试,有四种调用方式
/**
* <h2> executeList - 测试编程方式服务熔断<h2>
* version: 1.0 - 2022/3/6
* @return {@link List< Map< String, Object>> }
*/
@GetMapping("/execute/list")
public List<Map<String,Object>> executeList(){
log.info("Hystrix Command test");
return orderHystrixCommand.execute();
}
/**
* <h2> queueList - 测试编程方式服务熔断 - 采用异步<h2>
* version: 1.0 - 2022/3/6
* @param
* @return {@link List< Map< String, Object>> }
*/
@GetMapping("/queue/list")
public List<Map<String,Object>> queueList() throws ExecutionException, InterruptedException {
log.info("queue Hystrix Command test");
Future<List<Map<String, Object>>> future = orderHystrixCommand.queue();
//异步执行,这里可以进行其他操作
return future.get();
}
/**
* <h2> observeList - 测试编程方式服务熔断 - 热响应调用<h2>
* version: 1.0 - 2022/3/6
* @param
* @return {@link List< Map< String, Object>> }
*/
@GetMapping("/observe/list")
public List<Map<String,Object>> observeList() throws ExecutionException, InterruptedException {
log.info("observe Hystrix Command test");
Observable<List<Map<String, Object>>> observe = orderHystrixCommand.observe();
//异步执行,这里可以进行其他操作
return observe.toBlocking().single();
}
/**
* <h2> toObservableList - 测试编程方式服务熔断 - 冷响应调用<h2>
* version: 1.0 - 2022/3/6
* @param
* @return {@link List< Map< String, Object>> }
*/
@GetMapping("/observe/list")
public List<Map<String,Object>> toObservableList() throws ExecutionException, InterruptedException {
log.info("toObservable Hystrix Command test");
Observable<List