hystrix结合dubbo框架实现服务熔断降级, 保证后台服务稳定性

发布时间:2024-12-17 23:23

通过购买性价比高的商品和服务实现消费降级 #生活技巧# #理财规划技巧# #消费降级#

一, 服务稳定性以及熔断降级的意义

需求的多样性, 业务的复杂程度也是不断上升的, 一个接口依赖的服务也会逐步增加, 各个服务的稳定性是需要着重考虑的; 例如一个电商订单场景, 不能因为评论服务异常超时, 而阻止用户浏览该商品的其他信息, 同样的也不能因为用户优惠券服务等这些非核心服务(弱依赖), 异常超时从而阻止用户下订单; 但是网络环境又是不可控的, 有可能在某一段时间内, 由于网络抖动, 请求被拒绝, 或者是高并发的大流量进来, 导致系统资源繁忙(线程池耗尽等), 请求被拒绝. 这时就需要使用熔断降级的方式提供有损服务, 确保核心业务不受影响.

二, 图示演示

一次用户请求过来, 需要后台多个服务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框架开发智慧社区业务综合平台

随便看看