服务治理-超时熔断
# 一、需求背景
对于一些核心业务,是需要保证其可靠性的,比如支付系统、订单系统等。
这类核心业务存在一个特点,那就是请求量特别大,但是请求存在网络、环境等外在因素,为了不让一些长时间的业务请求拖垮我们整个业务响应,就需要超时熔断
,让超过一定时间阈值的请求熔断返回。
# 二、方案设计
- 使用自定义注解和切面技术,拦截需要被熔断保护的方法
- 拦截到方法后,根据设置的时间阈值进行熔断处理
# 三、实现方案
# 1、自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoHystrix {
/**
* 失败结果 JSON
*/
String returnJson() default "";
/**
* 超时熔断时间阈值
*/
int timeoutValue() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
:标记注解在JVM运行时可见@Target(ElementType.METHOD)
:注解的对象为方法
# 2、服务实现
接口定义
public interface HystrixService {
Object access(ProceedingJoinPoint point, Method method, DoHystrix doHystrix, Object[] args) throws Throwable;
}
接口实现
@Service
public class HystrixServiceImpl extends HystrixCommand<Object> implements HystrixService {
private ProceedingJoinPoint point;
private Method method;
private DoHystrix doHystrix;
public HystrixServiceImpl() {
/*********************************************************************************************
* 置HystrixCommand的属性
* GroupKey: 该命令属于哪一个组,可以帮助我们更好的组织命令。
* CommandKey: 该命令的名称
* ThreadPoolKey: 该命令所属线程池的名称,同样配置的命令会共享同一线程池,若不配置,会默认使用GroupKey作为线程池名称。
* CommandProperties: 该命令的一些设置,包括断路器的配置,隔离策略,降级设置,以及一些监控指标等。
* ThreadPoolProperties:关于线程池的配置,包括线程池大小,排队队列的大小等
*********************************************************************************************/
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GovernKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GovernThreadPool"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10))
);
}
@Override
public Object access(ProceedingJoinPoint point, Method method, DoHystrix doHystrix, Object[] args) throws Throwable {
this.point = point;
this.method = method;
this.doHystrix = doHystrix;
// 设置熔断超时时间
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(doHystrix.timeoutValue()));
return this.execute();
}
@Override
protected Object run() throws Exception {
try {
return point.proceed();
} catch (Throwable throwable) {
return null;
}
}
@Override
protected Object getFallback() {
return JSON.parseObject(doHystrix.returnJson(), method.getReturnType());
}
}
构造函数
:配置启动参数access()
:该方法内部拿到注解信息后,设置超时熔断时间run()
:返回正确方法调用结果getFallback()
:熔断保护时候返回的对象信息
# 3、切面实现
@Aspect
@Component
public class DoHystrixPoint {
@Autowired
private HystrixServiceImpl hystrixService;
@Pointcut("@annotation(me.xu.hystrix.annotation.DoHystrix)")
public void aopPoint() {
}
@Around("aopPoint() && @annotation(doGovern)")
public Object doRouter(ProceedingJoinPoint point, DoHystrix doGovern) throws Throwable {
return hystrixService.access(point, getMethod(point), doGovern, point.getArgs());
}
private Method getMethod(JoinPoint point) throws NoSuchMethodException {
Signature sig = point.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
return point.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
}
# 四、案例测试
# 1、依赖引入
<dependency>
<groupId>me.xu</groupId>
<artifactId>spring-hystrix</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
# 2、控制层调用
@RestController
public class UserController {
private Logger logger = LoggerFactory.getLogger(UserController.class);
/**
* 测试:http://localhost:8081/api/queryUserInfo?userId=aaa
*/
@DoHystrix(timeoutValue = 350, returnJson = "{\"code\":\"1111\",\"info\":\"调用方法超过350毫秒,熔断返回!\"}")
@RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
public UserInfo queryUserInfo(@RequestParam String userId) throws InterruptedException {
logger.info("查询用户信息,userId:{}", userId);
Thread.sleep(1000);
return new UserInfo("wxx:" + userId, 19, "地址");
}
}
- 通过注解的方式,设置了超时熔断的时间350毫秒和返回的结果信息。
- 调用方法的过程中,通过
Thread.sleep(1000)
,让接口调用时间变成,达到时间阈值。
{"code":"1111","info":"调用方法超过350毫秒,熔断返回!","name":null,"age":null,"address":null}
# 参考
上次更新: 2024/06/29, 15:13:44