通过Dubbo实现微服务级别的资源隔离

需求

为了保障SaaS云服务的稳定性,缩小故障范围,资源隔离或者说故障隔离是一种常用手段。在应用层按照隔离的粒度一般可以分为:线程级别的隔离、服务级别的隔离。

有这么一个功能依赖了第三方的服务B,这个三方服务分布在各个省和地区,我们有一个微服务A封装了和B的通信细节,专门负责和这个三方服务B的通信,其它业务服务只和A服务通信即可。 由于各省接口稳定性不一样,所以就需要有一种隔离机制来应对故障区域,防止A服务的线程资源被故障区域的请求占满,从而影响其它 正常区域接口的访问。

方案

如果使用线程隔离的方案,则如下:

如果使用服务级别的隔离方案,则如下:

今天说下如何通过Dubbo实现服务级别的隔离

实现

服务A是可以处理所有区域的请求的,但是我们为了实现按区域独立部署,实现所谓的隔离就需要给服务A的每个实例打上一个区域的标签,让调用方的请求按照区域流向不同的服务实例,通过Dubbo如何实现呢?

其实挺简单的,我之前写过一篇 关于Dubbo应用的分布式调试方案的文章,实现的思路 大同小异,在服务提供者身上打上标签,通过服务消费者端 自定义Dubbo路由策略去实现。

具体步骤如下:

1、提供者端服务A的每个实例上打上区域编码的标签,有了这个标签才有可能让消费方去按区域编码路由。

具体如何打标签呢,之前也说过了,可以在  provider标签下自定义parameter参数

<dubbo:provider>   
    <dubbo:parameter key="areaCode" value="${areaCode:}"/>
</dubbo:provider>

2、消费者端 自定义路由策略,通过扩展SPI接口 RouterFactory  、Router  即可

public class AreaCodeRouter implements Router {
    private static final Logger logger = LoggerFactory.getLogger(AreaCodeRouter.class);
    private final URL url;


    public AreaCodeRouter (URL url){
        this.url = url;
    }
    @Override
    public URL getUrl() {
        return this.url;
    }


    @Override
    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        if (invokers != null && invokers.size() != 0) {
            try {
                //获取需要自定义路由的areaCode
                String areaCode = TraceUtil.getAreaCode();
                List<Invoker<T>> result = new ArrayList();
                while (true){
                    Iterator iterator = invokers.iterator();
                    while(iterator.hasNext()) {
                        Invoker<T> invoker = (Invoker)iterator.next();
                        URL invokerUrl = invoker.getUrl();
                        //获取提供者携带的AreaCode参数
                        String providerAreaCode = invokerUrl.getParameter("areaCode");
                        if(areaCode ==null){
                             result.add(invoker);
                        }else{
                            //添加所有符合AreaCode内容一致的提供者
                            if (providerAreaCode !=null&&providerAreaCode.equals(areaCode )) {
                                result.add(invoker);
                            }
                        }
                    }
                    if (result.size()==0&&areaCode!=null) {
                        //不存在areaCode内容一致的提供者服务,就不区分区域了,可以走所有的服务
                        areaCode =null;
                    }else{
                        //存在areaCode 对应的提供者服务
                        break;
                    }
                }
                return result;




            } catch (Throwable throwable) {
                logger.error("Failed to execute areaCode  router rule: " + this.getUrl() + ", invokers: " + invokers + ", cause: " + throwable.getMessage(), throwable);
            }
        }


        return invokers;
    }


    @Override
    public int compareTo(Router o) {
        return 0;
    }
}
public class AreaCodeRouterFactory implements RouterFactory {
    @Override
    public Router getRouter(URL url) {
        return new AreaCodeRouter(url);
    }
}

3、消费者端SPI配置

META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.RouterFactory的配置


areaCodeRouterFactory=com.xxx.dubbo.router.AreaCodeRouterFactory

4、消费者端路由策略生效

<dubbo:registry address="xxx"  group="xxx" >
   <dubbo:parameter key="router" value="areaCodeRouterFactory" />
</dubbo:registry> 

5、消费者端areaCode标签的传递

调用方在发起RPC之前,将areaCode参数值绑定到当前线程上(通过ThreadLocal传递),这样在路由策略中才能取出使用

总结

主要利用了Dubbo的自定义传参和参数优先级覆盖机制,才能在消费者端 invoker 的url中获取到 提供者端 自定义的areaCode参数,不得不说Dubbo确实挺强大的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕哥架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值