作者:京東零售 胡本奎
一 背景
隨著移動網際網路的快速發展,為滿足各類使用者及人群的體驗需求,移動端的開發者們開發了豐富多彩的體驗與功能。同時對於快速控制各類功能的切換、灰度,降級等能力的要求也越來越高,例如透過配置快速開啟某個灰度功能,透過配置資訊的實時觸達關閉某個引起App崩潰的功能等等。因此需要一套具有實時觸達配置資訊到移動端的能力,低沉本的配置平臺來解決。 我們研發了Switchquery配置平臺,它是一套具有秒級變更能力,助力業務快速變更,讓配置資訊在App執行中秒級生效,同時提升配置資訊觸達率,統一管理的配置平臺。
二 技術原理
1 觸達技術選型
在Switchquery配置平臺核心能力中,實時觸達的能力尤為重要,目前業界主流的觸達技術方案主要有以下幾種方式:
-
推送push 訊息: push訊息當前已經成為實時推送營銷資訊、重要通知的最主要手段之一,push訊息擁有較強的實時性,而實際的移動端的應用場景中,push訊息多用於營銷方案或重要資訊的通知,很少使用此通道來作為研發配置資訊的觸達通道,其會產生UI互動的變化。另外push訊息依賴於使用者開啟通知許可權開關,而業內普遍開啟通知開關許可權的比例低於50%,因此大部分使用者無法觸達。
-
tcp或websocket長連線: 透過建立一條客戶端到服務端之間的長連線通道,此方案可以在發生配置資訊變更後實時的將資訊傳遞至客戶端,但是需要耗費較大的伺服器資源,來維護一條長連線通道。
3) 輪詢: 客戶端以一定的時間間隔向服務端發出請求,透過頻繁請求的方式來保持客戶端和伺服器端的資訊同步,這種同步方案的最大問題是當客戶端以固定頻率向伺服器發起請求的時候,伺服器端的資料可能並沒有更新,這樣會帶來很多無效的網路傳輸。
2 實現原理
2.1 實時觸達方案
由於推送push訊息方案存在觸達比例低的問題,長連結存在耗費伺服器資源的缺點,同時輪詢的方案也存在很多無效的網路傳輸等弊端,因此以上三種方案都不是Switchquery 配置平臺的觸達方案的最佳技術選型。透過調研,我們採取了一種配置資訊從服務端實時觸達到客戶端的新方案,方案的具體描述為: 先搭建一個資訊配置管理CMS平臺,同時構建一個客戶端獲取配置資訊的客戶端元件,由使用者在CMS配置資訊,然後由CMS後臺將配置資訊的版本號資訊同步至統一閘道器,所有客戶端請求到達統一閘道器,並在返回的介面資料的header內都會攜帶最新的版本號至客戶端,客戶端對比發現新的版本號比快取的版本大則請求配置資訊拉取Switchquery配置介面,這樣只要App開啟就會存在介面攜帶變化標誌返回,這樣就會觸發客戶端主動發起請求更新配置資訊,提高了實時性,不受push開關許可權控制和影響,不需要額外打造長連線通道,具有低成本,實時性高等優點。以下是Switchquery配置平臺的時序圖:
-
使用者在Switchquery CMS 後臺配置相關資訊,目前平臺上支援配置布林型別、整型、字串等型別的配置資訊,可以配置App版本生效區間,按裝置號灰度比例,iOS或者安卓平臺的設定,生效白名單等相關資訊。
-
Switchquery CMS後臺配置資訊並提交和儲存完成後,由CMS配置後臺將新的版本號寫入到統一閘道器後臺(所有客戶端到服務端的http請求都會經過統一閘道器,所有服務端返回到客戶的http請求響應都會經過統一閘道器),統一閘道器記錄下資料版本號,客戶端的所有介面請求的響應header增加一個欄位x-switch-config,此欄位會攜帶回配置資訊的版本號至客戶端。
-
Switchquery CMS配置後臺完成資訊配置後,後臺會基於當前時間戳,生成一個新的配置資訊版本號,同時將這些配置的靜態資料寫入到服務端記憶體快取內,同步重新整理配置開關介面。
-
Switchquery CMS配置後臺將配置資訊資料寫入和儲存一份靜態資料json到CDN,防止介面降級或者失敗以後可以降級從CDN拉取配置資訊資料。
5) 閘道器會將版本號下發至客戶端網路元件,網路元件在接受到網路請求返回後,首先會解析網路請求的響應header,如果解析到關鍵字將其對應的value一起解析封裝後發起一個全域性通知。
6) 配置客戶端元件在監聽到通知後,與本地已經快取的配置資訊資料版本號進行比對,相同則不處理,大於本地版本號則發起配置資訊拉取請求,這樣即可獲取到最新的開關配置資訊並快取在磁碟。
- 客戶端在介面降級或者失敗後會從CDN拉取配置資料資訊。
此種觸達方式只要客戶端開啟即會觸發請求至統一閘道器,隨即就可以根據變化情況來決定是否更新最新的配置介面資料,無需push通知,無需建立長連線通道,成本低,實時性高。
2.2 流程架構設計
1) 使用者在CMS配置平臺進行資訊配置後,配置後臺介面對配置資訊進行對比,包括配置資訊中的開關的狀態,開關值等關鍵資訊,如果沒發生變化,則結束;發生變化則判斷此次變更距離上一次變更是否到了n秒,距離n秒內則不會觸發配置資訊變更同步,距離n秒外則觸發配置資訊同步,觸發閘道器和後臺介面資料發生變化。
2) CMS觸發變化將新的版本號傳遞至統一閘道器,統一閘道器會做資料版本號的儲存,同時會將統一閘道器的所有機器記憶體裡都儲存一份最新的版本號。 也會將資料變更資訊同步到配置後臺介面,同步寫入一份json靜態資料到CDN,這個是為了防止配置資訊介面服務端掛了後可以走CDN兜底。
3) 客戶端任意介面請求都會經過統一閘道器,所有請求的返回也會透過統一閘道器返回,在返回的響應header內新增一個x-switch-config欄位,其value是一段字串,由下劃線隔開,格式如: switch_version_randomtime_reserved,第一個欄位switch=0/1,其中0表示此能力統一降級關閉,1表示此能力開啟;第二個欄位version就是配置資訊的資料版本號,目前是按時間戳的形式標識版本號;第三個欄位randomtime表示客戶端獲取到版本號變化差異後並非立刻請求,會延遲[0,randomtime]之間的一個隨機時間後才發起請求,這個是為了降低瞬間尖峰流量的產生;第四個欄位是留作未來使用。
4) 客戶端網路框架在客戶端會不間斷隨機廣播全域性通知, 開關客戶端元件收到通知後,獲取到統一閘道器的返回資料,解析網路介面返回的header部分,獲取x-switch-config欄位,解析欄位中的value,如果是降級,則結束,如果版本號沒有發生變化,則結束,如果非限流同時 switch=1,並且本地的快取的開關version小於解析後的version,則根據randomtime隨機數發起客戶端請求;如果服務端返回了特定的限流碼則客戶端直接從CDN拉取配置資訊資料並更新本地快取資料,如果服務端正常返回則獲取開關資料並更新本地快取。
3 技術最佳化
在Switchquery 配置平臺的設計開發中,從實時性,效能,成本,穩健等多維度進行了最佳化,具體的最佳化措施如下:
-
考慮到實時性與機器成本的平衡,我們在CMS配置端做了聚合n秒後才將配置變更同步至統一閘道器,主要為了防止多個使用者在很近的時間內做了多個修改,會導致統一閘道器側頻繁的接收到不同的版本號,進而引起客戶端頻繁的發起請求,導致配置資訊服務端的流量陡增,目前的經驗值是n=5秒。
-
考慮效能與機器成本的平衡,客戶端會根據randomtime來隨機發起請求,是為了打散請求發起時機,實際經驗我們發現5s會增日常2倍左右的QPS,10s會增加日常1.5倍左右,實際各個場景可以根據自身的伺服器機器數量與成本來動態決定選擇設定多長時間。
-
為了保障在大促或者特殊促銷場景下的穩定性和健壯性,我們在配置資訊產生後,首先寫入資料到伺服器的記憶體裡,這樣每次客戶端的請求就直接讀取記憶體效能很高,另外也會寫入一份json資料到CDN,當服務端出問題後或在大促主動降級後可以透過CDN來兜底。
-
實時觸達方案在App原生端來實現此功能,同時對於App內嵌的小程式、H5、RN都提供了橋接元件,尤其webview也可以讀取此配置資訊來實現配置資訊的實時獲取。
三 接入流程
1 客戶端:
1.1 Android 平臺接入
//chName:開關名稱,拉取失敗或未取到配置返回defValue預設值
SwitchQueryFetcher.getSwitchBooleanValue(String switchName, boolean defValue)
//獲取int開關值,拉取失敗或未拉取到配置返回defValue預設值
SwitchQueryFetcher.getSwitchIntValue(String switchName, int defValue)
//獲取String開關值,拉取失敗或未拉取到配置返回defValue預設值
SwitchQueryFetcher.getSwitchStringValue(String switchName, String defValue)
1.2 Apple 平臺接入
//自定義bool開關,獲取不到返回NO
BOOL JDSwitchBoolValue(NSString *key);
//自定義整型開關,獲取不到返回0
NSInteger JDSwitchIntValue(NSString *key);
//自定義字元開關,獲取不到返回nil
NSString* JDSwitchStringValue(NSString *key);
//取intvalue
NSNumber *n1 = [JDRouter openURL:@"router://JDBSHServerConfigModule/intValue?key=test"
arg:nil
error:nil
completion:nil];
//取boolvalue
NSNumber *n2 = [JDRouter openURL:@"router://JDBSHServerConfigModule/boolValue?key=test"
arg:nil
error:nil
completion:nil];
//取stringValue
NSString *n3 = [JDRouter openURL:@"router://JDBSHServerConfigModule/stringValue?key=test"
arg:nil
error:nil
completion:nil];
2 CMS 建立
為了讓研發測試階段和線上的資料安全隔離,預發和線上的資料是隔離的,在預發環境測試驗證OK後,配置資料再同步到線上。
2.1 業務模組建立
進入CMS介面,選擇左側的模組管理選單,進入模組管理介面,新增業務模組,彈出彈窗如下圖:
-
名稱:對應業務模組名稱;
-
關鍵字:設定對應業務模組的關鍵字;
-
管理員:模組分配的管理員,一般預設為模組的建立者;
-
成員:該模組分配的管理成員,成員有新增,刪除,修改該模組下的配置許可權,但沒有修改,刪除當前模組的許可權;
-
說明:對當前模組的描述;
2.2 配置建立
建立好業務模組後,在該業務模組下新建或者編輯配置,編輯介面如下圖:
-
開關編號:為當前開關配置分配的唯一標識編號;
-
平臺版本:目前支援android,apple,ipad三種平臺,可支援開關生效App的版本的區間範圍設定,按照左閉右開的原則,預設不設定,全版本生效;
-
系統版本:設定系統版本的區間,預設不設定,全系統版本生效;
-
開關型別:目前支援布林開關,整形開關,字串開關以及敏感資料開關(10.4.4版本以上)4種型別開關配置資訊;
-
開關名稱:設定的開關配置名稱;
-
開關開啟比例:命中規則為:android 平臺根據uuid,apple平臺根據openudid,透過hash演算法算出來的值和100取餘加1,如果最終值小於或者等於設定的值即為命中,反之不命中;
-
白名單:該開關配置對應的白名單,可以透過手動的方式將pin以逗號分隔複製到編輯框,未來可接入嚐鮮系統透過掃碼的方式新增白名單;
-
開關配置值:布林開關預設不展示,整形或者字串型別的配置型別需設定開關值;
-
開關描述:透過描述知道開關配置的用途;
四 收益
1 護航X專案
在2022年春晚X專案中每次口播的時候面臨著流量大,啟動介面多的問題,這樣會造成閘道器壓力巨大,業務癱瘓的問題,會導致整個X專案的失敗,不容有失。因此透過銷峰降頻,減少介面請求等方式進行App啟動降級。透過Switchquery配置平臺,在客戶端下發降級資訊配置,以及修正時間戳等資料,成功的保障X專案中App啟動介面的成功降級。
1.1 啟動介面降級
降級成功率為100%,線上0事故,啟動介面數從110個降級到8個。
1.2 流量降級
單個介面的峰值QPS比日常QPS降幅達88.7%左右,閘道器整體峰值QPS比日常QPS降幅達30%左右,均在2分鐘之內完成降級。
2 護航雙十一
2022年雙十一期間Switchquery 保障了大促活動的穩定運營,具體情況如下:
2022 年雙十一期間,Switchquery 配置平臺服務業務模組數為38個,線上開關總數為392個,整體開關配置的觸達率為98.3%左右,服務開關配置秒級變更次數為61次,Switchquery配置介面峰值QPS環比去年下降58.8%有效的保障了大促活動的順利進行。
五 結語
未來Switchquery配置平臺會為更多的業務模組提供配置服務,同時我們會賦能更多的App,支援一整套從配置客戶端元件控制到後臺CMS支援多App切換以及閘道器實時秒級觸達的一整套秒級觸達的高效能移動配置技術方案。同時支援更完備的功能體驗例如操作日誌檢視能力,支援機型過濾能力,黑白名單透過接入嚐鮮平臺透過掃碼的方式動態新增等功能,打造一套具有秒級配置變更能力,助力業務快速變更的配置平臺。