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

@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 的世界中,让我们一探究竟限流、熔断通常是如何实现的。

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


作者信息:丁威,《RocketMQ技术内幕》作者,目前担任中通科技技术平台部资深架构师,RocketMQ官方社区优秀布道师、CSDN2019博客之星TOP10,维护公众号 中间件兴趣圈公众号,目前主要发表了源码阅读java集合、JUC(java并发包)、Netty、ElasticJob、Mycat、Dubbo、RocketMQ、mybaits等系列源码。点击链接:加入笔者的知识星球,一起探讨高并发、分布式服务架构,分享阅读源码心得。

源码分析 Sentinel 之 Dubbo 适配原理的更多相关文章

  1. 5.Sentinel源码分析—Sentinel如何实现自适应限流?

    Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 3. Senti ...

  2. 4.Sentinel源码分析— Sentinel是如何做到降级的?

    各位中秋节快乐啊,我觉得在这个月圆之夜有必要写一篇源码解析,以表示我内心的高兴~ Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. ...

  3. 并发编程学习笔记(9)----AQS的共享模式源码分析及CountDownLatch使用及原理

    1. AQS共享模式 前面已经说过了AQS的原理及独享模式的源码分析,今天就来学习共享模式下的AQS的几个接口的源码. 首先还是从顶级接口acquireShared()方法入手: public fin ...

  4. 6.Sentinel源码分析—Sentinel是如何动态加载配置限流的?

    Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 3. Senti ...

  5. 7.Sentinel源码分析—Sentinel是怎么和控制台通信的?

    这里会介绍: Sentinel会使用多线程的方式实现一个类Reactor的IO模型 Sentinel会使用心跳检测来观察控制台是否正常 Sentinel源码解析系列: 1.Sentinel源码分析-F ...

  6. Guava 源码分析之Cache的实现原理

    Guava 源码分析之Cache的实现原理 前言 Google 出的 Guava 是 Java 核心增强的库,应用非常广泛. 我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Goog ...

  7. 从SpringBoot源码分析 配置文件的加载原理和优先级

    本文从SpringBoot源码分析 配置文件的加载原理和配置文件的优先级     跟入源码之前,先提一个问题:   SpringBoot 既可以加载指定目录下的配置文件获取配置项,也可以通过启动参数( ...

  8. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  9. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

随机推荐

  1. nodejs express 框架 上传文件

    web 项目应用express4.0框架 html 表单post 文件上传失败,后端无法获取提交文件 express不支持文件上传. 方式一 若是图片,可以将图片转码为BASE64上传 前端框架ang ...

  2. CPU|MICGPU|FPGA|超算|Meta-data|

    生物医学大数据: 收集数据后对数据的分析,如同看相,而对数据信息的挖掘可以看作是算命.这两个过程是基于算法和软件这类工具之上的. 在存储方面:在硬件上,为了Parallel computing的目的, ...

  3. SQL逻辑查询处理顺序特别提醒

    我们知道在SQL语句中,第一个被处理的子句式FROM,而不是第一出现的SELECT.这就是SQL不同于其他编程语言的最明显特征之一,以下先看一下SQL查询处理的步骤序号: (8) SELECT (9) ...

  4. python 简单主机批量管理工具

    需求: 主机分组 主机信息配置文件用configparser解析 可批量执行命令.发送文件,结果实时返回,执行格式如下  batch_run  -h h1,h2,h3   -g web_cluster ...

  5. figure图像

    import matplotlib.pyplot as plt import numpy as np x=np.linspace(-3,3,50) y1=x*2+1 y2=x**2 plt.plot( ...

  6. windowserver 2012安装openssh

    下载https://github.com/PowerShell/Win32-OpenSSH/releases解压放到C:\Program Files\OpenSSH-Win64 进入到C:\Progr ...

  7. kibana增加验证

    Kibana从5.5开始不提供认证功能,想用官方的认证X-Pack收费 ... 自己动手吧,用nginx的代理加apache生成的密码认证文件.环境:ubuntu16.04 安装nginxapt-ge ...

  8. java23种设计模式 (转)

    文章在:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html 随着自己的开发经验增加以及自己做了很多的 大专栏  jav ...

  9. 干了这碗蛋炒饭 继续APP性能提升

    [前言] 什么是做功能,功能就是客户要一碗蛋炒饭,然后做了给他. 我想谁都明白,一家餐厅能活下去,是因为能把食材料理好,客户喜欢. 更准确的说,一家餐厅能活得下去,要考虑用户需求.食材,然后就是料理水 ...

  10. 【自己的下载平台】搭建aria2网站

    前言 本文章将带你搭建一个自己的服务器下载平台:aria2,它的用途是什么? 下载用途 百度网盘 普通文件 迅雷种子 等等 准备工具 服务器连接软件xshell或者putty 一台服务器 安装宝塔面板 ...