轻重接口隔离

7854635047b1187b81597fcf3102660c.png

名词约定

1、轻重接口

轻接口=轻量级接口,运行时间短,性能高,对服务器资源(内存、CPU、数据库)占用少;

重接口=重量级接口,运行时间长,性能差,对服务器资源(内存、CPU、数据库)占用多;

2、隔离

隔离是指通过技术手段使两个本来相互竞争资源的接口,在线程资源占用、内存资源占用、CPU资源、容器占用上达到互不影响的效果

背景

在容器化部署环境中,对单个容器的资源占用有上限控制,超限后容器可被自动销毁或者重启。

引起单个容器资源超限的原因一般是由于 重量级接口 、批量操作引起,随着容器的重启,容器上原本正在的运行的线程(轻重线程混合在一起)全部被终止销毁,这就导致一种现象:某一个客户的一个重量级请求影响了其它几百个客户的轻量级请求,客户端的表现就是多处功能响应缓慢,而不单单是那个重量级功能。

这就是轻重分离的需求所在。

解决方案

轻重接口隔离的解决有几种方案:

方案1:代码的拆分和独立部署

重接口的独立,将重接口的代码拆分到另一个独立的工程或者叫微服务中,从而实现部署和资源占用的独立。

优点:

未来代码可维护性好,天然部署隔离

缺点:

1、有一定工作量,代码的改动、关联服务的改动;

2、复杂接口的依赖接口是否都需要代码拆分,这是有难度的,可能造成微服务爆炸,甚至不可行的;

适合场景:

1、适合内聚性非常高的接口,对其它接口依赖少或者无依赖的功能

4e62a27db89d82a87b1db7ecc326c83d.png

方案2:运行时的隔离

运行时的隔离指的是业务代码不做拆分,通过运行时将不同的请求路由到不同的实例上,从而实现资源占用的独立。

优点:

技术手段,无需业务代码改动,快速解决问题

缺点:

可能存在类似于单体应用的缺点

适用场景:

任何场景,尤其适合人员少、业务复杂、依赖关系复杂、不愿意动代码 的隔离场景

6df809cadfd4f3efa6ecfd68b9ba3887.png

本次老吕要讲述的是方案2如何通过技术手段实现运行时的隔离

运行时的隔离方案的实现

整体思路是在提供者端打标签,在消费者端做路由策略实现,如下图:

e091a7eb28b62a8be45f0565599f75c9.png

1、对微服务进行运行时打标签(增加环境变量)

2、RPC路由策略的实现

3、对请求进行打标,可做成动态配置的,随时将请求调度到指定服务上

在Dubbo中实现轻重分离的步骤:

1、对服务提供者进行标签化配置,比如增加 tagMethod=weight 环境变量

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

通过这个步骤的配置,可以使Dubbo的提供者带上特有的参数(我把它称为标签),这个特有的参数会自动带入到注册中心的,最终可以被消费者端获取

2、实现Dubbo轻重分离路由策略

Router接口的实现(大家可以按需修改)

/**
 * 1、带tagMethod标签的请求优先路由到"带tagMethod且标签内容相同的服务实例"上
 * 2、不带tagMethod标签的请求路由到"不带tagMethod标签的服务实例"上
 * 3、如果带tagMethod标签的请求严格匹配服务提供者失败,则降级到"不带tagMethod标签的服务实例"上(或者降级到"带tagMethod标签但内容不同的实例上")
 * 4、如果不带tagMethod标签的请求匹配不带标签的服务提供者失败,则降级到"带tagMethod标签的任意服务实例"上
 * 5、也就是说:无论何种情况下只要有服务提供者实例存在,请求一定能找到一个提供者来用。
 * @param invokers
 * @param url
 * @param invocation
 * @param <T>
 * @return
 * @throws RpcException
 */
@Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
    if (!enable) {
        return invokers;
    }
    logger.info("method router");
    if (invokers == null && invokers.size() == 0){
        return invokers;
    }
    try {
        //获取需要自定义路由的tag
        String consumerMethodTag = TraceUtil.getTags().getTagMethod();
        List<Invoker<T>> result = new ArrayList();
        Iterator iterator = invokers.iterator();
        while(iterator.hasNext()) {
            Invoker<T> invoker = (Invoker)iterator.next();
            URL invokerUrl = invoker.getUrl();
            //获取提供者携带的mytag参数
            String providerMethodTag = invokerUrl.getParameter(RouterTags.TAG_METHOD);
            if ("".equals(providerMethodTag)) {
                providerMethodTag = null;
            }
            if(consumerMethodTag==null&&providerMethodTag==null){
                //轻请求走轻通道
                result.add(invoker);
            }else if (consumerMethodTag!=null&&providerMethodTag!=null&&providerMethodTag.equals(consumerMethodTag)) {
                //重请求走重通道
                result.add(invoker);
            }
        }
        if (result.size()==0) {
            //没有合适的通道则走任意通道(车道借用)
            return invokers;
        }else{
            //匹配到了合适的通道
            return result;
        }
    } catch (Throwable e) {
        logger.error("method router 异常:"+e.getMessage());
        return invokers;
    }


}

RouterFactory接口的实现(略)

通过这个步骤就实现了消费者端的路由策略

3、配置中心增加要分离的接口配置

这个就随意定义了,怎么喜欢怎么来,比如配置格式如下:标签:url1,url2,url3    例如:

weight:/v1/edf/importaccount/import,/v1/edf/user/login,/v1/cw/reportBatchPrint/getPrintDataAsync

这样就把那三个url会被路由到带weight标签的服务提供者上;

记着DB配置中的tagMethod值和k8s环境变量设置的tagMethod需要保持一致;

4、支持同时配置多个不同的tagMethod

比如又增加了tagMethod=light的标签。则配置格式如下:

weight:url1,url2,url3;

light:url4,url5,url6

5、请求识别、请求打标、RPC时标签传递

1)当请求进入网关后在拦截器中识别url,根据配置中心的配置决定是否打标,打什么标

2)打上标后,绑定到请求线程上,RPC时要带过去,这个都知道,弄个Dubbo过滤器就解决了

3)请求结束后把标清理下

以上就是实现步骤,可动态配置,还是挺方便的,性能考虑记着配置信息做下缓存,非关键代码我就不贴了,思路我都写清楚了,大家有不明白的可以公众号联系我

总结

看过我文章的都知道我之前写过好几篇关于Dubbo路由的文章,

Dubbox 2.8.4 的一种分布式开发调试方案

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

k8s环境中dubbo故障容器自动隔离功能的实现

它们的实现思路是类似的,都是对Dubbo路由策略的定制,感兴趣的朋友可以试一试你想要的路由策略。

隔离不单单用在今天老吕提到的场景下,它是一种思想、一种方法论,可以用在很多场景:

1、按请求渠道隔离服务:如移动端、PC端的请求路由到不同的服务上;

2、按用户所在区域隔离服务:如按省市区域的分离,同一个省的路由到带同一个标签的服务上

3、整个集群被隔离为多个分片,便于灰度发布、AB测试

4、按所在数据库分片的隔离,这可以做到按数据库分片灰度发布了

今天就到这里,觉得有用的给老吕点个看一看赞一赞。

706bf4a52cec8c44e928fa0b78ccf969.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吕哥架构

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

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

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

打赏作者

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

抵扣说明:

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

余额充值