结合 Sentinel 专栏谈谈我的源码阅读方法
做积极的人,越努力越幸运!
本文行文思路:先抛出源码阅读方法,然后结合Sentinel创作过程谈谈具体是如何运用这些技巧,最后解答几个源码阅读的误区。
Sentinel 系列共包含15篇文章,主要以源码分析为手段,图文并茂的方式对 Sentinel 的架构设计理念、核心实现要点进行了一一剖析,并加以实战分析与思考。
很多朋友都在咨询我是如何阅读源码的。对此可归纳为如下几个要点,然后结合 Sentienl 源码分析专栏对各个要点进行拆解,对源码阅读方法进行一次“实战”。
阅读官方文档,从全局了解待学习框架能解决什么样的问题,整体架构设计与思想是什么,主要包含哪些要点。
从官方提供的 Demo 程序开始,学习基本的使用方法,进一步加深其理解,并伺机寻找入口(突破口)。
寻找突破口,逐一突破,先主干再旁支,适度分解,各个击破。
接下来将展示我是如何使用这套方法论来学习 Sentinel 的。
在准备深入学习 Sentinel 之前,首先认真看了一遍 Sentinel 的官方文档,从而形成了对 Sentinel 的基本认识,我们可以从官方文档了解到 Sentinel 主要涉及的核心内容,正如下图所示:
本文不会再详细介绍每一个知识点的细节,有关各个知识点的具体讲解,大家可以点击感兴趣的链接中进行深入研究,本文主要是点到为止,重在介绍笔者是如何学习源码的。
1、
该文章主要从如下几个点进行展开:
Sentinel 是什么 ?主要能解决什么问题?
限流与熔断的使用场景
Sentinel 源码结构
在 IntelliJ IDEA 中运行 Sentine Demo
其实第三点并不是特别必须,不过要得出这些结论也并不难,因为对 Sentinel 有了全局的认识后并根据各个模块的命名很容易能得出该模块的作用。这里第四点非常关键,通常一个优秀的开源框架都会提供完备的演示 Demo,大家可以看到 Sentinel 的演示 demo 非常丰富,在本文中我特意选择了 Dubbo 来做示例,主要是我们公司大量使用 dubbo 来实现公司的微服务,这样会更加贴近实战,更有利于寻找突破口。
通过跑通 Demo 的主要目的有三个:
通过运行 Demo,了解框架的基本使用方法。
搭建一个可 Debug 的环境,为后续看不懂代码的情况下进行调试,根据运行时数据,可加快代码的理解速度,但千万不要一开始就 debug。
寻找源码阅读的入口。
2、
紧跟第一篇文章,既然使用的是 Dubbo 作为其示例代码,自然而然的思考 Sentinel 是如何做到对 Dubbo 的适配并对业务无侵入性。
通过该篇文章的学习我们了解到可以通过 Dubbo 的扩展机制实现对 Dubbo 的适配,在 Dubbo Filter 中我们能看到了与 Sentinel 相关的核心 API SphU.entry,从而找到深入学习 Sentinel 的核心入口,也就是后续文章会通过对该方法的研究,从而打开进入 Sentinel 内核世界的大门。
备注:在阅读这篇文章的时候,我觉得 Dubbo 的适配感觉非常简单,但随着我对这个系列的深入学习,发现了该方法没有那么简单,当时很多点都没有理解到位,这个在后续会有重点阐述,这也是不断学习、不断思考带来的好处。
3、
本文主要是详细跟踪 SphU.entry 方法的执行流程,从而揭晓其实现的关键点,果不其然,通过跟踪该方法的流程,找到了 Sentinel 的核心运作机制:Slot 处理链。
4、
按照上述 Slot 的链,开始了 NodeSelectorSlot 的研究,通过学习了解到该 NodeSelectorSlot 主要是构建 Sentinel 的调用链,即调用上下文环境管理,准确的说是构建调用链的入口节点。在 Sentinel 中每进入一个资源都会有对应的节点实时存储该资源的调用信息。
5、Sentinel 实时数据采集原理
这个议题共两篇文章,其相关链接如下:
如果按照 Slot 链的执行顺序,下一个执行的 ClusterBuilderSlot,从名字就可以看出与集群限流相关的,但秉承着先简后难的学习策略,在当前先跳过该类的学习,先重点突破单机版限流,后续再回过头来学习集群限流相关的知识。
要实现限流、熔断等功能,首先要解决的问题是如何实时采集服务(资源)调用信息。例如将某一个接口设置的限流阔值 1W/tps,那首先如何判断当前的 TPS 是多少?Alibaba Sentinel 采用滑动窗口来实现实时数据的统计,实现类:StatisticSlot。
6、Sentinel 限流实现原理
在弄懂了 Sentinel 的实时数据采集原理后,限流实现就非常简单了,就是基于采集的调用信息,然后与限流规则进行比较,判断是否需要限流,Sentinel 在触发限流后还提供了多种处理策略,例如快速失败、匀速排队、预热等机制。
但我在学习限流的时候,我将限流核心逻辑与触发限流后的处理策略进行了分解,在学习限流的时候挑选了最简单处理策略(匀速排队),将比较难的预热机制分解,再单起一篇文章进行学习,这样的拆解有利于保证学习单篇文章的用时,并提高自己的“产量”,提高自己的成就感。
这块主要包含如下4篇文章:
这里还要重点阐述一下限流领域最核心的算法:漏桶算法、漏斗算法等,并且 Sentinel 的预热机制主要是参考 Guava 的实现,故这里花了点精力认真学习了 Guava 的 RateLimite 的实现原理。
7、
限流部分学习完后,我就迫不及待的去探究熔断的实现,其实熔断本身并不复杂,和限流一样,无非就是根据当前的实时调用信息与熔断规则进行对比即可,如果满足熔断规则就抛出异常。如果只是熔断自身的实现本质确实简单,但要结合实际,其实有更多的问题需要思考,这个在后面的实战篇又是反复思考,从而发现 Sentinel 在熔断的实现上其实比较粗糙。
8、
经过前面的文章,Sentinel 的单机限流与熔断已经基本学习了,这个时候就要开始思考如何使用 Sentinel 了,但 Sentinel 官方提供的后台运维管理系统的熔断、限流规则只能存储在内存,显然不能直接用于生产环境,故需要提出解决方案,本篇文章详细介绍了笔者是如何根据官方资料进行动态数据源配置的方法调研的,完成是按照工作中架构设计方案的标准来思考的,强烈推荐。
9、
支持了动态数据源,就继续进行思考,在微服务领域是如何思考引入熔断机制的,进行一番思考后发现官方提供的 Dubbo 适配器的粒度是服务级别的,无法控制机器级别,例如下图所示:
以上就是我学习源码的方法,希望对大家真正有所帮助与感触。
最后我再来谈一下回答关于源码阅读方面误区的几个问题。
1、看源码会忘记吗?为什么我们看源码的时候感觉看懂了,但很容易就忘记?
我们要始终明白看源码只是手段,目的是要思考框架的设计原理、并通过源码了解实现细节并指导实践。重在思考。当然实现细节看过后容易忘记,但只要理解了思想,在需要使用时可以看自己写过的文章,一下子就能拾起来。
2、看源码的时候是不是可以直接使用 Debug 进行调试学习
我是强烈不建议这样做,这样会迷失在细节中无可自拔。正确的姿势是寻找入口,带上自己的思考去梳理,当遇到看不懂源码或是无法理解其思想时,这个时候可以借助 Debug,可以通过运行时可视化的数据,帮助我们更快的了解。
原创不易,如果对你有所帮助请你为本文点个【在看】吧,这将是我写作更多优质文章的最强动力。
欢迎加入我的知识星球,一起交流源码,探讨架构,揭秘亿级订单的架构设计与实践经验,打造高质量的技术交流圈,为广大星友提供高质量问答服务,长按如下二维码加入。