Nacos 服务端创建了相关的配置项后,客户端就可以进行监听了。客户端是通过一个定时任务来检查自己监听的配置项的数据的,一旦服务端的数据发生变化时,客户端将会获取到最新的数据,并将最新的数据保存在一个 CacheData 对象中,然后会重新计算 CacheData 的 md5 属性的值,此时就会对该 CacheData 所绑定的 Listener 触发 receiveConfigInfo 回调。
考虑到服务端故障的问题,客户端将最新数据获取后会保存在本地的 snapshot 文件中,以后会优先从文件中获取配置信息的值。
那么客户端如何感知到数据发生变化的呢?
我们知道客户端会有一个长轮训的任务去检查服务器端的配置是否发生了变化,如果发生了变更,那么客户端会拿到变更的 groupKey 再根据 groupKey 去获取配置项的最新值更新到本地的缓存以及文件中,那么这种每次都靠客户端去请求,那请求的时间间隔设置多少合适呢?
长轮训的概念:
客户端发起一个请求到服务端,服务端收到客户端的请求后,并不会立刻响应给客户端,而是先把这个请求hold住,然后服务端会在hold住的这段时间检查数据是否有更新,如果有,则响应给客户端,如果一直没有数据变更,则达到一定的时间(长轮训时间间隔)才返回。
长轮训典型的场景有: 扫码登录、扫码支付。
timeout是在init这个方法中赋值的,默认情况下是30秒,可以通过configLongPollTimeout进行修改,但是源码中delayTime字段用于作为结束监听返回数据的时间间隔,所以等待的时间一般是略小于30秒。
ClientLongPolling 被提交给 scheduler 执行之后,实际执行的内容可以拆分成以下四个步骤:
- 1.创建一个调度的任务,调度的延时时间为 29.5s
- 2.将该 ClientLongPolling 自身的实例添加到一个 allSubs 中去
- 3.延时时间到了之后,首先将该 ClientLongPolling 自身的实例从 allSubs 中移除
- 4.获取服务端中保存的对应客户端请求的 groupKeys 是否发生变更,将结果写入 response 返回给客户端
在过程中总共分两种情况,第一种在监听过程中发生变化,第二种就是超时之后执行检测后返回
第一种(等待期发生变化)
第二种(等待期未发生变化)
最后通过一些问题来加强理解
- nacos是采用推还是拉
实时感知是建立在客户端拉和服务端“推”的基础上,但是这里的服务端“推”需要打上引号,因为服务端和客户端直接本质上还是通过 http 进行数据通讯的,之所以有“推”的感觉,是因为服务端主动将变更后的数据通过 http 的 response 对象提前写入了。
- 客户端长轮询的响应时间会受什么影响
客户端长轮询的响应时间,设置的是30s,但是有时响应很快,有时响应很慢,这取决于服务端的配置有没有发生变化。当配置发生变化时,响应很快就会返回,当配置一直没有发生变化时,会等到 29.5s 之后再进行响应。
- 为什么更改了配置信息后客户端会立即得到响应
因为服务端会在更改了配置信息后,找到具体的客户端请求中的 response,然后直接将结果写入 response 中,就像服务端对客户端进行的数据 “推送” 一样,所以客户端会很快得到响应。
- 客户端的超时时间为什么要设置为30s
这应该是一个经验值,该超时时间关系到服务端调度任务的等待时间,服务端在前29.5s 只需要进行等待,最后的 0.5s 才进行配置变更检查。