sentinel源码分析第三篇一sentinel-adapter模块一第一章dubbo

adapter模块概述

  • adapter模块负责集成常用流量请求框架
  • adapter模块负责对常见框架进行适配
  • 构建类似Spring-AOP功能.实现流量拦截,sentinel核心限流逻辑处理
  • 针对不同框架的适配协议各不相同
  • dubbo采用filter作为代理位点,完成限流增强逻辑

源码分析一filter

  • sentinel通过dubbo的过滤器扩展点完成流量管控

org.apache.dubbo.rpc.Filter

filter名称class类作用
sentinel.dubbo.provider.filtercom.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter提供者流量控制
sentinel.dubbo.consumer.filtercom.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter消费者流量控制
dubbo.application.context.name.filtercom.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter为invocation会话对象所在RpcContext上下文设置attachment附件 附件内容为applicationName

1-DubboAppContextFilter

  • 获取invoker执行体对象的applicationName
  • 放置到当前会话上下文附件中

@Activate(group = CONSUMER)
public class DubboAppContextFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        获取invoker执行体对象的applicationName
        String application = invoker.getUrl().getParameter(CommonConstants.APPLICATION_KEY);
        if (application != null) {
            放置到当前会话上下文附件中
            RpcContext.getContext().setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, application);
        }
        return invoker.invoke(invocation);
    }
}

2-BaseSentinelDubboFilter

  • dubbo从两个维度进行资源限流,该类定义资源获取的相关方法
  • 接口维度
  • 方法维度
public abstract class BaseSentinelDubboFilter implements Filter {
    获取方法名
    abstract String getMethodName(Invoker invoker, Invocation invocation, String prefix);
    获取接口名
    abstract String getInterfaceName(Invoker invoker, String prefix);
}

在这里插入图片描述

2.1-限流逻辑SentinelDubboConsumerFilter

EntryType为OUT类型

  • 通过filter.invoke进入限流
  • 根据dubbo接口信息获取方法和接口两个维度资源名,对两个维度限流
  • SphU.entry完成限流处理
  • 未限流则执行rpc调用
  • Entry.exit完成entry链当前节点出栈

@Activate(group = CONSUMER)
public class SentinelDubboConsumerFilter extends BaseSentinelDubboFilter {
    ...... 删除其他代码
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        限流入口
        InvokeMode invokeMode = RpcUtils.getInvokeMode(invoker.getUrl(), invocation);
        同步调用限流入口
        if (InvokeMode.SYNC == invokeMode) {
            return syncInvoke(invoker, invocation);
        } else {
            ......异步调用限流入口 
            return asyncInvoke(invoker, invocation);
        }
    }

    private Result syncInvoke(Invoker<?> invoker, Invocation invocation) {
        Entry interfaceEntry = null;
        Entry methodEntry = null;
        String prefix = DubboAdapterGlobalConfig.getDubboConsumerResNamePrefixKey();
        获取接口名
        String interfaceResourceName = getInterfaceName(invoker, prefix);
        获取方法名
        String methodResourceName = getMethodName(invoker, invocation, prefix);
        try {
            相同的contextName interfaceEntry和methodEntry 意味着相同的entranceNode 
            注意资源名不同 则限流统计数据容器不同
            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT,
                invocation.getArguments());
            rpc调用
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                Tracer.traceEntry(result.getException(), interfaceEntry);
                Tracer.traceEntry(result.getException(), methodEntry);
            return result;
        } catch (BlockException e) {
            被限流
            return DubboAdapterGlobalConfig.getConsumerFallback().handle(invoker, invocation, e);
        } catch (RpcException e) {
            标记异常信息
            Tracer.traceEntry(e, interfaceEntry);
            Tracer.traceEntry(e, methodEntry);
            throw e;
        } finally {
            注意exit 使用节点出栈桢
            if (methodEntry != null) {
                methodEntry.exit(1, invocation.getArguments());
            }
            if (interfaceEntry != null) {
                interfaceEntry.exit();
            }
        }
    }
}

2.2-限流逻辑SentinelDubboProviderFilter

EntryType为IN类型

  • 外部构建Context,创建EntranceNode
  • 限流逻辑处理
  • 触发限流 处理响应
  • 否则,rpc远程调用
  • 处理rpc异常
  • entry出栈
Activate(group = PROVIDER)
public class SentinelDubboProviderFilter extends BaseSentinelDubboFilter {
    ...... 删除其他代码
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(invoker, invocation);
        if (null == origin) {
            origin = "";
        }
        Entry interfaceEntry = null;
        Entry methodEntry = null;
        String prefix = DubboAdapterGlobalConfig.getDubboProviderResNamePrefixKey();
        String interfaceResourceName = getInterfaceName(invoker, prefix);
        String methodResourceName = getMethodName(invoker, invocation, prefix);
        try {
            Only need to create entrance context at provider side, as context will take effect
            at entrance of invocation chain only (for inbound traffic).
            翻译: 只需要在提供者端创建相关名称的context 对应创建相关entranceNode,因为context仅在调用链入口处生效(用于入站流量)。
           
            理解:Provider采用外部创建context,context name为methodResourceName  consumer采用内置创建context
            相应的对象的EntranceNode不同,也就是说提供者独占EntranceNode,消费者因为contextName为默认名称,所以共享EntranceNode
            ContextUtil.enter(methodResourceName, origin);
            限流逻辑
            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN,
                invocation.getArguments());
            rpc远程调用
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                Tracer.traceEntry(result.getException(), interfaceEntry);
                Tracer.traceEntry(result.getException(), methodEntry);
            }
            return result;
        } catch (BlockException e) {
            触发限流 处理响应
            return DubboAdapterGlobalConfig.getProviderFallback().handle(invoker, invocation, e);
        } catch (RpcException e) {
            记录异常
            Tracer.traceEntry(e, interfaceEntry);
            Tracer.traceEntry(e, methodEntry);
            throw e;
        } finally {
            entry出栈
            if (methodEntry != null) {
                methodEntry.exit(1, invocation.getArguments());
            }
            if (interfaceEntry != null) {
                interfaceEntry.exit();
            }
            ContextUtil.exit();
        }
    }
}

总结

  • Adapter负责桥接所有需要限流的通信框架
  • dubbo适配器基于filter接入sentinel限流功能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值