源码分析 Sentinel 之 Dubbo 适配原理

简介: 源码分析 Sentinel 之 Dubbo 适配原理

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


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


871d0ab86f2c892f899c407f0ad65291.png

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


  • 1、限流、熔断相关的功能是在 Dubbo 的客户端实现还是服务端实现?为什么?
  • 2、如何对 Dubbo 进行功能扩展而无需改动业务代码?


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


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


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 接口,其声明如下:

3dd0dc7668a750718ea0448584e59f1e.png

然后需要调用 DubboFallbackRegistry 的 setConsumerFallback 和 setProviderFallback 方法分别注册消费端,服务端相关的监听器。通常只需要在启动应用的时候,将其进行注册即可。


4、总结


本文只是以 Sentienl 对 Dubbo 的适配实现来了解 Sentinel 核心相关的 API,其核心实现就是利用 Dubbo 的 Filter 机制进行无缝的过滤拦截。但本文只是提到 Sentinel 如下核心方法:


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


上述这些方法,将在后面的文章中进行深入探究,即从下一篇文章开始,我们将真正进入 Sentinel 的世界中,让我们一探究竟限流、熔断通常是如何实现的。

相关文章
|
3月前
|
负载均衡 监控 Dubbo
Dubbo 原理和机制详解(非常全面)
本文详细解析了 Dubbo 的核心功能、组件、架构设计及调用流程,涵盖远程方法调用、智能容错、负载均衡、服务注册与发现等内容。欢迎留言交流。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Dubbo 原理和机制详解(非常全面)
|
9月前
|
负载均衡 监控 Dubbo
秒懂Dubbo接口(原理篇)
【4月更文挑战第25天】秒懂Dubbo接口(原理篇)
343 3
秒懂Dubbo接口(原理篇)
|
4月前
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
|
4月前
|
运维 监控 算法
聊一聊Sentinel背后的原理
本文介绍了Sentinel的核心原理,包括流量控制、熔断降级、系统负载保护、实时监控和统计、与多种微服务框架的集成能力以及扩展性,强调了Sentinel在保障分布式系统稳定性方面的重要性。
198 0
|
6月前
|
运维 监控 NoSQL
【Redis】哨兵(Sentinel)原理与实战全解~炒鸡简单啊
Redis 的哨兵模式(Sentinel)是一种用于实现高可用性的机制。它通过监控主节点和从节点,并在主节点故障时自动进行切换,确保集群持续提供服务。哨兵模式包括主节点、从节点和哨兵实例,具备监控、通知、自动故障转移等功能,能显著提高系统的稳定性和可靠性。本文详细介绍了哨兵模式的组成、功能、工作机制以及其优势和局限性,并提供了单实例的安装和配置步骤,包括系统优化、安装、配置、启停管理和性能监控等。此外,还介绍了如何配置主从复制和哨兵,确保在故障时能够自动切换并恢复服务。
|
6月前
|
负载均衡 Dubbo 应用服务中间件
Dubbo服务调用过程原理
该文章主要介绍了Dubbo服务调用过程的原理,包括服务调用的主要阶段和服务调用的具体步骤。
Dubbo服务调用过程原理
|
6月前
|
缓存 Dubbo Java
Dubbo服务消费者启动与订阅原理
该文章主要介绍了Dubbo服务消费者启动与订阅的原理,包括服务消费者的启动时机、启动过程以及订阅和感知最新提供者信息的方式。
Dubbo服务消费者启动与订阅原理
|
6月前
|
Dubbo 网络协议 Java
深入掌握Dubbo服务提供者发布与注册原理
该文章主要介绍了Dubbo服务提供者发布与注册的原理,包括服务发布的流程、多协议发布、构建Invoker、注册到注册中心等过程。
深入掌握Dubbo服务提供者发布与注册原理
|
6月前
|
负载均衡 Dubbo Java
Dubbo服务Spi机制和原理
该文章主要介绍了Dubbo中的SPI(Service Provider Interface)机制和原理,包括SPI的基本概念、Dubbo中的SPI分类以及SPI机制的实现细节。
Dubbo服务Spi机制和原理
|
6月前
|
缓存 负载均衡 Dubbo
Dubbo服务集群容错原理(重要)
该文章主要介绍了Dubbo服务集群容错的原理,包括集群容错技术的概念、Dubbo中使用的集群容错技术种类及其原理。