Soul网关数据同步
-
为什么需要数据同步?
Soul作为独立的网关系统,有自己的管理后台soul-admin
,通过页面操作就可以控制插件数据,选择器,规则数据,元数据,签名数据等等,并且所有插件的选择器,规则都是动态配置,立即生效,不需要重启服务。这样便捷的操作当然需要一套完善的数据同步机制。又考虑到性能问题,不可能每次更改了设置都要通过数据库来获取,所以soul设计了一套数据同步机制,保证了数据始终在JVM的内存中,且是最新的数据,这样也就大大提高了性能。 -
Soul的数据同步原理是什么?
详细的介绍可以参考官方社区的文档【Soul数据同步原理】
我这里概括以下就是用户通过后台页面修改了设置,Soul就会分别将数据同步到数据库,和同步给我们的网关系统。然后我们的网关系统就会更新本地的缓存,当又相应的流量过来的时候,不需要去我们的数据库再去拿数据。对应的就是下面这张图:
-
Soul支持哪些数据同步方式?
到目前为止,Soul支持以下四种数据同步方式:- websocket同步
- zookeeper同步
- http长轮询同步
- nacos同步
今天 我们主要看的是websocket同步方式。
websocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
以上摘抄自百度百科
代码跟踪
基本的概念了解清楚后,接下来就打开源码来学习吧。
因为Soul默认使用的就是websocket方式进行数据同步,所以这里就不再赘述了,不清楚的同学可以参考官方文档【Soul数据同步策略】。
-
启动
soul-admin
-
启动网关
soul-bootstrap
启动成功后我们分别再soul-admin
的后台和soul-bootstrap
的后台分别看到如下log信息。这就说明我们的后台管理系统和网关系统使用websocket建立了连接。2021-01-20 19:57:59.428 INFO 19448 --- [0.0-9095-exec-1] o.d.s.a.l.websocket.WebsocketCollector : websocket on open successful....
2021-01-20 19:57:59.411 INFO 19576 --- [ocket-connect-1] o.d.s.p.s.d.w.WebsocketSyncDataService : websocket reconnect is successful.....
-
先从这两个log入手,看一下源码,先看
soul-admin
的。这里使用的是websocket的OnOpen
监听方法,当有新的连接的时候,会把该连接的session放入到一个Set中。private static final Set<Session> SESSION_SET = new CopyOnWriteArraySet<>(); /** * On open. * * @param session the session */ @OnOpen public void onOpen(final Session session) { log.info("websocket on open successful...."); SESSION_SET.add(session); }
这里主要处理的是建立连接的时候处理的一些逻辑。
- 如果配置了多个url,通过“,”分割(这个再配置的时候有说明)。
- 创建WebSocketClient,并添加到List中去
- 针对于List中的Client创建连接,并且创建定时任务监视是否处于连接中,如果断开了连接,则尝试重新连接(如果在executor.scheduleAtFixedRate(() -> {})里面打断点,会发现每隔30面进来一次)。
/** * Instantiates a new Websocket sync cache. * * @param websocketConfig the websocket config * @param pluginDataSubscriber the plugin data subscriber * @param metaDataSubscribers the meta data subscribers * @param authDataSubscribers the auth data subscribers */ public WebsocketSyncDataService(final WebsocketConfig websocketConfig, final PluginDataSubscriber pluginDataSubscriber, final List<MetaDataSubscriber> metaDataSubscribers, final List<AuthDataSubscriber> authDataSubscribers) { String[] urls = StringUtils.split(websocketConfig.getUrls(), ","); executor = new ScheduledThreadPoolExecutor(urls.length, SoulThreadFactory.create("websocket-connect", true)); for (String url : urls) { try { clients.add(new SoulWebsocketClient(new URI(url), Objects.requireNonNull(pluginDataSubscriber), metaDataSubscribers, authDataSubscribers)); } catch (URISyntaxException e) { log.error("websocket url({}) is error", url, e); } } try { for (WebSocketClient client : clients) { boolean success = client.connectBlocking(