Zuul2源码分析

关注精彩内容,要先点击这里哦~

Zuul2

Zuul2的难产,终于在 2018.4.13 上架了中心仓库,也代表着Zuul正式加入Netty全家桶的怀抱,关于 Zuul2 有一篇宏观性的博文有兴趣的可以阅读 Zuul 2 : The Netflix Journey to Asynchronous, Non-Blocking Systems 此篇博客。

简而言之,Zuul2也就是从传统的 BIO 切换到了 NIO 模式。

传统的BIO模型基于Thread的方式

NIO模型基于Reactor模型。

Zuul2 架构

从上帝视角来开,Zuul2是一个在上运行一系列Filter的服务,执行完成PreFilter (inbound filters)之后将请求通过转发出去,然后将请求的结果通过一系列PostFilter (outbound filters) 返回,如下图所示。

正如之前的 分为了 ,,,,Zuul2的Filter分为三种类型

Inbound Filters: 在路由之前执行

Endpoint Filters: 路由操作

Outbound Filters: 得到相应数据之后执行

我们用官方的Demo进行分析 zuul-sample,诸位看官自行下载导入。

(https://github.com/Netflix/zuul/tree/2.1/zuul-sample)

ServerStartup

在Demo的启动中,我们发现启动的入口

➊ 获得系统的一些配置参数

➋ Demo中使用的是Google的Guice进行依赖注入的,这个就展开了有兴趣的可以自行去搜索

➌ 启动一个Zuul2服务

我们从这个 作为我们的突破口,

➊ 构建一个新的

➋初始化一个,根据之前Netty的分析,我们知道Netty需要使用进行 端口绑定,那这里是不是就是那个东西。

我们继续深入

在 ➊ 构建了一个 这个正是Netty的启动类

➋ 正如Netty的启动中的处理数据的 那这里应该也就是Zuul处理的核心所在

➌ 一个我们的老朋友,和Eureka集成时改变服务器状态

➍ 绑定 不再多做分析

1/3 休息

我们已经发现了Zuul2是如何启动一个Netty服务的,我们解决了图中红框部分的原理,那我们接下来去了解最为重要的这些Filter是如何工作的,我们上启动中已经发现一个很重要的对象 我们知道在Netty中,是将一系列的 聚合在一起并使用 执行(参考Netty源码分析-(3)-ChannelPipeline)我们可以猜测 zuul 的做法是类型,我们从这个 入手去研究。

ZuulServerChannelInitializer

我们轻而易举的可以发现其实是对象。在initChannel中我们发现了

在➊前面的都比较简单都是一些标准的大家可以自己阅读,最为重要是这个函数,我们继续深入。

上面的都很容易看出来,是日志,Session之类的Handler,最为重要的是 ➋ 处增加 ZuulFilter。

从 ➊ 深入可以看到

这里返回了一个 的数组,开始分别是 和 对应的刚好是 。

然我们继续回到 函数上来,我们发现有三段相似的代码正好对应着获得了

这三种Filter,在代码我们可以看出顺序是

和 合并成

构建成

和 组合成

将 添加至 中

那这里我们还有一个疑问,这些Filter是从何而来的?这个答案隐藏在

中,通过简单的跟踪我们可以得到

在这里 ➊ 获得所有的Fiter,而这里的Filter看起来是通过进来的,通过一个简单的断点,我们就可以发现

➊ 我们通过类的全称限定类名获得的这个Fitler,这个配置是在我们的配置文件中配置的。

2/3 休息

文至中场,我们已经明白了Zuul2如何将自己的变换成并添加到之中的,那我们还剩下一个问题,这个是如何运作的。但是我们在上段中,我们已经发现了最后是一个通过名称我们可以推测出,这是一个,我们继续往下探索吧。

ZuulFilterChainHandler

我们知道,最终注册到上的最终肯定是, 我们只需要从 Netty 的函数作为突破口去阅读。

➊ 这段逻辑处理 已经被转化为 类型的消息

➋ 实际上的 filter 处理逻辑

➌ 处理还没被转化为 类型的消息

➍ 无法处理抛出异常,释放MSG

而这里的 就是之前我们传入进去的 我们看看这 函数做了什么?

➊ 获得当前运行的Filter的下标值

➋ 获得对应的

➌ 调用 进行处理

➍ 将下标志值 +1,继续循环体

➎ 执行下个阶段,这里对应着我们自己再构建

通过这段代码,我们知道了 的Chain是由 运行,和Netty的Head tail的链方式大相径庭。

在 中的 函数也相当有趣。

➊ 临时存储起来这个Filter待异步完成回调

➋ 具体的执行处

➌ 获取当前的所在的并在这个线程上观察

➍ 将数据在 resumer 中消费

➊ 处获得我们的结果并将其恢复到我们保管的 。

剩余关于 的运行机制是类似的,诸位看官自行分析下。

终场休息

通过上面的一系列分析,我们已经知道的,Zuul的 ,的运行机制,整个Zuul2的运行机制在我们的面前一览无遗。整体的Zuul代码是相当的明了的,代码的分层也很好,但是还有一朵乌云在我们的头顶之上,那就是在那张途中的 我们并没有发现其踪迹,但是我们知道只有在 阶段,我们才会对外进行访问,在官网的Wiki中,我们也可以获得

Zuul does not use Ribbon for making outgoing connections and instead uses its own connection pool, using a Netty client. Zuul creates a connection pool per host, per event loop. It does this in order to reduce context switching between threads and to ensure sanity for both the inbound event loops and outbound event loops. The result is that the entire request is run on the same thread, regardless of which event loop is running it.

我们从 中可以得知,Netty不再默认使用 Ribbon 而是默认使用 作为一个 .

ProxyEndpoint

这个类的对象及其的复杂,我们从filter的核心逻辑看起来。

➊ 将请求转发至远端

➊ 处将请求包装,连接到远端地址,获得 Promise

➋ 结束的 Promise 处理,在中包含了成功的执行代码,至于Zuul 包装了 Netty的Client。

➊ 获得建立的连接

➋ 写入Zuul的请求,也就是用户的请求

➌ 将消息Flush出去

➍ 在这里读取响应的数据,也就是触发的处理时间

总结

Zuul整体逻辑,我们通过博文可以分析而出。

ZuulFilter 分为 , ,

, , 包裹成

组合成一个 ,而 是Netty的 一个Handler

会组装到 Netty 的 中,剩下来就是Netty的流程了

参考知识

给 Android 开发者的 RxJava 详解

(https://gank.io/post/560e15be2dca930e00da1083)

谜之RxJava (三)update 2 —— subscribeOn 和 observeOn 的区别(https://segmentfault.com/a/1190000004856071)

Zuul-Wiki

(https://github.com/Netflix/zuul/wiki)

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180625G1X0T700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券