从移动端的配置说起

出了什么问题

大多数客户端都有远程配置的功能和需求,项目规模由小到大以后,对客户端动态配置的需求就会迅速增加。就会出现新的问题和需求。

  • 配置项逐渐增多,配置内容大小逐步增大
  • 客户端版本逐渐曾多,版本之间的配置差异较大,配置管理混乱,牵一发而动全身
  • 运营和产品对业务配置的需求逐渐增加,需要有独特的配置关联逻辑
  • 配置不断庞大,下发到客户端的时候需考虑流量问题
  • 配置服务端考虑并发问题
  • 配置动态下发,考虑不同的更新策略,考虑安全性

历史及现状

可能很多移动端的开发者都有这样的经历:
通过某一个接口,获取某一业务功能的配置信息,有时候需要根据业务触发的逻辑,在不同的时机调用接口,获取配置,又有些时候需要把客户端的一些信息,如版本号、时间、上次的缓存等等,传入接口获取最新配置,这其实就是最简单的远程配置需求,根据配置相关条件,通过不同的更新策略,获取远程配置。

1.0阶段

设计接口如下:

$ curl https://api.xxx.com/v0/configuration/getMessageConfig?appVersion=1.0.0&platform=iOS&messageType=1 \
-H "SS-Cache-Version: XXXXXXXXX"

{
    "code":"0",
    "result":{
        "config_value":"******",
        "cache_version":"******"
    }
}

通过不断开发新的接口,满足各个业务线对配置功能需求。
优点:需求较少的时候,开发特别快
缺点:客户端需要不断开发新的API调用,服务端则需要不断开发新接口,配置与客户端的关联信息发生变化,API则需要进行升级,而客户端存在多版本并存的情况,老版本API也无法下线,占用服务端资源。

2.0阶段

为减轻服务端开发依赖,有的开发者通过使用第三方开发平台进行配置分发。
例如,使用umeng的在线参数进行远程配置

image

优点:
无需服务端开发,第三方实现SDK与其服务端的通信,不需要做客户端开发

缺点:
无法与客户端信息做相关,只能通过约定配置参数名称例如 配置项名称+平台名称+客户端版本作为配置项名称,做硬关联,大量生成重复配置项。无法控制更新策略。业务相关配置放置在第三方平台,无法保证数据安全。

3.0阶段

由此前的经历和需求痛点,我们设计出新的移动端配置中心。
主要有如下功能

  1. 支持配置客户端信息与配置项相关,做到不同的客户端获取不同的配置项
  2. 支持配置增量更新
  3. 支持客户端配置加密下发,保证安全
  4. 提供统一后台配置界面,方便进行配置的管理
  5. 做到配置更新,主动推送到客户端
  6. 支持配置回滚,删除恢复

解决思路

根据以上需求,整体方案的解决思路可以是如下这样:

  1. 移动端开发远程配置组件,用于获取最新的后端配置
  2. 客户端与接口交互的时候,将诸如appid(存在对个应用)、appVersion、platform、channel(渠道)、systemVersion等基础信息传入接口,方便配置项与其关联
  3. 客户端与接口交互的时候,支持全量更新,支持通过生成增量包进行增量更新
  4. 服务端与客户端进行数据传输的时候,进行通信数据加密
  5. 对于服务端,客户端提供定时配置同步策略,服务端通过推送和长连接通讯主动推送配置
  6. 配置项后台的增删改查,都采取版本叠加,而不是重新覆盖,支持回滚与删除回复
  7. 通过标签系统,提供更灵活的配置项与客户端的匹配关系

涉及方面

有了大概的解决思路以后,可以对涉及到的方面进行整体盘点,其实这也是移动端基础设施的摸查,涉及以下几个方面:


image
  • 客户端配置组件,与配置中心交互,获取配置信息,定时轮询更新策略,内存缓存与本地持久化配置信息,增量包应用,接收服务端推送事件
  • 配置中心,提供对客户端获取配置的API接口服务,接口支持根据客户端信息和标签返回增量数据包/全量更新包
  • 后台管理系统,提供应用管理和配置管理,支持新建配置,修改配置,回滚和删除配置
  • 认证服务,客户端通过认证服务以后,获取通讯管道加密的会话密钥,提供接口数据加密功能
  • 标签系统,提供对客户端、设备、用户等多个维度的标签设置和获取服务
  • 消息中心,提供根据标签系统,将配置更新的事件推送到客户端
  • 定时任务系统,提供定时服务,将配置生效、推送配置等设置为定时任务

整体设计

API设计

客户端与配置中心进行API交互,接口定义如下:
queryConfiguration
入参:

  • clientInfo,包含appid、appVersion、platform、channel等
  • cacheInfo
{
    "clientInfo":{
        "appid":"***",
        "appVersion":"1.0.0",
        "platform":"1", //1为iOS 2为Android
        "channel":"AppStore"
    },
    "cacheInfo":[{
            "configName":"routerConfigMap",
            "version":"*****"
        },
        {
            "configName":"conditionConfiguration",
            "version":"*****"
        }
    ]
}

返回值:

  • configurationData,一个数组,包含配置项全量或者增量数据包
code 含义 备注
0 增量包 返回增量包数据
1 全量数据 返回配置全量数据
2 已删除 表示该配置项已删除
{
    configurationData:[
        {
            "configName":"routerConfigMap",
            "version":"*****",
            "code":0,
              "hash":"*****",
            "patch":[]
        },
        {
            "configName":"orderActivity",
            "version":"xxxxxx",
            "code":1,
              "hash":"*****",
            "value":"xxxxx"
        },
        {
            "configName":"conditionConfiguration",
            "version":"xxxxxx",
            "code":2
        },
    ]
}

客户端与API交互流程图


image

配置中心管理平台

App管理平台

image

配置平台

image
image

配置管理后台,提供对应用的管理与配置项的管理,配置项与基本客户端信息关联。
配置项存储与客户端信息进行关联映射,关系有OR和AND两种,每个配置项设置关联条件。例如配置项的关联条件为:

configId <—> appId AND appVersion AND channel AND platform OR tag

image

新建、更新或者删除某一配置,可以设置定时生效,Job系统会定时执行操作,并调用消息中心,按照关联条件,进行推送通知给客户端,客户端接到更新事件后,再调用API接口完成配置项更新。

服务端查询配置项流程

image

这个流程里有三个关键点:

  1. 根据clientInfo查询匹配的配置列表,其中,AND关系和OR关系,需要通过构建一个配置id与条件的字典表,查询的时候将AND或者OR的条件相关的配置id全部查询出来,然后进行AND计算(取交集),OR计算取并集,其中appVersion是一个范围,例如设置某一配置项的appVersion为”<=2.3.0 & >=2.1.0”, 根据语义化版本,进行单独匹配,语义化版本 2.0.0 | Semantic Versioning的规范请详细查看文档
  2. 如果客户端上传有cacheInfo,将缓存的配置id列表上传,那么,根据条件查出的最新配置id列表为A,上传的缓存配置id列表为B,分别计算出A与B的交集,逐个对比hash值,算出增量包,再算出属于A但不属于B的部分,属于新增配置项,做全量包,再算出属于B不属于A的,属于要删除的部分。进行上述计算,只需要定义一套数组的交集、并集与补集的计算,就可计算出结果。
  3. 生成增量包的时候,需要根据客户端配置id和对应hash值,找到旧版本的配置项,再跟最新的配置项做文本对比生成增量包。文本增量算法有google官方实现的一套:GitHub - google/diff-match-patch: Diff Match Patch is a high-performance library in multiple languages that manipulates plain text.

推送更新消息

这个比较简单,通过后台增删改查的配置项,根据其标签和客户端信息,使用消息中心,将更新事件静默推送到设备,而设备客户端信息和标签,与设备唯一标示的绑定关系,在标签系统维护。

总结改进

新的配置中心,满足了现阶段的需求,通过将配置项的关联条件抽象成标签,再加上增量更新,满足了节省流量的需求。
未来还有进一步改进的空间:

  1. 配置后台通过jsonschema来效验配置的格式,方式配置错误
  2. 客户端的配置组件改善通讯方式,使用推拉结合的方式,目前的推送基于消息中心,未来可以使用UDP+心跳方式维持客户端与服务端的数据同步
  3. 实现更多的更新发布场景,例如,更新配置项,可按照一定比例,逐步进行灰度更新,失败可回退,提高可用性

多谢您花费宝贵的时间阅读,希望能够与大家多多交流

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容