當前位置:
首頁 > 科技 > 如何達到facebook發版速度:Dropbox灰度發布平台系統架構

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

像 Dropbox 這樣的 SaaS 公司需要持續升級迭代他們的系統,並且這會涉及整個架構棧的所有層。當需要調整某些基礎架構,發布一個新功能,或是設置 A/B 測試時,最重要的是我們如何快速變更並體現在產品中。

對我們的代碼進行更改,然後「簡單地」推送出去不是一個好選擇:因為推送變更代碼到 Web 伺服器這個流程可能需要數小時,而發布新的移動版或桌面版客戶端則需更長時間。同時在任何情況下,完整的代碼部署是非常危險的,因為它可能會引入新的代碼缺陷:


我們想要把一些可配置的 「開關」 添加到我們的產品中,並且根據我們的需要來動態打開或關閉。這能帶給我們很好的靈活性,以及安全的實時的調整能力。

為了滿足這種需要,我們構建了一個名為 Stormcrow的平台,它允許我們編輯和部署 「feature gates」(可以稱作功能門或開關)。它是一個可配置的代碼路徑,通過請求 Stormcrow 來確定如何執行。典型的代碼使用看起來像這樣:

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

  • 可在更改後10分鐘內於生產環境生效。

  • 可用於所有 Dropbox 系統,從底層的基礎架構到桌面版或移動版產品。

  • 提供高級的用戶投放功能,比如可以根據我們數據倉庫中的用戶畫像來細分用戶。

構建一個像這樣通用的功能開關係統並不容易,因為它需要具有足夠的表達或描述能力來處理不同的用例,同時要足夠健壯來應對 Dropbox 巨大的流量。 接下來就讓我一一描述系統的工作原理和我們的一些經驗教訓。

示例

假設我們想執行一項 A/B 測試,看看德國用戶喜歡什麼顏色的按鈕。 進一步,假設我們已經知道英語為母語的用戶喜歡藍色按鈕。那麼在 Stormcrow UI 中,我們可以這樣配置功能:

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

這表明我們將對「德語區域的用戶」分別以 33% 和 33% 的比例顯示紅色按鈕(RED_BUTTON)和藍色按鈕(BLUE_BUTTON),剩餘 34% 的用戶則不顯示該按鈕。同時,使用英語會話(譯者注,指瀏覽器語言或客戶端語言)的用戶則 100% 顯示藍色按鈕(BLUE_BUTTON)。除此之外的所有剩餘用戶並不參與這項 A/B 測試。

需要注意的是,對於給定的任意特性/功能,可以使用不同的群體(population)類型:上面例子分別使用「用戶」和「會話」來定義群體,前者僅代表已登錄的用戶,後者代表對我們網站的任何訪問者。

在 Stormcow 中,有一系列的群體,這些群體按照自頂向下的方式進行匹配:首先,我們將嘗試匹配群體1,如果失敗了,我們在匹配群體2,依此類推。一旦我們匹配一個群體,我們就選擇一個變數(variant)應用到這個群體上。

通過用戶的 ID 與種子(圖中右上角的小灰色框)hash 而實現隨機。Stormcrow 用戶也可以通過種子來實現特殊的行為。例如,如果想要兩個不同的特性/功能分配給完全相同的用戶們,那可以指定相同的種子。

如何定義群體?

要了解群體是如何定義的,我們需要了解兩個概念:

  1. 選擇器(selector)是一個代碼對象,它被傳遞進 Stormcrow 以幫助它做出判斷。例如,usersession

  2. 數據欄位(datafield)是一段代碼,它接收一個或多個選擇器,並提取指定類型的值:布爾值、日期、數字、集合或字元串。 然後將它們通過簡單的規則引擎(使用這些值執行邏輯計算)組合成數據欄位。

這裡是一個真實的數據欄位例子,user_email

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

@dataField裝飾器(decorator)指定該數據欄位需要一個USER對象,並且將產生一個STRING。 它還包括一段幫助文本,由此我們可以自動生成文檔。函數的實際主體只是將用戶的電子郵件從對象中取出。

定義數據欄位後,您可以在定義群體中使用它。這裡有一個例子,它要麼匹配 Gmail 和 Yahoo 用戶並且顯式排出兩個特定的用戶,要麼匹配 tomm@dropbox.com這個用戶:

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

因為可以運行任意邏輯計算,所以數據欄位十分強大。在 Dropbox 內部定義了很多數據欄位,來支持我們所有的用例,不通的團隊如果需要他們可以不斷得添加新的數據欄位。

基於 Hive 的群體分類:連接我們的分析數據倉庫

即使具有創建任意數據欄位的能力,我們也面臨一個限制:我們只能依賴我們伺服器代碼可訪問的信息(來定義群體),也就是已經載入的模型或資料庫中。但是 Dropbox 還有另一個大數據源:我們基於 Hive 的分析數據倉庫。有時候 Dropboxer 想要通過寫一個 HiveQL 來查詢一組任意的用戶,這就可以利用各種歷史日誌和分析數據。

為了使 Stormcrow 可以利用通過 Hive 查詢獲得的群體,我們需要將其從分析倉庫移到可擴展的,同時可被生產代碼檢索的數據存儲中。為此我們構建了一個每天運行的數據管道,它將當天的所有基於 Hive 查詢的群體導出到生產環境中。

這種方法的主要缺點是數據滯後。與數據欄位不同(數據欄位總是生成最新的數據),基於 Hive 導出的資料庫僅僅每天更新一次。雖然這對於某些類型的開關是不可接受的,但它對於群體變化緩慢的場景來說很有用。

基於 Hive 的群體分類體現了表達力和數據新鮮度之間的權衡:對複雜分析數據執行特徵開關比對常用數據進行開關具有更多的滯後和數據工程工作。

派生群體:從簡單的群體定義中構建複雜群體

Stormcrow 最強大的功能之一是定義群體的能力。比如派生群體,下面示例是一個群體,它匹配 a)「Android設備」用戶和 b)功能 recents_web_comments值為 OFF。

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

這個功能幫我們避免了有些複雜匹配規則不斷得被複制和粘貼。相反,Dropbox 的功能開關旨在構建一組核心的基本群體,可以混合和匹配以滿足任意複雜的匹配需求。我們在實踐中發現,設計派生群體層次結構與重構代碼非常相似

實際上,可以將派生群體視為替換代碼中的 「if」 語句,以便在實驗之間進行選擇。而不是寫形如「如果用戶匹配在實驗 A 中就顯示東西 A,否則如果匹配在實驗 B 中就顯示東西 B」這樣的邏輯。

選擇器推斷:通過推斷附加信息使得 API 更易於使用

像其他複雜的軟體系統一樣,我們的代碼中使用了很多 Dropbox 內部模型。例如,user模型表示單個用戶帳戶,team模型表示 Dropbox 業務團隊。identity模型代表配對的帳戶:它將個人和商業用戶模型綁定到單個對象中。我們所有的模型都通過各種一對多和多對一的關係連接。

在 Dropbox 產品代碼中,我們通常可以訪問一個或多個這類模型。為了開發人員的方便,如果 Stormcrow 理解我們的模型關係就可以自動推斷額外的選擇器。例如,開發者可以訪問用戶對象 u並且希望查詢針對團隊而開關的功能。 他們可以這樣寫:

Stormcrow 自動推斷來獲取更多的信息,所以開發人員只需要寫:

在 Stormcrow 中,我們將 Dropbox 的模型關係表示成一個圖,我們稱之為選擇器推斷圖。在這個圖中,每個節點都是模型類型,從節點 A 到節點 B 的邊意味著我們可以從模型 A 推斷除模型 B。當 Stormcrow 調用時,我們做的第一件事是獲取指定的選擇器,接著在圖中計算其傳遞閉包(transitive closure)。

當然,推斷可能因為額外的計算或網路調用而造成性能損耗。為了使它更高效,推斷會產生 thunk,它們會被延遲求解(evaluate),這樣我們只有在實際需要選擇器來作出開關決策時才計算它們。 請參閱下面的「性能風險」

這是我們真實的選擇器推斷圖。每個節點表示 Stormcrow 中的選擇器類型。例如,viewer是一個非常方便的模型,因為我們可以使用它來推斷sessionteamuseridentity

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

我們發現選擇器推斷為開發人員帶來了巨大便利,同時易於理解。當然我們也有檢查工具來確保開發人員不會傳遞錯誤的選擇器。請參閱後面的「審核挑戰」

部署:Web 和內部基礎設施

如果你有大量生產伺服器,如何將功能門控的配置部署到它們上面呢?很顯然,我們需要將功能門控相關的數據保存在資料庫中,但是那麼就需要一次網路調用來檢索。dropbox.com 上一次典型的頁面載入中可能會涉及大量的功能門控,這會導致對資料庫的大量讀取。即使使用精心設計的緩存系統(例如使用本地緩存+ memcached)緩解這些問題,資料庫也會成為系統的單點故障。

相反,我們將一個名為 stormcrow_config.json的 JSON 文件部署到所有的生產伺服器上。這個部署僅僅使用我們的內部推送系統,並且在每次對 Stormcrow 配置進行更改時推送。

我們所有的伺服器都運行一個稱為「Stormcrow 載入器」的後台線程,它監視磁碟上的 stormcrow_config.json副本,當它改變時就重新載入它。這讓 Stormcrow 不用中斷伺服器就可以重新載入。

如果由於某種原因找不到配置文件,那麼 Stormcrow 也能夠回退到直接訪問資料庫,但是對於任何大流量的系統來說,這是非常危險和不推薦的做法。

部署:桌面端和移動端

對桌面版和移動版的功能開關稍有不同。對於這些客戶端,它們通常是批量請求開關相關的信息。比如從後端獲得的 Stormcrow:

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

這兩種平台上的客戶端還會傳遞一個或多個包含平台特定信息的特殊選擇器。移動客戶端傳遞一個選擇器,提供關於正在使用的 App 和設備本身的信息。桌面客戶端則傳遞一個帶有桌面主機信息的選擇器。與其他選擇器一樣,Stormcrow 有可根據這些平台特殊的選擇器來定義規則的數據欄位。

監控

Stormcrow 中所有被開關的功能的每次分配和曝光,都會記錄到我們的實時監控系統 Vortex 中。 Stormcrow UI 中嵌入了圖表,用戶可以利用其來跟蹤分配和曝光的速率。例如,下圖顯示了三種不同的變數(黃色,藍色和綠色),以及每個變數隨時間曝光給用戶的數量。 每次修改功能(或功能所依賴的群體)時,圖表中會用垂直線注釋。這使我們很容易地看到變更的影響。在該圖中,我們可以看到綠色和藍色變數在第一次修改之後收斂(垂直線),同時黃色變數上升。

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

用戶還可以單擊底部的鏈接,使用我們的 Vortex 或其他數據工具更詳細地挖掘數據。

性能風險

由於 Stormcrow 的模塊化數據欄位設計,Dropbox 的開發人員可能直接或間接得編寫嚴重影響性能的數據欄位。比如:有人創建一個新的數據欄位,對於他們的小型業務來說是非常安全的,但這個數據欄位也可被其他人使用,這就可能造成小型業務系統無法承載大量的請求流量。

這告訴我們一個重要的教訓:在功能開關中要避免資料庫調用或其他 I/O!

相反,調用方應該傳遞進來儘可能多的信息。這樣避免 Stormcrow 因為推斷而產生的隱式 I/O ,同時調用方的顯式 I/O 也使得調用方更好評估性能的損耗。

理想情況下,Stormcrow 應是完全「純粹的」(以函數式編程而言),並不會執行任何 I/O。目前我們還沒有能夠做到這一點,因為一些實際的原因:有時為調用方提供一個便捷的 API 意味著 Stormcrow 需要做更多並付出性能代價。

審計挑戰

功能開關有一方面比較棘手,因為它們沒有被納入版本控制中:它們可以獨立於使用方代碼進行更改。通過我們的「每日推送」系統(對於我們的後端)或通過桌面版或移動版客戶端的發布過程,Dropbox 中的代碼上線以可預測的方式進行。 但對於功能開關的變更,由於它們的性質,可以發生在白天或晚上的任何時間。因此,擁有完善的審計工具很重要,因為我們可以儘可能快地跟蹤功能開關相關的回歸。

Stormcrow 通過提供完整的審核歷史記錄,以及靜態分析代碼庫中的功能來解決此問題。

審核歷史記錄很簡單:我們對給定功能和群體的所有歷史修改顯示一個類似 「News Feed」 的視圖。

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

對代碼庫的靜態分析更有趣。我們運行一個名為「Stormcrow 靜態分析器」的特殊服務。 它會拉取我們的代碼並掃描它,搜索 Stormcrow 相關功能的使用。 對於給定的需要開關的功能,它會生成:

  1. 一個當前 master branch 中所有出現此功能的列表。

  2. 一個「歷史視圖」,展示了此功能相關的所有提交記錄。

例如,下面是靜態分析器對一個名為 can_see_weathervane功能的輸出:

如何達到facebook發版速度:Dropbox灰度發布平台系統架構

靜態分析器還會執行另一項重要的任務,那就是,我們的生產代碼中找到的與單元測試正在測試相匹配的變數。 它會發送「nag」郵件給該功能的所有者告知相關問題,比如已經棄用的功能應該從代碼庫中刪除。

質量保障和測試

針對功能的手工測試,Stormcrow 支持「重覆蓋」(override)。重覆蓋允許 Dropboxers 臨時將自己放入任一群體中。 我們還有一個「數據欄位重覆蓋」(datafields override)的概念,可以臨時更改單個數據欄位的值。 比如,臨時將語言區域設置為德語,來測試德語下的體驗。

對於單元測試,我們運行一個」模擬的「(mocked)Stormcrow,並對每個開關功能都返回一個「默認」變數用於測試。

總結

在 Dropbox 當前系統的體量和規模下構建出這樣一個統一的功能開關服務需要方方面面的仔細考慮,從基礎設施層面,到數據獲取和配置管理,再到 UI 設計和相關工具鏈。我們希望這篇文章對於正在打造自己的功能開關係統的同行有所幫助。


為什麼新的平台稱為 Stormcrow?因為這個系統取代了我們以前的功能開關係統 Gandalf(譯者注,甘道夫會說「你不能通過!」) ,同時指環王的粉絲們會將「風暴」(Stormcrow)視為甘道夫的名字之一。

英文原文

https://blogs.dropbox.com/tech/2017/03/introducing-stormcrow/

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 高可用架構 的精彩文章:

為極致的視頻體驗而設計:facebook新一代存儲平台Bryce Canyon架構
架構師經常參考的Netflix架構,它的全貌是怎樣的?
獲得PCC性能大賽背後的RocksDB引擎:5分鐘全面了解其原理
Redis架構之防雪崩設計:網站不宕機背後的兵法
容器與持久化存儲:容器的開源分布式存儲方案選型

TAG:高可用架構 |

您可能感興趣

Photoshop詳解灰度蒙版在後期調色中的應用
Nine Muses 灰度與性感黑一體
程序員誤操作?Flyme6.2今天全機型推送!淡定,只是個灰度測試
手機QQ安卓 v7.2.5灰度測試版更新:語音可實時轉為彈幕
GBWC2017少年組作品,浮空灰度
WB的灰度值計算,你都會了嗎?
小程序如何灰度發布新版本?| 小程序問答 #37
搞趣網:征途手機版關於7月24日19:00灰度區跨服賽異常的問題
灰度直方圖與K最近鄰的影像分割演算法
小程序如何灰度發布新版本?
灰度幾何空間,92㎡簡約兩居室
灰度世界和完美反射
「校園性侵案」啟示:適度給予孩子人性灰度的教育
《王者榮耀》灰度上線戰隊招募功能,智能匹配戰隊
依賴治理、灰度發布、故障演練,阿里電商故障演練系統的設計與實戰經驗
性感抽象的灰度美人兒插畫
特朗普政府「灰度監管」,為無人駕駛開綠燈
57歲唐先生近照憔悴不堪:守著哥哥的骨灰度過下半生,終身不娶!
灰度空間卻看到色彩斑斕,刷爆設計師盆友圈的神作!