A185147e93bb0838b47604d90a2ba52f
Android 架构之秒级移动配置中心

文末可获取进入小专栏读者群方式。

正文

之前的《Android 架构之动态化之路》我们提到的动态化方案一般都是比较大型的,比如React NativeFlutter等都是从UI、运行逻辑等多方面实现完整的动态更新。但实际上,移动端还有很多细粒度的配置类数据需要支持动态更新。

比如某个文案或者按钮位置希望可以根据用户表现来随时改动;又比如你开发了一个线上功能,但上线后才发现里面潜藏了一个严重问题,希望通过一个线上开关立即关闭该功能;再比如之前的文章《高可用移动网络连接》里提到的兜底IP列表,哪天我们服务器发生了问题导致老IP列表全部失效,我们希望能够立即将新IP列表同步给所有客户端。

这类需求用一句黑话来讲,就叫做:不要写死。

Android 里面大家很熟悉 SharedPreference,可以存储很多K-V类型的数据。那我们如何来实现一套可动态更新的K-V存储机制呢?从而将这类小型配置参数AB开关准实时下发到所有客户端。

为了实现这个功能,很多公司研发了自己的一套配置中心系统,比如阿里内部的Orange系统,能够做到秒级下发所有配置到全量客户端。本文就准备带大家一起来设计这样一套配置中心系统。有了它,妈妈再也不用担心把你写的代码发布到线上了,一旦出了问题,把开关一关就好了。

要实现这样一套系统,需要考虑几个问题:

  1. 首先,远端配置更新后,如何实时通知给所有客户端呢?
  2. 配置数据体积越来越大,下载失败率变高,如何优化数据包大小呢?
  3. 配置数据的安全性如何保证?
  4. 如何灰度发布配置?
  5. 实时全量下发的话,CDN会存在什么问题吗?
  6. Android 如何实现多进程监听配置变更?

下面,我会和你一起来逐个探讨这些问题。

如何通知客户端配置更新

首先我们要解决的问题是:如何才能尽快告诉客户端,配置数据已经更新了?

1. 主动拉取(Pull)

第一种方式,我们可以让客户端进行主动轮询:

  • Polling 定时轮询:定时发起请求到后端,拉取最新的配置数据;
  • Long Polling 长轮询:后台起一个Service,持续去发起长轮询判断后端是否有配置数据更新,一旦发现有更新,再发起请求去拉取配置;

关于长轮询说明下,普通的短连接是客户端发起socket请求,服务端收到后,不管有没有数据,都会立即返回;

而如果是长轮询,服务端如果没有数据则会Hold住该请求,将socket等请求信息保存起来,不立即返回,等到有数据时才通过socket重新写回客户端。当客户端收到结果,或者判断请求超时,便会发起下一次长轮询请求。此处的超时时间一般会比正常http请求的超时时间长,比如60s,以减少请求次数。

这种方式可能能够达到比较好的实时性,但很显然,会带来非常多的流量浪费,而且对于后端也会带来非常多无用的请求,造成机器资源浪费。

2. 推送(Push)

第二种方式,我们可以借助长连接通道。前文我们已经点亮了长连接技能树,此处就派上用场了。

当我们发布配置后,可以通过长连接通道向在线用户下发配置变更通知,用户收到通知后便会主动去拉取配置。

这种方式可以极大降低流量损耗,只有配置变更时才会拉取数据。但也存在一些问题:

  • 需要维护稳定长连接通道,存在一定的技术成本;
  • 如果用户长连接断开,会导致无法收到消息,从而不能保证实时变更;

因此,这种方式虽然能节省流量,但并不能够保证100%的实时配置生效率。

3. 推拉结合

既然主动拉取和推送都做不到,很自然的,我们会想到能不能两种方式结合起来,方案如下:

  1. 客户端与服务端保持一个长连接,当有配置变更时,立即下发;
  2. 为防止长连失效导致更新不及时,客户端还会作定期轮询,拉取配置;

通过这种方式,可以获得较低的流量开销和较高的更新率。业界不少企业采用的是类似的方案,比如携程的配置中心系统Apollo

4. 统一网关

这里我们还要介绍第四种更新机制,来自阿里的Orange移动配置系统,它无需任何轮询请求和长连接通道下发,而且可以做到在线用户100%的秒级更新率。

它的秘密就是利用了全集团的统一网关系统,这套网关同时运行在客户端(Android、iOS)和服务端。移动端网关会接管所有客户端的请求,而后端网关则会承接所有移动端发过来的请求。具体流程如下:

  • 客户端的任何网络请求在经过移动端网关时,带上本地配置的版本号;
  • 服务端网关收到请求后,抽取出配置版本号,发送给配置中心服务,其他参数透传给业务后端;
  • 配置中心服务基于当前App的版本号、配置版本号等信息,判断是否有新配置,如果有则返回新配置版本号给网关;
  • 当业务后端返回时,带上这个新配置版本号给客户端;
  • 客户端发现新配置版本号,则去CDN拉取最新配置数据,完成更新。

在这个流程里,我们没有为配置单独发起轮询请求,也不需要依赖长连接服务进行下发。而是借助现有的业务请求,加上网关的协助,来实现配置的动态更新。只要客户端处于活跃状态,就能立即发现配置更新,而且非常稳定。

top Created with Sketch.