本文将介绍Zuul的动态路由。
Zuul的动态路由
启动时Zuul会读取静态配置文件加载路由信息,将URL Path与路由映射关系建立好,提前加载到内存。在很多场景下,我们需要在不停止Zuul进程的前提下,完成路由映射规则的重新建立,这时候我们就需要动态路由(Dynamic Routing)功能,有两种实现动态路由的方式。
方式一:通过Spring Boot Acturator开启Zuul的Endpoint功能,它支持Refresh动态刷新配置文件,这种方式的好处是Zuul无须做任何修改,也不需要维护路由映射规则,缺点是没有可视化界面,维护起来比较烦琐。
方式二:覆写RouteLocator的List<Route>getRoutes()方法,通过事件刷新机制,从数据库中读取路由配置规则。这是常用的Zuul动态路由解决方案,它可以轻松地实现可视化管理,减少引入新的Spring Cloud组件的依赖绑定。Sia-Gateway(GitHub已开源项目)使用了基于MySQL DB的动态路由机制。如下图所示是Zuul动态路由架构图。
Zuul的动态路由思路及解决方案如下。
首先,Admin作为前端管理界面将用户对路由的添加、修改、删除等操作通过RouteService存储到DB中。DB中的存储结构如下图所示。
字段映射关系如下。
● id:标识路由的唯一ID,唯一主键,可以根据路由ID查找路由。
● ZuulGroupName:网关集群组名,标识这个新建的路由归属在哪个网关集群下面。
● apName:应用名称,标识路由的别名。
● path :匹 配 路 径 , 新 建 路 由 的 路 径 匹 配 Patten ( 例如/foo/**),所有发到/foo/**路径下的请求都会转发到这个路由下面。
● strategy:后端服务策略,后端路由有以下三种策略(只能选其中一种策略)。
○ SERVICEID策略:针对连接到Eureka上的应用,根据配置的ServiceID,网关会动态匹配一个后端服务。
○ SERVICEURL策略:针对非Eureka上的应用根据配置的URL映射到匹配的URL后端服务上。
○ LISTOFSERVICE策略:针对非Eureka上的应用,可以选择多个IP:PORT(通过逗号分隔)实现路由负载,默认使用RoundRobin方式实现负载均衡。
例如“192.168.1.3:8070,192.168.1.2:8090”。
● SERVICEID:匹配一个新建路由的后端服务唯一标识。● url:后端服务URL,匹配一个新建路由的后端服务URL物理地址。
● stripPrefix:前缀是否生效,标识这个路由在转发时是否需要删除前缀设置。
○ 当stripPrefix=true时,主要的路由映射关系如下:
http://127.0.0.1:8181/api/user/list-
>http://192.168.1.100:8080/user/list
○ 当stripPrefix=false时,主要的路由映射关系如下:
http://127.0.0.1:8181/api/user/list-
>http://192.168.1.100:8080/api/user/list).
其次,Admin对Route的状态管理类似状态机,网关节点的路由状态变更通过事件触发机制实现,以达到路由状态的一致性。如下图所示是路由(Route)状态在Admin上的状态流转图。
当Admin在修改Route状态时,它需要首先进行Route下线,当Route处于发布上线状态时,执行发布路由操作会调用publishRoute操作,publishRoute会调用Gateway的对外刷新接口,Gateway会从Admin同步最新的路由信息,并将Route设置为发布状态。
网关节点的路由管理机制主要由两部分组成,一部分通过自定义RouteLocator从Admin同步最新的路由状态,Admin会访问数据库,并返回给网关节点最新的路由状态信息,另一部分就是路由缓存状态管理,即同步更新。下面是代码实现。
● 说明1#:CustomizeRouteLocator是自定义路由加载的核心处理 类 , 该 类 继 承 了 SimpleRouteLocator , 并 实 现 了RefreshableRouteLocator接口。该类的主要功能是覆盖简单路由定位器的具体实现类,完成具体路由的加载策略及Zuul的内部事件刷新机制。
● 说明2#:refresh方法是RefreshableRouteLocator刷新事件的 回 调 方 法 , 该 回 调 方 法 在 ZuulHandlerMapping 执 行setDirty方法时被触发。ZuulHandlerMapping的代码如下:
ZuulRefreshListener在@ ZuulServerAutoConfiguration自动化配置类中被初始化,setDirty(true)将触发配置信息的重新加载并触发refresh方法,代码如下:
● 说明3#:locateRoutes方法是SimpleRouteLocator的回调方法 , 下 面 是 SimpleRouteLocator 的 具 体 实 现 , 可 以 看 到SimpleRouteLocator在doRefresh事件中回调了locateRoutes方法。
● 说明4#:这部分代码是自定义路由加载的核心策略,我们设置了一个布尔型的原子变量:refreshCalled,当这个变量设置为true时,表示需要自定义Locator,强制从数据库中加载最新路由信息。当从数据库同步路由信息并将其存储到本地缓存中时,将refreshCalled设置为false,这样下次加载路由信息时,从缓存中加载就可以了,不需要从远端数据库中加载。这样做的好处是,可以明显提升维护本地路由信息的效 率 。RouteLocatorUpdater 的 作 用 就 是 当 Admin 调 用refreshRoute 方 法 时 , 将 refreshCalled 原 子 变 量 设 置 为true,强制从数据库同步加载路由信息。
最后一步,就是Admin从数据库获取路由数据信息,即从数据库中加载网关的路由信息,并返回给网关节点,作为最新的路由信息。
注意:在网关获取动态路由信息的过程中,使用REST方式通过Admin代理获取路由信息,没有使用网关节点直接去数据库查询路由信息,主要有两个原因: ● 网关如果直接连接数据库,就会产生网关与数据库的强耦合关系,对于所有网关服务来说,都需要引入对MySQL数据库的依赖。 ● 网关节点服务如果使用连接数据库的方式,那么就需要数据库的相关配置(用户名、密码)等信息,从数据安全的角度考虑,网关作为云原生的服务资源,应该尽量少暴露给后端用户,我们应该通过网关Admin服务统一管理数据库资源。
本文给大家讲解的内容是微服务网关:Zuul的动态路由
- 下篇文章给大家讲解的内容是微服务网关:Zuul Filter扩展功能实现
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。