拉模式主要是在客户端按照订阅关系发起主动拉取过程。客户端在首次订阅能够进行一次相关服务 ID 的服务列表查询,并拉取到本地缓存,后续经过长轮询按期进行服务端服务 ID 的版本变动检测,若是有新版本变动则及时拉取更新本地缓存达到和服务端一致。这种模式在服务端能够不进行订阅关系的存储,只须要存储和更新服务发布数据。由客户端主动发起的数据获取过程,对于客户端实现较重,须要主动获取和定时轮训,服务端只须要关注服务注册信息的变动和健康状况及时更新内存。这个过程因为存在轮训周期,对于时效性要求不高的状况比较适用。
**SOFARegistry 服务发现模式采用的是推拉结合方式。**客户端订阅信息发布到服务端时能够进行一次地址列表查询,获取到全量数据,而且把对应的服务 ID 版本信息存储在 Session 回话层,后续若是服务端发布数据变动,经过服务 ID 版本变动通知回话层 Session,Session 由于存储客户端订阅关系,了解哪些客户端须要这个服务信息,再根据版本号大小决定是否须要推送给这个版本较旧的订阅者,客户端也经过版本比较肯定是否更新本次推送的结果覆盖内存。此外,为了不某次变动通知获取失败,按期还会进行版本号差别比较,按期去拉取版本低的订阅者所需的数据进行推送保证数据最终一致。
主动获取:服务订阅信息注册到服务端时,须要查询全部的服务提供方地址,而且须要将查询结果推送到客户端。这个主动查询而且拉取的过程,推送端是一个固定的客户端订阅方,不涉及服务 ID 版本信息断定,直接获取列表进行推送便可,主要发生在订阅方应用刚启动时刻,这个时期可能没有服务发布方发布数据,会查询到空列表给客户端,这个过程基本上相似一个同步过程,体现为客户端一次查询结果的同步返回。
版本变动:为了肯定服务发布数据的变动,咱们对于一个服务不只定义了服务 ID,还对一个服务 ID 定义了对应的版本信息。服务发布数据变动主动通知到 Session 时,Session 对服务 ID 版本变动比较,高版本覆盖低版本数据,而后进行推送。此次推送是比较大面积的推送,由于对于这个服务 ID 感兴趣的全部客户端订阅方都须要推送,而且须要按照不一样订阅维度和不一样类型的客户端进行数据组装,进行推送。这个过程数据量较大,而且须要全部订阅方都推送成功才能更新当前存储服务 ID 版本,须要版本更新确认,因为性能要求必须并发执行而且异步肯定推送成功。
按期轮训:由于有了服务 ID 的版本号,Session 能够按期发起版本号比较,若是Session 存储的的服务 ID 版本号高于dataServer存储的 ,Session再次拉取新版本数据进行推送,这样避免了某次变动通知没有通知到全部订阅方的状况。
服务推送性能优化
服务订阅方的数量决定了数据推送一次的数量,对于一台 Session 机器来讲目前咱们存储 sub 数量达到60w+,若是服务发布方频繁变动,对于每次变动推送量是巨大的,故咱们对整个推送的过程进行优化处理:
即便对服务变动进行了合并延迟处理,可是推送任务产生也是巨大的,因此对于瞬间产生的这么大的任务量进行队列缓冲处理是必须的。目前进行全部推送任务会根据服务 ID、推送方 IP 和推送方信息组成惟一任务 ID 进行任务入队处理。队列当中若是是相同的服务变动产生推送任务,则进行任务覆盖,执行最后一次版本变动的任务。此外任务执行进行分批次处理,批次大小能够配置,每一个批次处理完成再获取任务批次进行处理。
补偿措施:对于推送失败以前也说有定时任务进行轮训服务 ID 版本,服务 ID 的版本在全部推送方都接受到这个版本变动推送才进行更新,若是有一个订阅方推送失败,就不更新版本。后续持续检查版本再启动任务,对没有推送成功的订阅方反复执行推送,直到推送成功或者订阅方不存在,这个过程相似于无限重试的过程。
数据处理分阶段
注册中心数据的来源主要来自于两个方向,一个是大量应用客户端新链接上来而且发布和订阅数据并存储在注册中心的阶段,另一个是以前这些发布的服务数据必须按照订阅方的需求推送出去的阶段。这两个阶段数据量都很是巨大,都在首次部署注册中心后发生,若是同时对服务器进行冲击网络和 CPU 都会成为瓶颈,故咱们经过运维模式进行了两个阶段数据的分离处理:
关闭推送开关:咱们在全部注册中心启动初期进行了推送开关关闭的处理,这样在服务注册中心新启动或者新发布初期,由于客户端有本地缓存,在推送关闭的状况下,注册中心的启动只从客户端新注册数据,没有推送新的内容给客户端,作到对现有运行系统最小影响。而且,因为推送关闭,数据只处理新增的内容这样对网络和 CPU 压力减小。