安阳天气:源码剖析 Sentinel 之 Dubbo 适配原理

admin 3个月前 (04-13) 科技 7 0

在Alibaba Sentinel 限流与熔断初探(技巧篇) 的示例中我选择了 sentinel-demo-APache-dubbo 作为突破点,故本文就从该项目入手,看看 Sentinel 是若何对 Dubbo 做的适配,让项目使用方无感知,只需要引入对应的依即可。

sentinel-apache-dubbo-adapter 比较简单,睁开如下:

上面的代码应该比较简单,在正式进入源码研究之前,我先抛出如下二个问题

  • 1、限流、熔断相关的功效是在 Dubbo 的客户端实现照样服务端实现?为什么?
  • 2、若何对 Dubbo 举行功效扩展而无需改动营业代码?

Dubbo 提供了 Filter 机制对功效举行无缝扩展,有关 Dubbo Filter 机制,人人可以查阅笔者的源码研究 Dubbo 系列:Dubbo Filter机制概述。

接下来我们带着上面的问题1最先本章的研究。

@

目录
  • 1、源码剖析 SentinelDubboConsumerFilter
  • 2、源码剖析 SentienlDubboProviderFilters
  • 3、Sentienl Dubbo FallBack 机制
  • 4、总结

1、源码剖析 SentinelDubboConsumerFilter

@Activate(group = "consumer")   // @1
public class SentinelDubboConsumerFilter implements Filter {

    public SentinelDubboConsumerFilter() {
        RecordLog.info("Sentinel Apache Dubbo consumer filter initialized");
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RPCException {
        Entry interfaceEntry = null;
        Entry methodEntry = null;
        try {
            String resourceName = DubboUtils.geTresourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix());   // @2
            interfaceEntry = SphU.entry(invoker.getInterface().getName(),
                ResourceTypeConstants.COMMON_RPC, EntryType.OUT);     // @3
            methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);    // @4

            Result result = invoker.invoke(invocation);            // @5
            if (result.hasException()) {                                     // @6
                Throwable e = result.getException();
                // Record common exception.
                Tracer.traceEntry(e, interfaceEntry);
                Tracer.traceEntry(e, methodEntry);
            }
            return result;
        } catch (BlockException e) {        
            return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e);  // @7
        } catch (RpcException e) {    
            Tracer.traceEntry(e, interfaceEntry);
            Tracer.traceEntry(e, methodEntry);
            throw e;
        } finally {
            if (methodEntry != null) {   // @8
                methodEntry.exit();
            }
            if (interfaceEntry != null) {
                interfaceEntry.exit();
            }
        }
    }
}

代码@1:通过 @Activate 注解界说该 Filter 在客户端生效。

代码@2:在 Sentinel 中一个异常焦点的观点就是资源,即要界说限流的目的,当泛起什么异常(匹配用户设置的规则)对什么举行熔断操作,Dubbo 服务中的资源通常是 Dubbo 服务,分为服务接口级或方式级,故该方式返回 Dubbo 的资源名,其主要实现特征如下:

  • 若是启用用户界说资源的前缀,默以为 false ,可以通过设置属性:csp.sentinel.dubbo.resource.use.prefix 来界说是否需要启用前缀。若是启用前缀,消费端的默认前缀为 dubbo:consumer:,可以通过设置属性 csp.sentinel.dubbo.resource.consumer.prefix 来自界说消费端的资源前缀。
  • Dubbo 资源的名称示意方式为:interfaceName + ":" + methodName + "(" + "paramTyp1参数列表,多个用 , 离隔" + ")"。

代码@3:挪用 Sentinel 焦点API SphU.entry 进入 Dubbo InterfaceName。从方式的名称我们也能很容易的明白,就是使用 Sentienl API 进入资源名为 Dubbo 接口提供者类全路径限命名,即以为挪用该方式,Sentienl 会网络该资源的挪用信息,然后Sentinel 凭据运行时网络的信息,再配合限流规则,熔断等规则举行盘算是否需要限流或熔断。本节我们不计划深入研究 SphU 的焦点方式研究,先开端领会该方式:

  • String name 资源的名称。

  • int resourceType 资源的类型,在 Sentinel 中现在界说了 如下五中资源:

    • ResourceTypeConstants.COMMON
      同样类型。
    • ResourceTypeConstants.COMMON_WEB
      WEB 类资源。
    • ResourceTypeConstants.COMMON_RPC
      RPC 类型。
    • ResourceTypeConstants.COMMON_API_GATEWAY
      接口网关。
    • ResourceTypeConstants.COMMON_DB_SQL
      数据库 SQL 语句。
  • EntryType type
    进入资源的方式,主要分为 EntryType.OUT、EntryType.IN,只有 EntryType.IN 方式才能对资源举行壅闭。

代码@4:挪用 Sentinel 焦点API SphU.entry 进入 Dubbo method 级别。

代码@5:挪用 Dubbo 服务提供者方式。

代码@6:若是泛起挪用异常,可以通过 Sentinel 的 Tracer.traceEntry 跟踪本次挪用资源进入的情形,详细 API 将在该系列的后续文章中详细先容。

代码@7:若是是由于触发了限流、熔断等操作,抛出了壅闭异常,可通过 注册 ConsumerFallback 来实现消费者快速失败,将在下文详细先容。

代码@8: SphU.entry 与 资源的 exit 方式需要成对泛起,否则会泛起统计错误。

2、源码剖析 SentienlDubboProviderFilters

@Activate(group = "provider")
public class SentinelDubboProviderFilter implements Filter {
    public SentinelDubboProviderFilter() {
        RecordLog.info("Sentinel Apache Dubbo provider filter initialized");
    }
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // Get origin caller.
        String application = DubboUtils.getApplication(invocation, "");
        Entry interfaceEntry = null;
        Entry methodEntry = null;
        try {
            String resourceName = DubboUtils.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix());   // @1
            String interfaceName = invoker.getInterface().getName();
            // Only need to create entrance context at provider side, as context will take effect
            // at entrance of invocation chain only (for iNBound traffic).
            ContextUtil.enter(resourceName, application);
            interfaceEntry = SphU.entry(interfaceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);  // @2
            methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC,
                EntryType.IN, invocation.getArguments());
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                Throwable e = result.getException();
                // Record common exception.
                Tracer.traceEntry(e, interfaceEntry);
                Tracer.traceEntry(e, methodEntry);
            }
            return result;
        } catch (BlockException e) { 
            return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);   // @3
        } catch (RpcException e) {
            Tracer.traceEntry(e, interfaceEntry);
            Tracer.traceEntry(e, methodEntry);
            throw e;
        } finally {
            if (methodEntry != null) {
                methodEntry.exit(1, invocation.getArguments());
            }
            if (interfaceEntry != null) {
                interfaceEntry.exit();
            }
            ContextUtil.exit();
        }
    }
}

Dubbo 服务提供者与消费端的适配套路差不多,这里就重点论述一下其不同点。
代码@1:若是启用前缀,默认服务提供者的资源会加上前缀:dubbo:provider:,可以通过在设置文件中设置属性 csp.sentinel.dubbo.resource.provider.prefix 改变其默认值。

代码@2:服务端挪用 SphU.entry 时其进入类型为 EntryType.IN。

代码@3:同样可以在 抛出壅闭异常(BlockException) 时指定快速失败回调处置逻辑。

3、Sentienl Dubbo FallBack 机制

Sentinel Dubbo FallBack 机制比较简单,就是提供一个全局的 FallBack 回调,可以划分为服务提供端,服务消费端指定。只需实现 DubboFallback 接口,其声明如下:

然后需要挪用 DubboFallbackRegistry 的 setConsumerFallback 和 setProviderFallback 方式划分注册消费端,服务端相关的监听器。通常只需要在启动应用的时刻,将其举行注册即可。

4、总结

本文只是以 Sentienl 对 Dubbo 的适配实现来领会 Sentinel 焦点相关的 API,其焦点实现就是行使 Dubbo 的 Filter 机制举行无缝的过滤阻挡。但本文只是提到 Sentinel 如下焦点方式:

  • SphU.entry
  • Entry.exit
  • Tracer.traceEntry

上述这些方式,将在后面的文章中举行深入探讨,即从下一篇文章最先,我们将真正进入 Sentinel 的天下中,让我们一探讨竟限流、熔断通常是若何实现的。

本文就先容到这里了,点赞是一种美德,您的点赞是我连续分享的最大动力,谢谢。

推荐阅读:源码剖析 Alibaba Sentinel 专栏。
1、Alibaba Sentinel 限流与熔断初探(技巧篇)

作者信息:丁威,《RocketMQ手艺内幕》作者,现在担任中通科技手艺平台部资深架构师,维护 中间件兴趣圈民众号,现在主要揭晓了源码阅读jAVa聚集、JUC(java并发包)、Netty、ElasticJob、Mycat、Dubbo、RocketMQ、mybaits等系列源码。点击链接:加入笔者的知识星球,一起探讨高并发、分布式服务架构,分享阅读源码心得。

,

进入sunbet官网手机版登陆

欢迎进入sunbet官网手机版登陆!Sunbet 申博提供申博开户(sunbet开户)、SunbetAPP下载、Sunbet客户端下载、Sunbet代理合作等业务。

Sunbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:安阳天气:源码剖析 Sentinel 之 Dubbo 适配原理

网友评论

  • (*)

最新评论

标签列表

    文章归档

      站点信息

      • 文章总数:559
      • 页面总数:0
      • 分类总数:8
      • 标签总数:932
      • 评论总数:186
      • 浏览总数:4594