Nacos 1.4.x 配置管理交互 与 源码简解

以一次 配置推送 解析整个交互过程,理解 Nacos 配置管理的架构
背景知识:长轮询 long-polling(简书:Long Polling长轮询详解),仅需经此一遭便可


Nacos 官方 描述了其命名的由来 Nacos: Dynamic Naming and Configuration Service;按照目前主流的使用场景,Nacos 有两个核心能力:服务注册发现(Naming)和配置中心(Configuration);而这里我们不讨论注册发现和通用基础能力,只讨论配置中心的配置变更如何达成集群的一致性。

一图胜千言

看过了不少 Nacos 的博客文章,但在阐述整体配置的功能时,都没有一个完整的图,说清楚整个集群的配置同步情况,**如何达成集群配置一致?如何做到客户端对配置的实时感知?**虽然图画得不优美,符号也不是准确,期望大体意思是能表述的。

画图水平有待持续提升~

集群成员平等,能力完全一致:Nacos-0 Nacos-1 Nacos-2 只是为了方便描述,各个客户端经过 ALB 后随机连接后端服务
MemoryCache :内存缓存配置元信息 dataId group namespace md5 betaIp 等等,不包含配置的内容
DiskFile :磁盘缓存配置的内容,获取时通过 nio channel.transfer 直接零拷贝返回网络
AsyncTask :异步通知所有集群成员,在失败时有多次重试
配置以数据库为准:管控台的所有操作直接读写数据库,DumpTask 会从数据库取出配置,然后 dump 入 MemoryCache 和 DiskFile

  1. Nacos-0 处理 long-polling 的过程,holding 时会放入 queue 队列;然后等候 LocalDataChangeEvent 事件后,收到事件后告知客户端

  2. Nacos-1 处理 publish-config 的过程,会先写数据库,再发出一个 ConfigDataChangeEvent ;再由 AsyncTask 告知 all Members

    2.1. All Members 处理 DumpTask 的过程,主要是把 数据库为准 的配置 dump 入 MemoryCacheDiskFile
    然后发布一个事件 LocalDataChangeEvent ,转而告知了 (1)

  3. Nacos-2 处理 get-config 的过程,先匹配 MemoryCache 获取配置信息,而配置内容保存在 DiskFile,它由nio channel.transfer 返回

关于 AsyncTask 通知所有集群成员 (包括自己)

  • 好处是更平等地对待集群内的所有成员,发起者自身在处理 DumpTask 时不至于比其他成员提前太多;
    • 若本地内优先处理,由于 LocalDataChangeEvent 让客户端长轮训返回,客户端发起配置获取时,存在延时其他节点尚未 DumpTask 结束,所以会拿到旧配置;然后再发起 long-polling 才可能感知到 md5 有变化而获取到最新配置,最糟糕情况是还没 DumpTask 结束,要 30s 超时后才获得最新变更。

关于 任意客户端 -> 任意服务端 获取配置变更的完备性

  • 讨论极端场景:配置变更完 DumpTask 刚处理结束,LocalDataChangeEvent 还没开始,而 客户端此时发起 listening
    • 这种情况得讨论 客户端的 ClientLongpolling 能否写入到维持队列 queue 里
      • 已写入:则 DataChangeTask 就会正常返回变更通知给 客户端 ·正常
      • 未写入1:存在一个 compare md5 with MemoryCache 的判断过程,由于 DumpTask 的处理已经把变更写入 MemoryCache,此时的 listening 会立马返回 ·正常
      • 未写入2:若已经 compare md5 with MemoryCache 而刚好又没写入 维持队列 queue 里,那是最糟糕情况需 ·兜底
  • 讨论极端场景:客户端被告知配置有变更,发起 get config 请求到另一个服务端
    • 另一个服务端已经过 DumpTask ,此时最新配置获取 ·正常
    • 另一个服务端尚未到 DumpTask 阶段(比较极端),此时仅获得旧配置,客户端再次发起 listening
      • 再次发起 listening,服务端已经过 DumpTask 阶段,此时的 listening 会立马返回,再次发起 get config ·正常
      • 再次发起 listening,服务端还未到 DumpTask 阶段(太极端),那是最糟糕情况需 ·兜底
  • 兜底:最糟糕情况需 30s 超时后,再次请求才能获取到变更。
  • 故障:集群成员间的配置不一致!通知失败、异常等,TODO 需增强的自身一致性检测;目前有 6h/次 全量 dumpAll 的异步 sch 任务。

更优的长连接 gRPC 期待 Nacos 2.x

Http/2 及 gRPC 的一些文章

  • gRPC 长连接在微服务业务系统中的实践 : https://cloud.tencent.com/developer/article/1748323

Nacos 2.x

  • gRPC 长连接 客户端与一个服务端建立长连接,则在服务端重启升级过程中,最后一批启动的会一直没有被连接,会造成整体服务的不均匀性;为此 Nacos 将引入 服务端 主动协调 客户端的均衡策略。

##简解源码 > 走读

注:… 表示异步执行, * 标识重点

###Long-polling .getConfigChange

ConfigController.listener() // The client listens for configuration changes.
    ConfigServletInner.doPollingConfig()
        LongPollingService.addLongPollingClient()
            ... ClientLongPolling.run()
                    create ScheduledFuture: asyncTimeoutFuture // timeout with return null
                    Queue<ClientLongPolling> allSubs.add(ClientLongPolling.this);
        ... **LocalDataChangeEvent**   *// 关键的配置变更事件*
                ... DataChangeTask.run()
                        Queue<ClientLongPolling> allSubs.iterator() // compare and return changeGroupKeys

Nacos 1.4.x 配置管理交互 与 源码简解_第1张图片

###Publish config .change Config

ConfigController.publishConfig()   // Adds or updates non-aggregated data.
    **PersistService.insertOrUpdate()**   *// write into db first*
    **NotifyCenter.publishEvent > ConfigDataChangeEvent**    *// 关键配置变更事件*
        ... AsyncNotifyService.onEvent()
            ConfigExecutor.executeAsyncNotify(new AsyncTask(nacosAsyncRestTemplate, queue)) // async task in queue
                ... AsyncTask.run() executeAsyncInvoke()
                        restTemplate url:(**/v1/cs/communication/dataChange**) // rest get url to notify all members.

Nacos 1.4.x 配置管理交互 与 源码简解_第2张图片

####Notify data change // all members.

CommunicationController.notifyConfigInfo()
    DumpService.dump()
        TaskManager.addTask(taskKey, new DumpTask(..))
            ... DumpProcessor.process()
                **PersistService.findConfigInfo()**   *// get config from db*
                DumpConfigHandler.configDump(ConfigDumpEvent)
                    DumpConfigHandler.configDump()
                        ConfigCacheService.dump()
                            **DiskUtil.saveToDisk(dataId, group, tenant, content)**  *// dump in disk first*
                            ConfigCacheService.updateMd5()
                                MemoryCache.update()                              *// dump in memory second*
                                NotifyCenter.publishEvent > **LocalDataChangeEvent**  *// 关键的配置变更事件*

Nacos 1.4.x 配置管理交互 与 源码简解_第3张图片

在这里插入图片描述Nacos 1.4.x 配置管理交互 与 源码简解_第4张图片Nacos 1.4.x 配置管理交互 与 源码简解_第5张图片

你可能感兴趣的:(java,源码之旅,分布式学习,Nacos,后端,架构,长轮训,long-polling)