hystrix结合dubbo框架实现服务熔断降级, 保证后台服务稳定性
通过购买性价比高的商品和服务实现消费降级 #生活技巧# #理财规划技巧# #消费降级#
一, 服务稳定性以及熔断降级的意义
需求的多样性, 业务的复杂程度也是不断上升的, 一个接口依赖的服务也会逐步增加, 各个服务的稳定性是需要着重考虑的; 例如一个电商订单场景, 不能因为评论服务异常超时, 而阻止用户浏览该商品的其他信息, 同样的也不能因为用户优惠券服务等这些非核心服务(弱依赖), 异常超时从而阻止用户下订单; 但是网络环境又是不可控的, 有可能在某一段时间内, 由于网络抖动, 请求被拒绝, 或者是高并发的大流量进来, 导致系统资源繁忙(线程池耗尽等), 请求被拒绝. 这时就需要使用熔断降级的方式提供有损服务, 确保核心业务不受影响.
二, 图示演示
一次用户请求过来, 需要后台多个服务A, B....提供支持, 但如果服务A一直失败, 而且服务A还是一个非核心服务(即是一个弱依赖的服务),可以采用熔断降级的方式, 使后续的请求直接走降级逻辑, 返回固定逻辑即可, 确保核心的业务不受到影响.
三, Hystrix框架
要想实现上面描述的过程, 那么hystrix就必须要实现下面这几样功能:
1 服务出现异常, 超时, 能够自动走降级逻辑;
2 当服务的失败率达到阈值时, 能够自动进行熔断;
3 在服务熔断期间, 所有对于该服务的请求, 全部走降级.
4 当服务恢复时, 后续请求能够正常访问该服务.
四, dubbo结合hystrix实现服务的熔断降级
1 通过在<dubbo:reference>下配置自定义<dubbo:parameters>参数, 决定是否启用hystrix
<dubbo:parameter key="isOpen" value="true"/>
@Activate(group = Constants.CONSUMER, order = 10002)
public class DubboHystrixFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String isOpen = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "isOpen");
if (isOpen != null && Boolean.parseBoolean(isOpen)) {
DubboHystrixCommand dubboHystrixCommand = new DubboHystrixCommand(invoker, invocation);
Result result = dubboHystrixCommand.execute();
return result;
} else {
return invoker.invoke(invocation);
}
}
}
2 DubboHystrixCommand继承HystrixCommand类, 并重写其run()和getFallback()方法, 当执行dubboHystrixCommand.execute()时, 就会执行其run()方法, 执行run()方法报异常时, 就会调用getFallback()方法走降级逻辑, 代码如下:
DubboHystrixCommand类构造方法如下: 调用HystrixCommand_Setter()方法配置hystrix熔断的条件属性.
public DubboHystrixCommand(Invoker<?> invoker, Invocation invocation){
super(HystrixCommand_Setter(invoker, invocation));
this.invoker = invoker;
this.invocation = invocation;
this.fallbackName = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "fallback");
;
}
①构造HystrixCommand.Setter
private static HystrixCommand.Setter HystrixCommand_Setter(Invoker<?> invoker, Invocation invocation) {
String key = String.format("%s.%s", invoker.getInterface().getName(), invocation.getMethodName());
if (setterHashMap.containsKey(key)) {
return setterHashMap.get(key);
} else {
setterHashMap.put(key,
HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(invoker.getInterface().getName()))
.andCommandKey(HystrixCommandKey.Factory.asKey(invocation.getMethodName()))
.andCommandPropertiesDefaults(hystrixCommandProperties_Setter(invoker.getUrl(),invocation.getMethodName()))
.andThreadPoolPropertiesDefaults(hystrixThreadPoolProperties_Setter(invoker.getUrl())));
return setterHashMap.get(key);
}
}
②配置hystrixCommandProperties.Setter熔断属性
public static HystrixCommandProperties.Setter hystrixCommandProperties_Setter(URL url, String method) {
return HystrixCommandProperties.Setter()
.withCircuitBreakerSleepWindowInMilliseconds(url.getMethodParameter(method,
"sleepWindowInMilliseconds",
5000))
.withCircuitBreakerErrorThresholdPercentage(url.getMethodParameter(method,
"errorThresholdPercentage",
50))
.withCircuitBreakerRequestVolumeThreshold(url.getMethodParameter(method,
"requestVolumeThreshold",
20))
.withExecutionIsolationThreadInterruptOnTimeout(true)
.withExecutionTimeoutInMilliseconds(url.getMethodParameter(method,
"timeoutInMilliseconds",
1000))
.withFallbackIsolationSemaphoreMaxConcurrentRequests(url.getMethodParameter(method,
"fallbackMaxConcurrentRequests",
50))
.withExecutionIsolationStrategy(getIsolationStrategy(url))
.withExecutionIsolationSemaphoreMaxConcurrentRequests(url.getMethodParameter(method,
"maxConcurrentRequests",
10));
}
③ 配置HystrixThreadPoolProperties.Setter线程池属性
public static HystrixThreadPoolProperties.Setter hystrixThreadPoolProperties_Setter(URL url) {
return HystrixThreadPoolProperties
.Setter()
.withCoreSize(url.getParameter("coreSize",10))
.withAllowMaximumSizeToDivergeFromCoreSize(true)
.withMaximumSize(url.getParameter("maximumSize",20))
.withMaxQueueSize(-1)
.withKeepAliveTimeMinutes(url.getParameter("keepAliveTimeMinutes",1));
}
④ 设置隔离策略
public static HystrixCommandProperties.ExecutionIsolationStrategy getIsolationStrategy(URL url) {
String isolation = url.getParameter("isolation", THREAD);
if (!isolation.equalsIgnoreCase(THREAD) && !isolation.equalsIgnoreCase(SEMAPHORE)) {
isolation = THREAD;
}
if (isolation.equalsIgnoreCase(THREAD)) {
return HystrixCommandProperties.ExecutionIsolationStrategy.THREAD;
} else {
return HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE;
}
}
⑥重写run()方法, 当远程调用异常时, 就会hystrix框架就会调用getFallback()方法执行降级逻辑.
protected Result run() throws Exception {
Result result = invoker.invoke(invocation);
if (result.hasException()) {
throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION,
DubboHystrixCommand.class, result.getException().getMessage(),
result.getException(), null);
}
return result;
}
⑦getFallback()方法, 执行降级逻辑; 基于SPI扩展机制让业务方实现Fallback接口, 执行降级逻辑.
protected Result getFallback() {
if (StringUtils.isEmpty(fallbackName)) {
return super.getFallback();
}
try {
ExtensionLoader<Fallback> loader = ExtensionLoader.getExtensionLoader(Fallback.class);
Fallback fallback = loader.getExtension(fallbackName);
Object value = fallback.invoker();
return new RpcResult(value);
} catch (RuntimeException ex) {
logger.error("fallback failed", ex);
throw ex;
}
}
⑧业务方实现Fallback接口, 执行降级逻辑.
首先创建, META-INF/dubbo/com.xxz.dubbo.fallback.Fallback文件, 并添加其实现类fallbackImpl=com.xxz.dubbo.fallback.FallbackImpl
五, 使用
1 引入依赖
<!-- 引入自定义dubbo-hystrix-filter熔断降级 -->
<dependency>
<groupId>com.xxz</groupId>
<artifactId>dubbo-hystrix-filter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2 实现降级Fallback接口, 如上步骤⑧配置, 实现降级逻辑.
public class FallbackImpl implements Fallback {
@Override
public Object invoker() {
return "返回默认值null";
}
}
3 <dubbo:reference>配置自定义参数
<dubbo:reference id="serviceA" interface="com.xxz.dubbo.ServiceA"
protocol="dubbo" check="false" mock="false"
retries="0">
<dubbo:method name="serviceA" timeout="3000"/>
<dubbo:method name="serviceNum" timeout="2000"/>
<dubbo:parameter key="isOpen" value="true"/>
<dubbo:parameter key="fallback" value="fallbackImpl"/>
<dubbo:parameter key="coreSize" value="10"/>
<dubbo:parameter key="maximumSize" value="20"/>
<dubbo:parameter key="keepAliveTimeMinutes" value="1"/>
<dubbo:parameter key="requestVolumeThreshold" value="5"/>
<dubbo:parameter key="sleepWindowInMilliseconds" value="20000"/>
<dubbo:parameter key="errorThresholdPercentage" value="50"/>
<dubbo:parameter key="timeoutInMilliseconds" value="3000"/>
</dubbo:reference>
六, 结果(基于上面的参数配置)
1 首先在一个统计周期(默认10s), 配置requestVolumeThreshold=5次请求, 有errorThresholdPercentage=50的错误异常率的话, hystrix就会自动熔断, 后续请求直接走降级逻辑getFallback()方法返回默认值.
2 同时, Hystrix也会在sleepWindowInMilliseconds=20000ms(即20s后), 会放入一个请求, 这时hystrix处于一个半开状态, 若这个请求能正常被处理, Hystrix熔断器就会关闭, 否则熔断器就会继续打开, 确保其他请求还是走降级, 从而继续等待下一个sleepWindowInMilliseconds.
七, 综上: 使用Hystrix确实是可以实现刚刚我们在上面描述的这四个功能点.
1 服务出现异常, 超时, 能够自动走降级逻辑;
2 当服务的失败率达到阈值时, 能够自动进行熔断;
3 在服务熔断期间, 所有对该服务的请求, 全部走降级.
4 当服务恢复时, 后续的请求能够正常访问到该服务.
网址:hystrix结合dubbo框架实现服务熔断降级, 保证后台服务稳定性 https://www.yuejiaxmz.com/news/view/504042
相关内容
flask框架本地生活服务平台毕设源码+论文雍和苑微服务:社区生活新体验,揭秘智能化服务背后的故事
基于Spring Boot框架人口老龄化社区服务和管理平台设计与实现
springboot社区服务平台的设计与实现
统一消息推送平台的研发:实现高效、稳定的信息传递服务
美团微服务架构揭秘:如何高效整理与优化服务生态?
springboot毕设服装个性化定制服务平台源码+论文+部署
基于Python实现智能生活服务平台毕设源码
【项目】在线教育平台项目总结
【开源】SpringBoot框架开发智慧社区业务综合平台