有贊 App 動態(tài)化配置中心實踐

背景

客戶端大量的硬編碼導致其靈活性大大降低,一些細小的改動只能通過發(fā)布版本解決,用戶升級更新迭代速度慢,時效性差等原因,催生出了有贊 App 的動態(tài)化配置中心,它可以將配置,功能,界面,數(shù)據(jù)等各種配置數(shù)據(jù)統(tǒng)一進行管理下發(fā),實時生效,極大地提升了客戶端的靈活性。

同時配置中心不僅僅是簡單的對配置數(shù)據(jù)進行修改、讀取而已,更需要在容錯性、流量優(yōu)化、帶寬節(jié)省等各方面的優(yōu)化上下功夫。本文主要提供了有贊 App 的動態(tài)化配置中心解決方案,也總結了版本迭代中所做的優(yōu)化。

配置中心設計

起初有贊各 App 內都散落著一些寫死的鏈接,但隨著 WWDC 16 中,Apple 表示將繼續(xù)在 iOS 10 和 macOS 10.12 里收緊對普通 HTTP 的訪問限制,并且無法使用 NSAllowsArbitraryLoads 來繞過 ATS 限制。我們只能很費時費力的把各 App 內所有訪問 HTTP 的鏈接都修改成 HTTPS,這一個小小的改動就如此麻煩,那后續(xù)大的改動更難以想象,所以我們開始思考能否將這些重復且動態(tài)的工作抽象成一個配置中心,用它來支撐各個業(yè)務。

第一版

第一版設計的相對簡單,我們只是專門設計了一個 API,通過 API 請求配置數(shù)據(jù),并且每個業(yè)務單獨維護一份配置文件。

具體流程:客戶端進入到前臺,也就是應用程序被激活的時候,通過配置中心的接口向服務端請求最新的配置數(shù)據(jù),如果配置文件有更新,則下發(fā)最新的配置給客戶端,并且客戶端本地存儲這份最新的配置,用于應用運行時使用。



但隨著模塊化的推進和應用數(shù)量的增加,配置文件的體積和數(shù)量會逐漸增大,每一次修改都會全量下發(fā)到客戶端,這部分的流量累積起來是一個非常龐大的數(shù)字。并且使用配置文件去管理配置,只能維護到最新的配置,無法做到下發(fā)指定版本的配置。

所以針對這些弊端問題,我們衍生出了第二版配置中心。

第二版

為了解決第一版產生的流量浪費和配置管理弱的問題,我們優(yōu)化了配置下發(fā)和管理流程,我們采取的策略是增量更新數(shù)據(jù)庫存儲配置。

具體流程改動:


增量更新

增量更新的優(yōu)勢主要體現(xiàn)在業(yè)務增長的過程中。我們的配置文件可能會從幾十 KB 增長到幾百 KB 甚至更大,如果還繼續(xù)使用全量更新,這部分流量對用戶來說是非常浪費的。而使用增量更新之后,服務端只需要下發(fā)不同配置之間的差異補丁包,補丁包的大小相比于原始配置的大小是非常小的,可以節(jié)省下90%左右的流量,這是非??捎^的。

增量更新我們目前使用的是 Google 出的 google-diff-match-patch ,支持 Java, JavaScript, Dart, C++, C#, Objective-C, Lua 和 Python,但是官網(wǎng)已經下掉了該 SDK(不明白為什么),需要到 GitHub 上搜索類似于 diff patch language:java 這樣的關鍵詞,就能找到對應平臺下的 SDK 了,有人已經 fork 出來了,因為只是字符串的比較處理,所以可以放心使用。
該增量更新的原理是先通過比較首部和尾部的相同部分,目的是提升一定的效率,再比較中間差異的部分,差異的部分通過一些字符去表示該改動是 DEL 還是 ADD 還是 EQUAL ,這樣最終形成的補丁包比改動部分要大一點,但是相比于全量更新已經減少很多了。

并且生成補丁包基本是毫秒級的,也不必擔心接口請求的耗時問題。

服務端把前后配置的字符串進行比較即可得到一組補丁數(shù)據(jù):

$dmp = new DiffMatchPatch();
$patches = $dmp->patch_make($oldConfigString, $latestConfigString);
$patchStrings = [];
foreach ($patches as $patchObject) {
    array_push($patchStrings, $patchObject->__toString());
}

生成的補丁以官方為例,補丁內包含兩個字符串之間變動部分的 location 和 length,并最終下發(fā)給客戶端:

@@ -16,21 +16,29 @@
 see 
-yonder
+the
  cloud 
+over there 
 that
@@ -47,18 +47,19 @@
  almost 
-in
+the
  shape o
@@ -86,24 +86,18 @@
  By 
-the mass, and 't
+golly, it 
 is l
@@ -129,21 +129,23 @@
 et: 
-Me
+I 
 think
-s
  it 
-i
+look
 s li
@@ -177,12 +177,12 @@
  is 
-back
+shap
 ed l
@@ -234,11 +234,19 @@
 us: 
-Ver
+It's totall
 y li

以 iOS 為例,客戶端獲取補丁包后,根據(jù)補丁包內變動符號以及變動內容對本地配置文件內容進行字符串拼接或刪除操作,形成最終的配置:

DiffMatchPatch *dmp = [[DiffMatchPatch alloc] init];
NSError *error = nil;
NSArray<NSString *> *patchStrings = configDic[@"patches"];
NSMutableArray<Patch *> *patches = [NSMutableArray array];
for (NSString *patchString in patchStrings) {
    NSArray<Patch *> *patch = [dmp patch_fromText:patchString error:&error];
    if (!error) {
        [patches addObjectsFromArray:patch];
    }
}
NSString *newCacheConfig = [[dmp patch_apply:patches toString:cacheConfig] objectAtIndex:0];

為了確??蛻舳俗罱K生成的配置與服務端保持一致,客戶端在打好補丁之后,用該配置生成 MD5 值,與我們在服務端下發(fā)補丁包時攜帶的最新配置的 MD5 值進行比較,在一致的情況下才去緩存配置,避免因為補丁造成 App 無法使用的問題。

數(shù)據(jù)庫管理配置

實現(xiàn)增量更新的前提是我們需要有不同版本的配置記錄,而用文件去管理是非常不可控的,取而代之的是我們可以通過數(shù)據(jù)庫來管理,同時利于后期的橫向擴展,可以針對不同平臺,不同渠道,不同版本等規(guī)則下發(fā)。



目前我們是根據(jù)版本和應用來關聯(lián)到配置,所以表結構設計的很簡單,把應用、版本和配置放在一張表里面,后面針對多渠道和多平臺等規(guī)則之后,表結構上會做一定調整。

由于需要 App 能及時獲取到最新配置,我們選擇在 App 激活的時機去獲取配置,通過數(shù)據(jù)統(tǒng)計中心我們可以看到 App 當日啟動次數(shù)的時段分析,再結合配置文件大小,我們可以預估所占帶寬的大小,運維是非常擔心你把他的帶寬跑滿,影響到其他業(yè)務,所以我們需要做兩個優(yōu)化,一個是壓縮配置,一個是本地緩存。

壓縮配置

為了不占用過多的帶寬,我們需要在寫入之前把配置壓縮,讀取之后解壓配置。

這里我們通過 gzip 來壓縮配置:

$data['config'] = base64_encode(gzcompress(json_encode($config)));

需要注意的是 gzip 可以設置壓縮等級,范圍是0 - 9,默認是6,但是提升壓縮等級會占用較多 CPU 時間和內存,我們使用默認等級壓縮之后,配置文件體積減少了75%,看來是配置內相同的部分比較多,所以壓縮效果還是比較明顯的。

這里有人會問,為什么 gzip 之后還要 base64 編碼一下,因為二進制數(shù)據(jù)不能直接寫到text字段里面,寫進去之后讀出來也是解壓不了的。進行 base64 編碼之后,我們的壓縮配置內容會比原來多1/3的長度。

本地緩存

對于相同的配置,我們可以不用頻繁地去請求數(shù)據(jù)庫,而將其緩存到本地,這樣后續(xù)的請求可以直接從緩存中讀取配置,當然請記得設置緩存的過期時間。

我們目前用的是 Redis 緩存,它對于復雜的數(shù)據(jù)結構和操作支持的相當不錯,而且操作簡單,對于前期只是key-value存儲的話,可以考慮使用 Redis 。

可操作界面

為了方便業(yè)務方修改配置,我們在內部平臺上提供了一個簡單的可操作界面,通過頂部的Tab欄切換查看不同應用下的配置記錄。


點擊 查看詳情 可以看到當前版本的配置內容,目前展示的效果并不友好,后面會進行優(yōu)化。

在需要修改配置的時候,我們可以通過 新增配置 給指定應用修改配置,新增時會自動在版本上 +1。

后續(xù)優(yōu)化

目前有贊 App 已經實現(xiàn)了動態(tài)化配置中心整一套流程,但是在一些細節(jié)方面還需要不斷的改進優(yōu)化,比如:

  • 更加豐富的配置下發(fā)規(guī)則
  • 可操作界面配置的有效性的校驗
  • 可操作界面的視覺優(yōu)化
  • 等等

也歡迎大家提出自己的意見和建議,我們一起探討學習!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容