dubbo集成netflix原生的hystrix框架

版权声明:Mr_Iron_Hand原创    https://blog.csdn.net/kailuan2zhong/article/details/81367106
一、需求描述
需要将一个现有项目添加熔断功能,而这个项目的技术栈为spring、dubbo等,并且使用的dubbo-Main方式启动。

二、存在问题
由于项目并未使用web容器、也未使用spring-boot。而目前能拿到的资料中,都是在spring-boot下进行hystrix集成的,不得不说spring-boot的开箱即用理念,集成起来真的非常方便。因此,基于当前结构无法快速集成,也就需要开始排坑。

三、解决思路
目前有几个方向来解决问题:
1、当现实情况改造为spring-boot不是上策
2、改造为web容器启动会引入tomcat等组件,运维不一定答应
3、想办法保持dubbo的Main方式启动、spring保留,找办法。

四、开始排坑
前提条件

1、对Hystrix框架要熟悉使用
2、对dubbo框架有一定认知,熟悉Filter使用

四-1、dubbo服务集成Hystrix
找思路

根据3中的方向,需要准备:
1、查看spring-cloud-starter-hystrix中的依赖,决定使用netflix的原生hystrix组件,spring-cloud能打包,我也可以。
2、引入了hystrix-core和hystrix-javanica

测试思路(Hystrix是否生效)

1、注解方式配置@HystrixCommand等,测试接口,发现异常情况下没有进入降级流程。
2、应该是dubbo框架对内部异常进行了封装,导致异常抛出后直接进入了dubbo处理流程
3、定义一个Filter,拦截dubbo的请求,对response进行分析,拿到success/exception,根据这里的结构,进入降级流程。
4、根据3的思路,需要实现HystrixCommand接口,进而在Filter中进行集成。

定义Filter

import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
 
@Activate(group = "consumer")
public class HystrixFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
 
        DubboHystrixCommand command = new DubboHystrixCommand(invoker, invocation, "aaa");
        Result res = command.execute();
        return res;
    }
}

实现HystrixCommand

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcResult;
import com.netflix.hystrix.*;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.util.Map;
 
 
public class DubboHystrixCommand extends HystrixCommand<Result> {
 
    private static Logger logger = LoggerFactory.getLogger(DubboHystrixCommand.class);
    private static final int DEFAULT_THREADPOOL_CORE_SIZE = 30;
    private Invoker invoker;
    private Invocation invocation;
    private String fallbackName;
 
    public DubboHystrixCommand(Invoker<?> invoker, Invocation invocation, String fallbackName) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(invoker.getInterface().getName()))
                .andCommandKey(HystrixCommandKey.Factory.asKey(String.format("%s_%d", invocation.getMethodName(), invocation.getArguments() == null ? 0 : invocation.getArguments().length)))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withCircuitBreakerRequestVolumeThreshold(20)//10秒钟内至少19此请求失败,熔断器才发挥起作用
                        .withCircuitBreakerSleepWindowInMilliseconds(3000)//熔断器中断请求30秒后会进入半打开状态,放部分流量过去重试
                        .withCircuitBreakerErrorThresholdPercentage(50)//错误率达到50开启熔断保护
                        .withExecutionTimeoutEnabled(false)//使用dubbo的超时,禁用这里的超时
                        )
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
                        .withCoreSize(getThreadPoolCoreSize(invoker.getUrl()))));//线程池为30
 
        this.invoker = invoker;
        this.invocation = invocation;
        this.fallbackName = fallbackName;
    }
 
 
    /**
     * 获取线程池大小
     * <dubbo:parameter key="ThreadPoolCoreSize" value="20" />
     *
     * @param url
     * @return
     */
    private static int getThreadPoolCoreSize(URL url) {
        if (url != null) {
            int size = url.getParameter("ThreadPoolCoreSize", DEFAULT_THREADPOOL_CORE_SIZE);
            if (logger.isDebugEnabled()) {
                logger.debug("ThreadPoolCoreSize:" + size);
            }
            return size;
        }
 
        return DEFAULT_THREADPOOL_CORE_SIZE;
 
    }
 
    @Override
    protected Result run() throws Exception {
        Result res = invoker.invoke(invocation);
        if (res.hasException()) {
            throw new HystrixRuntimeException(HystrixRuntimeException.FailureType.COMMAND_EXCEPTION,
                    DubboHystrixCommand.class,
                    res.getException().getMessage(),
                    res.getException(), null);
        }
        return res;
    }
 
    @Override
    protected Result getFallback() {
        if (StringUtils.isEmpty(fallbackName)) {
            //抛出原本的异常
            return super.getFallback();
        }
        return new RpcResult("the dubbo fallback.");
    }
}

注册、使用Filter

hystrixFilter=*****.HystrixFilter

测试结果:可以正常进入降级流程,并且实现熔断功能(熔断、半开、恢复)

<dubbo:service interface="*****.service.HelloService" ref="helloService"  timeout="*****" filter="hystrixFilter">
    <dubbo:method name="say" retries="0" />
    <dubbo:parameter key="ThreadPoolCoreSize" value="30" />
</dubbo:service>

https://blog.csdn.net/kailuan2zhong/article/details/81367106

猜你喜欢

转载自blog.csdn.net/varyall/article/details/82833218