soul源码阅读(十四)websocket bootstrap同步

目录

问题开头

bootstrap同步

总结


问题开头

(1)admin跟bootstrap websocket创建连接后,如果在收发消息过程中消息丢失,如何知晓,且通过补救措施,保证消息一致?

答:没看到admin端有自动重试的功能啥的,但想起页面有同步功能,那么会不会是页面同步做了这么个补救措施?查看源码如下:

果然每次同步都会去发送消息给到soul网关,那么疑问先到此为止,继续看soul网关看看,还有没有其它的机制来保障消息同步的事情。

bootstrap同步

以上是bootstrap端处理的流程图。

@Configuration
@ConditionalOnClass(WebsocketSyncDataService.class)
@ConditionalOnProperty(prefix = "soul.sync.websocket", name = "urls")
@Slf4j
public class WebsocketSyncDataConfiguration {
    @Bean
    public SyncDataService websocketSyncDataService(final ObjectProvider<WebsocketConfig> websocketConfig, final ObjectProvider<PluginDataSubscriber> pluginSubscriber,
                                           final ObjectProvider<List<MetaDataSubscriber>> metaSubscribers, final ObjectProvider<List<AuthDataSubscriber>> authSubscribers) {
        log.info("you use websocket sync soul data.......");
        return new WebsocketSyncDataService(websocketConfig.getIfAvailable(WebsocketConfig::new), pluginSubscriber.getIfAvailable(),
                metaSubscribers.getIfAvailable(Collections::emptyList), authSubscribers.getIfAvailable(Collections::emptyList));
    }
    @Bean
    @ConfigurationProperties(prefix = "soul.sync.websocket")
    public WebsocketConfig websocketConfig() {
        return new WebsocketConfig();
    }
}

soul-spring-boot-starter-sync-data-websocket的WebsocketSyncDataConfiguration会在网关启动的时候去读取配置文件的soul.sync.websocket.urls属性,然后注册websocketSyncDataService对象到spring 容器中。

 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(3000, TimeUnit.MILLISECONDS);
                if (success) {
                    log.info("websocket connection is successful.....");
                } else {
                    log.error("websocket connection is error.....");
                }
                executor.scheduleAtFixedRate(() -> {
                    try {
                        if (client.isClosed()) {
                            boolean reconnectSuccess = client.reconnectBlocking();
                            if (reconnectSuccess) {
                                log.info("websocket reconnect is successful.....");
                            } else {
                                log.error("websocket reconnection is error.....");
                            }
                        }
                    } catch (InterruptedException e) {
                        log.error("websocket connect is error :{}", e.getMessage());
                    }
                }, 10, 30, TimeUnit.SECONDS);
            }
            /* client.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxyaddress", 80)));*/
        } catch (InterruptedException e) {
            log.info("websocket connection...exception....", e);
        }

    }

在new WebsocketSyncDataService初始化逻辑中,可以看到会拿到url创建soulWebSocketClient,同时会启动一个线程池,扫描并对断线的client进行断线重连。

接下来就来到了核心类SoulWebsocketClient,每次创建连接后会进入onOpen方法,在这个方法里边有个参数alreadySync,默认给的是false,为false情况下,会去请求admin端做一次全量同步,否则不会同步。而这个位置笔者观察到只有首次启动的时候才是false。如果是断线重连,参数也会为true,也就说明断线重连并不会请求全量同步。(模拟断线重连,admin进程关掉,然后再重启,网关就会进行重连)。

@Override
    public void onMessage(final String result) {
        handleResult(result);
    }
   
    @SuppressWarnings("ALL")
    private void handleResult(final String result) {
        WebsocketData websocketData = GsonUtils.getInstance().fromJson(result, WebsocketData.class);
        ConfigGroupEnum groupEnum = ConfigGroupEnum.acquireByName(websocketData.getGroupType());
        String eventType = websocketData.getEventType();
        String json = GsonUtils.getInstance().toJson(websocketData.getData());
        websocketDataHandler.executor(groupEnum, json, eventType);
    }

onMessage方法为收到admin端发送的消息后就会调用此方法进行消息的消费处理,该方法李调用了hadleResult方法,此方法调用WebsocketDataHandler.executor。

该方法做的事情就是交给对应的handle处理。这里面又用了一个设计模式,叫抽象模板模式。

  protected abstract List<T> convert(String json);

    protected abstract void doRefresh(List<T> dataList);

    protected abstract void doUpdate(List<T> dataList);

    protected abstract void doDelete(List<T> dataList);

    @Override
    public void handle(final String json, final String eventType) {
        List<T> dataList = convert(json);
        if (CollectionUtils.isNotEmpty(dataList)) {
            DataEventTypeEnum eventTypeEnum = DataEventTypeEnum.acquireByName(eventType);
            switch (eventTypeEnum) {
                case REFRESH:
                case MYSELF:
                    doRefresh(dataList);
                    break;
                case UPDATE:
                case CREATE:
                    doUpdate(dataList);
                    break;
                case DELETE:
                    doDelete(dataList);
                    break;
                default:
                    break;
            }
        }
    }
AbstractDataHandler只做handle的类型判断,具体的doxxxx方法不做任何实现,有继承它的子类实现,也就是RuleDataHandler等xxxxHandler做最终的逻辑处理。

不难看出xxHandler的处理逻辑是会将data数据缓存到一个map里,同步会进行hadler.handlerxxx处理。

总结

以上介绍了websocket bootstrap同步的整个流程,最简单的跟踪方法就是可以再soul-admin页面打开和观察一个插件开关,然后断点调试查看,这里就不做演示了。

到最后,有一个小疑惑?

在onOpen方法里为啥加了个开关控制?如果由于网络抖动原因,双方连接断开了,admin发送消息的时候将直接丢弃消息,那么网关消息就丢失了,之后重连进入onOpen方法,由于加了开关,并不会进行全量同步,此时只能人工线上手工同步,而这对于线上使用来说是一个大问题,此问题暂时没有答案,不妨往下继续研究,或者官方再找找答案。

猜你喜欢

转载自blog.csdn.net/he_cha_bu/article/details/113276253