数据同步设计
本篇主要讲解数据同步原理,数据同步是指在 shenyu-admin
后台操作数据以后,使用何种策略将数据同步到 Apache ShenYu
网关。Apache ShenYu
网关当前支持ZooKeeper
、WebSocket
、Http长轮询
、Nacos
、Etcd
和 Consul
进行数据同步。
数据同步的相关配置请参考用户文档中的 数据同步配置 。
背景
网关是流量请求的入口,在微服务架构中承担了非常重要的角色,网关高可用的重要性不言而喻。在使用网关的过程中,为了满足业务诉求,经常需要变更配置,比如流控规则、路由规则等等。因此,网关动态配置是保障网关高可用的重要因素。
在实际使用 Apache ShenYu
网关过程中,用户也反馈了一些问题:
- 依赖
Zookeeper
,怎么使用Etcd
、Consul
、Nacos
等其他注册中心? - 依赖
Redis
、influxdb
,没有使用限流插件、监控插件,为什么需要这些? - 配置同步为什么不使用配置中心?
- 为什么不能动态配置更新?
- 每次都要查询数据库,使用
Redis
不就行了吗?
根据用户的反馈信息,我们对 Apache ShenYu
也进行了部分的重构,当前数据同步特性如下:
- 所有的配置都缓存在
Apache ShenYu
网关内存中,每次请求都使用本地缓存,速度非常快。 - 用户可以在
shenyu-admin
后台任意修改数据,并马上同步到网关内存。 - 支持
Apache ShenYu
的插件、选择器、规则数据、元数据、签名数据等数据同步。 - 所有插件的选择器,规则都是动态配置,立即生效,不需要重启服务。
- 数据同步方式支持
Zookeeper
、Http 长轮询
、Websocket
、Nacos
、Etcd
和Consul
。
原理分析
下图展示了 Apache ShenYu
数据同步的流程,Apache ShenYu
网关在启动时,会从配置服务同步配置数据,并且支持推拉模式获取配置变更信息,然后更新本地缓存。管理员可以在管理后台(shenyu-admin
),变更用户权限、规则、插件、流量配置,通过推拉模式将变更信息同步给 Apache ShenYu
网关,具体是 push
模式,还是 pull
模式取决于使用哪种同步方式。
在最初的版本中,配置服务依赖 Zookeeper
实现,管理后台将变更信息 push
给网关。而现在可以支持 WebSocket
、Http长轮询
、Zookeeper
、Nacos
、Etcd
和 Consul
,通过在配置文件中设置 shenyu.sync.${strategy}
指定对应的同步策略,默认使用 WebSocket
同步策略,可以做到秒级数据同步。但是,有一点需要注意的是,Apache ShenYu
网关 和 shenyu-admin
必须使用相同的同步策略。
如下图所示,shenyu-admin
在用户发生配置变更之后,会通过 EventPublisher
发出配置变更通知,由 EventDispatcher
处理该变更通知,然后根据配置的同步策略(Http、WebSocket、Zookeeper、Nacos、Etcd、Consul
),将配置发送给对应的事件处理器。
- 如果是
WebSocket
同步策略,则将变更后的数据主动推送给shenyu-web
,并且在网关层,会有对应的WebsocketDataHandler
处理器来处理shenyu-admin
的数据推送。 - 如果是
Zookeeper
同步策略,将变更数据更新到Zookeeper
,而ZookeeperSyncCache
会监听到Zookeeper
的数据变更,并予以处理。 - 如果是
Http
同步策略,由网关主动发起长轮询请求,默认有90s
超时时间,如果shenyu-admin
没有数据变更,则会阻塞Http
请求,如果有数据发生变更则响应变更的数据信息,如果超过60s
仍然没有数据变更则响应空数据,网关层接到响应后,继续发起Http
请求,反复同样的请求。
Zookeeper同步原理
基于 Zookeeper
的同步原理很简单,主要是依赖 Zookeeper
的 watch
机制。Apache ShenYu
网关会监听配置的节点,shenyu-admin
在启动的时候,会将数据全量写入 Zookeeper
,后续数据发生变更时,会增量更新 Zookeeper
的节点,与此同时,Apache ShenYu
网关会监听配置信息的节点,一旦有信息变更时,会更新本地缓存。
Apache ShenYu
将配置信息写到zookeeper
节点,是通过精心设计的,如果您想深入了解代码实现,请参考源码 ZookeeperSyncDataService
。
WebSocket同步原理
WebSocket
和 Zookeeper
机制有点类似,将网关与 shenyu-admin
建立好 WebSocket
连接时,shenyu-admin
会推送一次全量数据,后续如果配置数据发生变更,则以增量形式将变更数据通过 WebSocket
主动推送给 Apache ShenYu
网关。
使用 WebSocket
同步的时候,特别要注意断线重连,也就是要保持心跳。Apache ShenYu
使用java-websocket
这个第三方库来进行websocket
连接。 如果您想深入了解代码实现,请参考源码 WebsocketSyncDataService
。
Http长轮询同步原理
Zookeeper
和WebSocket
数据同步的机制比较简单,而 Http长轮询
则比较复杂。 Apache ShenYu
借鉴了 Apollo
、Nacos
的设计思想,取其精华,自己实现了 Http长轮询
数据同步功能。注意,这里并非传统的 ajax
长轮询!
Http长轮询
机制如上所示,Apache ShenYu
网关主动请求 shenyu-admin
的配置服务,读取超时时间为 90s
,意味着网关层请求配置服务最多会等待 90s
,这样便于 shenyu-admin
配置服务及时响应变更数据,从而实现准实时推送。
http
请求到达 shenyu-admin
之后,并非立马响应数据,而是利用 Servlet3.0
的异步机制,异步响应数据。首先,将长轮询请求任务 LongPollingClient
扔到 BlockingQueue
中,并且开启调度任务,60s
后执行,这样做的目的是 60s
后将该长轮询请求移除队列。因为即便是没有配置变更,也需要让网关知道,不能一直等待。而且网关请求配置服务时,也有 90s
的超时时间。
如果这段时间内,管理员在 shenyu-admin
变更了配置数据,此时,会挨个移除队列中的长轮询请求,并响应数据,告知是哪个 Group
的数据发生了变更(我们将插件、规则、流量配置、用户配置数据分成不同的组)。网关收到响应信息之后,只知道是哪个 Group
发生了配置变更,还需要再次请求该 Group
的配置数据。这里可能会存在一个疑问:为什么不是直接将变更的数据写出?我们在开发的时候,也深入讨论过该问题,因为 http 长轮询
机制只能保证准实时,如果在网关层处理不及时,或者管理员频繁更新配置,很有可能便错过了某个配置变更的推送,安全起见,我们只告知某个 Group
信息发生了变更。
当 shenyu-web
网关层接收到 http
响应信息之后,拉取变更信息(如果有变更的话),然后再次请求 shenyu-admin
的配置服务,如此反复循环。 如果您想深入了解代码实现,请参考源码 HttpSyncDataService
。
Nacos同步原理
Nacos
的同步原理与Zookeeper基本类似,主要依赖于Nacos
的配置管理
,各个配置节点的路径与Zookeeper类似。
Apache ShenYu
网关会监听配置的节点,启动时,如果Nacos
中不存在配置节点,将同步全量的数据写入Nacos
中,后续数据发生变更时,全量更新Nacos
中的配置节点,与此同时,Apache ShenYu
网关会监听配置信息的节点,一旦有信息变更时,会更新本地缓存。
如果您想深入了解代码实现,请参考源码 NacosSyncDataService
和Nacos
的官方文档。
Etcd同步原理
Etcd
数据同步原理与Zookeeper类似,主要依赖于Etcd
的watch
机制,各个配置节点路径与Zookeeper
相同。
Etcd
的原生API使用稍有点复杂,所有对其进行了一定的封装。
Apache ShenYu
网关会监听配置的节点,启动时,如果Etcd
中不存在配置节点,将同步全量的数据写入Etcd
中,后续数据发生变更时,增量更新Etcd
中的配置节点,与此同时,Apache ShenYu
网关会监听配置信息的节点,一旦有信息变更时,会更新本地缓存。
如果您想深入了解代码实现,请参考源码 EtcdSyncDataService
。
Consul同步原理
Consul
数据同步原理是网关定时轮询 Consul
的配置中心,获取配置版本号与本地进行比对。
Apache ShenYu
网关会定时轮询配置的节点,默认间隔时间为1s。启动时,如果 Consul
中不存在配置节点,将同步全量的数据写入Consul
中,后续数据发生变更时,增量更新 Consul
中的配置节点,与此同时,Apache ShenYu
网关会定时轮询配置信息的节点,拉取配置版本号与本地进行比对,若发现版本号变更时,会更新本地缓存。
如果您想深入了解代码实现,请参考源码 ConsulSyncDataService
。