目前网上大多数关于Zuul的相关讨论大都是 Spring-Cloud-Zuul 相关的,但是笔者认为Spring Cloud Zuul 有利也有弊。好处就是开发起来比较方便,一个注解就可以启用一个网关,并且增加了一些默认的过滤器组件;但是Spring Cloud 为了开发者的快速接入,也对Netflix Zuul 的一些功能做了阉割。
上图中可以看出,Netflix Zuul 主要包含了三大模块:Zuul Core模块、过滤器加载模块、过滤器管理模块。其中核心模块和过滤器加载模块,在Spring Cloud Zuul 的定制版本中,都没有做太大的改动。
核心模块:解决了,请求接收然后通过 pre、route、post 三个主要类型的过滤器。当然了,还有另外2 中上图中没有展现,就是 error 和 custom 类型。error 是处理异常时的处理动作,custom 是自定义处理请求的过滤流程。上面各个过滤器之间是通过 RequestContext (Map类型,ThreadLocal 变量) 来做上下文传递的。ZuulFilterRunner 组织了各种类型的过滤器的执行逻辑。
过滤器加载模块:这个模块主要是给Core 模块的FilterRunner 提供服务的,也就是提供编译好的Filter组件。其中的FilterFileManager 是以轮询的方式,不断的从包含groovy 脚本的目录中加载文件,提供给 FilterLoader 编译和管理。
过滤器管理模块:这个模块是往往被我们忽略的模块,但是这个模块对于我们运维和做一些功能增强时,非常有帮助。大多数情况下,都需要对其做定制开发,从而适应各个公司不同的业务需求。
Netflix Zuul 官方的代码目录如下所示:
上面代码一共有4 个模块,下面分别介绍一下:
zuul-core:核心模块,对应上面架构图的 GateWay Core。
zuul-netflix:该模块依赖于 zuul-core 模块,包含了 过滤器加载模块和过滤器管理模块的逻辑(管理模块的配置和页面在下面项目)。
zuul-netflix-webapp:包含了 Zuul 网关以 Web 的方式启用的启动配置。
zuul-simple-webapp:官方提供的一个简单的页面Demo。
核心模块
ZuulServlet
ZuulServlet 是Netflix Zuul 的全局入口,在 zuul-netflix-webapp 的web.xml 中的配置如下:
ZuulServlet 的主要逻辑如下:
上面 service() 方法中可以看出,ZuulServlet 依次执行了 pre过滤器、route过滤器、post过滤器;当产生错误时,会执行error 过滤器。
以上各种类型的 Filter 会委派给ZuulRunner 去执行。
ZuulRunner
ZuulRunner 本身也没什么逻辑,而是使用了单例的处理器 FilterProcessor 来处理。
FilterProcessor
FilterProcessor 回去从 FilterLoader 中获取各个类型的过滤器,并且顺序执行。主要逻辑如下:
RequestContext
在各个 Filter 执行的过程中,参数的传递依赖是通过 线程本地变量 RequestContext 来实现的。
过滤器加载模块
过滤器加载模块主要提供给 Core 模块,从磁盘(或者网络等其他介质)中加载Filter ,并完成实例化的过程,以备Core 模块的使用。其中FilterFileManager 负责从磁盘中加载数据,然后调用FilterLoader 的单例,去实例化Filter以备用。
FilterFileManager
FilterFileManager 中会启用一个守护线程,在后台不断地循环管理Filter 文件(源码中每次循环后,会休息1秒钟)。
循环每个Filter 都会调用 FilterLoader.getInstance().putFilter() 将其放入FilterLoader的Map中。
FilterLoader
过滤器管理模块
上面的过滤器加载模块最终交互的对象是磁盘文件,那么过滤器管理模块就相对是个独立的东西了。相关的操作就是Filter 文件。
过滤器管理模块直接操作文件的类是:ZuulFilterPoller 。它会起一个线程,不断的循环去抓取Filter的元数据(源码中由ZuulFilterDAO提供)。
ZuulFilterDAO
官方给的默认的实现是 Cassandra,也就是Filter的元数据是从 Cassandra 数据库中获取的。但是这个数据库在国内用的相对较少,如果要定制的话,通常会改成 MySQL 或者 Http接口的方式去实现。
ZuulFilterPoller
ZuulFilterPoller 中起了一个循环线程,不断的去获取元数据的信息,从而更新Filter。代码如下:
定制开发的建议
对于Zuul 网关的使用,有2 大方式:一种就是快速便捷的使用 Spring Cloud Zuul 的定制版本;另外一种就是基于Netflix Zuul 原生进行定制开发。Spring Cloud Zuul 的优点就是:开发方便,一个注解就可以开启一个网关节点;但是缺点也是很明显的,那就是不易于扩展,没有管理界面。那么相反的就是 原生的Netflix Zuul 的优缺点了。但是笔者认为,如果想要获取Zuul 的更多的定制特性,那么就需要基于原生的Zuul 进行定制开发。
通常情况下,需要对架构中的过滤器管理模块进行增强。可以考虑的功能点有:API 分组管理、API 管理、Filter 管理、服务管理等等。当然,生产中管理模块最好是一个独立的系统。Filter的管理通过网络去完成,所以由此看来工作量还是不小的。下面给出笔者的参考架构: