前言
近年来伴随着技术的不断进步,微服务概念的深入人心,微服务技术也被大家越来越多的应用在产品中。当企业还没有广泛应用微服务架构的时候,那时对于配置分发的解决方案多种多样,如脚本替换、环境变量读取、手工修改、重启应用等。但是随着微服务架构的盛行,配置管理的难度越来越大,企业亟需一套配置文件管理系统,将已有的应用配置有效管理起来。 面对这个问题,我们可以借助配置中心来管理应用配置。配置中心实现了多套环境、多套版本、多个应用的配置管理。但是随着平台微服务业务的进一步发展,新的问题也随之而来。微服务应用越来越多,配置请求越来越频繁,同时有些微服务对配置的需求更讲究时效性。此外,业务上也希望能够更精确地控制配置替换的影响范围,例如能做到单点应用的配置修改。 为了解决以上问题,我们基于微服务消息推送总线建设了配置中心实时配置推送系统。本文将基于该系统,深入分析配置推送的原理以及框架结构。
1. 核心业务介绍
配置推送业务需求
在建立配置中心推送系统前,我们先设计了一套基于平台微服务SDK的消息推送平台。将配置信息作为消息推送给微服务终端。我们希望该平台能够满足以下需求:
·高性价比,在有限的硬件资源下,尽可能的提高消息系统的性能和可用性;
·推送数据的一致性;
·推送消息的实时性;
·交互简单,学习门槛低,引入方便;
·结合配置分发的实际需求;
·推送失败后的补救处理;
·精确地控制推送范围。
作为消息推送平台的上层应用,配置中心实时推送则需要关注配置分发的业务需求:
·配置推送目标精确选择,包括特定租户、特定应用、特定环境等;
·保证配置推送的正确性;
·配置修改以后及时更新配置信息;
·应用掉线后能够重新获得推送信息。
配置推送服务流程
由配置中心决定置推送时机,如配置新建、配置更新、用户触发的时机等,配置信息发出后将交给终端微服务进行处理,如配置实时生效、重启等。
配置推送请求流程
消息推送平台由Inotify-Manager消息管理组件和Inotify-PushServer消息推送服务器组成。
其中Inotify-Manager负责接收配置中心、用户事件、Web管理页面传来的配置更新事件请求,对请求进行权限校验,并对通过权限校验的消息进行持久化保存。
Inotify-PushServer组件则负责接收Inotify-Manager传输的符合要求的消息信息,并且接收微服务终端中微服务SDK发送的注册请求,如果注册成功则为该终端保存一条消息传输通道,当其接到推送的消息时会根据推送过来的推送坐标选择相应的微服务终端进行推送。
配置推送接收SDK是微服务SDK功能的一部分,其主要逻辑由配置中心SDK和Inotify-SDK配合完成。Inotify-SDK负责根据微服务终端的配置生成消息通道ID(推送坐标)并将该id作为通道标识注册到Inotify-PushServer.当Inotify-PushServer推送消息时SDK也负责接收。接收到的消息为通用消息,配置中心SDK分析通用消息的类型,如果为配置类型则拦截消息进行处理。
2. 技术选型
系统架构图
根据配置分发业务的需求,我们的推送系统需要在硬件资源的有限的条件下具有较高的处理性能,并且满足大量的连接数场景。为此,在技术选型中传统的java.io被直接排除了,改为使用WebSocket协议的的长连接模式框架。Java的WebSocket框架选择比较有限,基本上就是在Netty,Undertow中二选一。Undertow的内存性能比Netty稍差,但是基于代码原因最终平台还是选择了Undertow作为推送服务的基础框架。
消息持久化
客户端上线之后需要将上线前一段时间的消息拉取消费,同时推送的历史消息也需要进行备份留待查询验证。因此消息持久化就成为了一个不可避免的问题。
目前消息推送平台数据量较小,且每次传输的数据多为服务元数据、配置信息、通知微服务终端消息等数据量较小的信息。目前这些信息在推送的同时也存储一份在数据库中,方便进行消息推送失败后的重发,以及后续数据的统计分析。
但是随着业务的日益增加,简单的持久化越来越满足不了需求,在这方面我们也正在积极开展工作。期望通过合理分表分库,使每个表的性能得到保障,并且保证总体的高分发量。在manager端也通过使用异步队列持久化的方式取代目前使用的同步方式,减少数据库的压力,提高消息推送的峰值。
数据传输协议
由于我们的消息推送平台需要维持长连接,因此在协议选择上就面临着两个选择:
·私有二进制协议
·基于HTTP的WebSocket
在综合多方面的考虑以后我们最终选择了WebSocket作为平台数据传输的协议,主要原因有以下几点。首先私有协议虽然性能较好,但是业务上的性能瓶颈往往并不在传输上,而使用WebSocket协议在安全校验、泛用性、开源工具等方面都有良好的支持,客户在使用时门槛也较低。
在传输数据格式方面我们选择了Json,这种格式比较简单、易于扩展且应用广泛。其实现在比较流行的Protobuf在性能上表现更好,序列化以后数据量大大减小,可以考虑在以后的版本中对其提供支持,由用户选择自己需要的序列化方式。
长连接
因为硬件资源有限,又要想维持尽可能多的连接数。在服务端我们采用了Undertow非阻塞时的维持长连接,提高单机所能维持的连接数。与此同时,还需要对失效连接及时进行清理,在高连接数的前提下提高有效连接的数量。
使用WebSocket的客户端与服务器端有可能因为一些情况导致连接中断,这种中断在客户端只有在再次发送消息时能被发现。但是在一些业务场景中,我们的客户端完全是消息的接收端,并不发送消息。在这种情况下,客户端下线后就永远不会再次连接。因此为了保证连接的可持续性和稳定性,我们使用了心跳检测机制,客户端定时发送心跳消息,用于检测网络和前后端连接问题。一旦发现异常,客户端端持续执行重连逻辑,直到重连成功。
3. 与配置推送结合的实现细节
分布式消息推送
消息推送随着业务量的增多,负载必然越来越重。为了满足业务需要,消息平台就需要在高性能的前提下具备水平扩展能力。因此分布式集群是消息平台一项必须的能力。
早期版本的消息推送平台由Nginx作为Router配合使用域名来为各个组件提供服务发现和负载均衡功能,示意图如下:
使用这种方法的前提是需要用户架设消息系统前,先部署一套Nginx-Router,同时还需要拥有域名。由于Client端要直连这两个域名,因此这也导致了一系列的安全问题。另外,PushServer其实是有状态的,故通过Nginx转发来推送消息导致PushServer只能是单点的。
为了解决以上问题,我们采用Zookeeper解决服务发现的问题,并在推送逻辑上加入根据消息组件信息决定的负载均衡机制,提出了新的分布式解决方案。
消息推送平台的各个角色都通过Zookeeper获取所需要的连接的地址。使用这套解决方案,不仅能轻松实现消息平台的集群化,而且也为系统的私有化提供了便利。
SDK消息处理
配置实时推送功能依托于微服务平台的配置中心,消息推送平台,微服务SDK完成自身的功能逻辑。其中当消息到达微服务终端时由微服务SDK对消息进行处理。
最新版本的微服务SDK在配置实时推送的功能上包含了以下两个组件:
·消息推送SDK(Inotify-SDK)
·配置中心SDK(Proteus-SDK)
其中消息推送SDK是可以单独使用的,不依赖微服务、Spring等其他框架。当该SDK引入微服务时则通过微服务插件机制读取微服务的配置信息,建立一条微服务推送通道。任何向该微服务推送的消息都会复用这条通道,减少服务端的压力。
配置中心SDK则提供了微服务配置分发的相关功能。当微服务收到配置分发消息时,同样也是基于微服务SDK插件机制触发相应的消息处理器,收到的消息会带有相关的类型,决定由哪些处理器进行处理。确认类型以后会完成后面的处理逻辑,例如实时更新配置,将消息信息写入文件等。
实质上来说,SDK的消息处理都是基于微服务SDK的插件机制来完成的。消息接收由消息SDK完成,而消息处理则通过插件机制建立一条消息处理的责任链,处于这条链上的处理器选择合适的消息截断进行处理。
配置推送范围
配置文件具有环境、版本、所属应用、租户、状态等多个属性,推送配置文件就需要根据这些文件属性装配出一个文件消息主题,但是我们又不能在消息系统中建立每一个文件的主题,因此配置推送范围这个问题就被提出来了。
为了解决这个问题我们提出了子主题的概念,而这个概念则建立于推送坐标的基础上:
如图所示,推送坐标由多段字符串组成。推送配置时推送坐标的精度越高,则推送范围越小。如果需要广播消息则只需要推送一个类型信息就可以了。
为了提高PushServer检索推送坐标的速度,提高性能,我们使用树形结构存储推送坐标,减少遍历坐标时耗费的时间。
4. 总结与展望
随着微服务业务开展的如火如荼,配置分发压力越发沉重。配置中心配置实时推送系统将拉取配置转化为推送配置,减少了无意义的网络请求,提高了配置更新的实时性,并且将配置分发的数据保存下来为数据统计与分析提供了宝贵的原材料。
与此同时,与配置推送业务一同诞生消息推送系统也多点开花,支撑了配置推送、实时下线、元数据推送、通用消息推送等业务。
基于消息平台和微服务治理平台的高扩展性,在未来消息平台不仅能够承担平台配置分发的工作,也能结合其他业务在功能上做进一步的扩展。为整个开发者中心提供一个可扩展、高可用、通用、易用的的综合消息推送平台。
开发者中心,将因你而变得更加精彩!