java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Alibaba Nacos配置中心动态感知

Alibaba Nacos配置中心动态感知原理示例解析

作者:Mr.Fire

这篇文章主要介绍了Alibaba Nacos配置中心动态感知原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

Nacos提供两大核心功能,服务注册发现,配置中心。对应Nacos的架构图,分别是Naming Service和Config Service,其中Config Service是实现配置中心的核心模块。实现了版本管理、灰度发布、监听管理、推送轨迹等功能。针对配置中心,当我们通过控制台或API修改配置之后,客户端能动态获取到修改后的配置,那么配置中心是如何实现动态感知的呢?

动态监听之Pull和Push

当Nacos Config Server上的配置发生变化时,需要让相关的应用程序感知到配置的变化,这就需要客户端对感兴趣的配置实现监听。那么客户端是如何实现配置变更实时更新的呢?

一般来说,客户端与服务端的交互无非两种:Pull模式和Push模式,一个是客户端主动拉取,一个是服务端主动推送。

Nacos的Pull模式

Nacos采用的是Pull模式,不过不是简单的Pull,而是一种长轮询机制。结合Pull和Push两者的优势,客户端采用长轮询的方式发起Pull请求,检查服务配置消息是否发生变化,如果更新,客户端会根据变更的内容获取最新配置信息。

所谓的长轮询,就是客户端发起Pull请求之后,服务端如果发生配置变更则立即返回,如果服务端和客户端配置是保持一致的,那么服务端会“Hold”住这个请求,在指定时间内不返回结果,直到这段时间内配置发生变化。这个长连接默认超时时间是30s。

服务端收到请求后,先检查配置是否发生变化,如果没变化,则设置一个定时任务,延期29.5s执行,并且把当前的客户端长轮询连接加入allSubs队列。这里有两种方式触发连接返回。

Nacos的动态感知

前面我们已经知道客户端通过长轮询请求来获取配置变更,但是定时任务是延迟执行的,那并没有达到实时的目的,当通过控制台或者API修改配置时,那Nacos是如何实时动态更新的呢?

LongPollingService 监听事件类

LongPollingService继承AbstractEventListenerAbstractEventListener是事件抽象类,它有一个onEvent抽象方法,而LongPollingService实现了这个方法

@Override
public void onEvent(Event event) {
    if (isFixedPolling()) {
        // ignore
    } else {
        if (event instanceof LocalDataChangeEvent) {
            LocalDataChangeEvent evt = (LocalDataChangeEvent)event;
            scheduler.execute(new DataChangeTask(evt.groupKey, evt.isBeta, evt.betaIps));
        }
    }
}

LongPollingService可以看到LocalDataChangeEvent事件,这个事件是服务端的配置数据发生变化时发布的一个事件。onEvent方法中通过线程池来执行一个DataChangeTask任务。

DataChangeTask线程

DataChangeTask是一个线程,实现了Runnable接口,对应的run()如下:

class DataChangeTask implements Runnable {
    @Override
    public void run() {
        try {
            ConfigService.getContentBetaMd5(groupKey);
            for (Iterator<ClientLongPolling> iter = allSubs.iterator(); iter.hasNext(); ) {
                ClientLongPolling clientSub = iter.next();
                if (clientSub.clientMd5Map.containsKey(groupKey)) {
                    // 如果beta发布且不在beta列表直接跳过
                    if (isBeta && !betaIps.contains(clientSub.ip)) {
                        continue;
                    }
                    // 如果tag发布且不在tag列表直接跳过
                    if (StringUtils.isNotBlank(tag) && !tag.equals(clientSub.tag)) {
                        continue;
                    }
                    getRetainIps().put(clientSub.ip, System.currentTimeMillis());
                    iter.remove(); // 删除订阅关系
                    LogUtil.clientLog.info("{}|{}|{}|{}|{}|{}|{}",
                        (System.currentTimeMillis() - changeTime),
                        "in-advance",
                        RequestUtil.getRemoteIp((HttpServletRequest)clientSub.asyncContext.getRequest()),
                        "polling",
                        clientSub.clientMd5Map.size(), clientSub.probeRequestSize, groupKey);
                    clientSub.sendResponse(Arrays.asList(groupKey));
                }
            }
        } catch (Throwable t) {
            LogUtil.defaultLog.error("data change error:" + t.getMessage(), t.getCause());
        }
    }
    DataChangeTask(String groupKey) {
        this(groupKey, false, null);
    }
    DataChangeTask(String groupKey, boolean isBeta, List<String> betaIps) {
        this(groupKey, isBeta, betaIps, null);
    }
    DataChangeTask(String groupKey, boolean isBeta, List<String> betaIps, String tag) {
        this.groupKey = groupKey;
        this.isBeta = isBeta;
        this.betaIps = betaIps;
        this.tag = tag;
    }
    final String groupKey;
    final long changeTime = System.currentTimeMillis();
    final boolean isBeta;
    final List<String> betaIps;
    final String tag;
}

总结

好了,最后整理下nacos实时动态感知的流程如下:

以上就是Alibaba Nacos配置中心动态感知原理示例解析的详细内容,更多关于Alibaba Nacos配置中心动态感知的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文