Apollo服务端设计原理剖析

栏目: Java · 发布时间: 5年前

内容简介:本文摘自于配置中心最重要的一个特性就是实时推送了,正因为有这个特性,我们可以依赖配置中心做很多事情。在我自己开发的Smconf这个配置中心,Smconf是依赖于Zookeeper的Watch机制来实现实时推送。

本文摘自于 《Spring Cloud微服务 入门 实战与进阶》 一书。

1 配置发布后的实时推送设计

配置中心最重要的一个特性就是实时推送了,正因为有这个特性,我们可以依赖配置中心做很多事情。在我自己开发的Smconf这个配置中心,Smconf是依赖于Zookeeper的Watch机制来实现实时推送。

Apollo服务端设计原理剖析

上图简要描述了配置发布的大致过程:

  • 用户在Portal中进行配置的编辑和发布

  • Portal会调用Admin Service提供的接口进行发布操作

  • Admin Service收到请求后,发送ReleaseMessage给各个Config Service,通知Config Service配置发生变化

  • Config Service收到ReleaseMessage后,通知对应的客户端,基于Http长连接实现

2 发送ReleaseMessage的实现方式

ReleaseMessage消息是通过 Mysql 实现了一个简单的消息队列。之所有没有采用消息中间件,是为了让Apollo在部署的时候尽量简单,尽可能减少外部依赖。

Apollo服务端设计原理剖析

上图简要描述了发送ReleaseMessage的大致过程:

  • Admin Service在配置发布后会往ReleaseMessage表插入一条消息记录

  • Config Service会启动一个线程定时扫描ReleaseMessage表,去查看是否有新的消息记录

  • Config Service发现有新的消息记录,那么就会通知到所有的消息监听器

  • 消息监听器得到配置发布的信息后,则会通知对应的客户端

3 Config Service通知客户端的实现方式

通知是采用基于Http长连接实现,主要分为下面几个步骤:

  • 客户端会发起一个Http请求到Config Service的notifications/v2接口

  • v2接口通过Spring DeferredResult把请求挂起,不会立即返回

  • 如果在60秒内没有该客户端关心的配置发布,那么会返回Http状态码304给客户端

  • 如果发现配置有修改,则会调用DeferredResult的setResult方法,传入有配置变化的namespace信息,同时该请求会立即返回

  • 客户端从返回的结果中获取到配置变化的namespace后,会立即请求Config Service获取该namespace的最新配置

4 源码解析实时推送设计

Apollo推送这块代码比较多,就不在本书中详细分析了,我把推送这块的代码稍微简化了下,给大家进行讲解,这样理解起来会更容易。当然我这边会比较简单,很多细节就不做考虑了,只是为了能够让大家明白Apollo推送的核心原理。

发送ReleaseMessage的逻辑我们就写一个简单的接口,用队列存储,测试的时候就调用这个接口模拟配置有更新,发送ReleaseMessage消息。

消息发送之后,前面我们有讲过Config Service会启动一个线程定时扫描ReleaseMessage表,去查看是否有新的消息记录,然后取通知客户端,这边我们也启动一个线程去扫描:

循环去读取NotificationControllerV2中的队列,如果有消息的话就构造一个ReleaseMessage的对象,然后调用NotificationControllerV2中的handleMessage()方法进行消息的处理。

ReleaseMessage就一个字段,模拟消息内容:

接下来,我们看handleMessage做了什么样的工作

NotificationControllerV2实现了ReleaseMessageListener接口,ReleaseMessageListener中定义了handleMessage()方法。

handleMessage就是当配置发生变化的时候,通知的消息监听器,消息监听器得到配置发布的信息后,则会通知对应的客户端:

Apollo的实时推送是基于Spring DeferredResult实现的,在handleMessage()方法中可以看到是通过deferredResults获取DeferredResult,deferredResults就是第一行的Multimap,Key其实就是消息内容,Value就是DeferredResult的业务包装类DeferredResultWrapper,我们来看下DeferredResultWrapper的代码:

通过setResult()方法设置返回结果给客户端,以上就是当配置发生变化,然后通过消息监听器通知客户端的原理,那么客户端是在什么时候接入的呢?

NotificationControllerV2中提供了一个/getConfig的接口,客户端在启动的时候会调用这个接口,这个时候会执行getApolloConfigNotifications()方法去获取有没有配置的变更信息,如果有的话证明配置修改过,直接就通过deferredResultWrapper.setResult(newNotifications);返回结果给客户端了,客户端收到结果后重新拉取配置的信息进行覆盖本地的配置。

如果getApolloConfigNotifications()方法没有返回配置修改的信息,证明配置没有发生修改,就将DeferredResultWrapper对象添加到deferredResults中,等待后续配置发生变化时消息监听器进行通知。

同时这个请求就会挂起,不会立即返回,挂起是通过DeferredResultWrapper中的下面的代码实现的:

在创建DeferredResult对象的时候指定了超时的时间和超时后返回的响应码,如果60秒内没有消息监听器进行通知,那么这个请求就会超时,超时后客户端就收到的响应码就是304。

整个Config Service的流程就走完了,接下来我们看客户端是怎么实现的,我们简单的写个测试类模拟客户端注册:

首先启动/getConfig接口所在的服务,然后启动客户端,客户端就会发起注册请求,如果有修改直接获取到结果,进行配置的更新操作。如果无修改,请求会挂起,这边客户端设置的读取超时时间是90秒,大于服务端的60秒超时时间。

每次收到结果后,无论是有修改还是没修改,都必须重新进行注册,通过这样的方式就可以达到配置实时推送的效果。

我们可以调用之前写的/addMsg接口来模拟配置发生变化,调用之后客户端就能马上得到返回结果。

本文摘自于 《Spring Cloud微服务 入门 实战与进阶》 一书。

Apollo服务端设计原理剖析

去年出版的 《Spring Cloud微服务:全栈技术与案例解析》 一书,得到了大家的支持以及反馈,基于大家的反馈,重新进行了更正和改进。

基于比较稳定的 Spring Cloud Finchley.SR2 版本和 Spring Boot 2.0.6.RELEASE 版本编写。

同时将示列代码进行标准的归档,之前的都在一起,不方便读者参考和运行。

Apollo服务端设计原理剖析

Apollo服务端设计原理剖析

同时还增加了像Apollo,Spring Cloud Gateway,生产实践经验等新的内容。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Art of Computer Programming, Volume 4,  Fascicle 3

The Art of Computer Programming, Volume 4, Fascicle 3

Donald E. Knuth / Addison-Wesley Professional / 2005-08-05 / USD 19.99

Finally, after a wait of more than thirty-five years, the first part of Volume 4 is at last ready for publication. Check out the boxed set that brings together Volumes 1 - 4A in one elegant case, and ......一起来看看 《The Art of Computer Programming, Volume 4, Fascicle 3》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具