從0到1:美團端側CDN容災解決方案

語言: CN / TW / HK

CDN已經成為網際網路重要的基建之一,越來越多的網路服務離不開CDN,它的穩定性也直接影響到業務的可用性。CDN的容災一直由美團的SRE團隊在負責,在端側鮮有方案和實踐。本文結合美團外賣業務中的具體實踐,介紹了一種在端側感知CDN可用性狀況並進行自動容災切換的方案,通過該方案可有效降低業務對CDN異常的敏感,提高業務的可用性,同時降低CDN運維壓力。希望本方案能夠對被CDN問題所困擾的同學有所幫助或者啟發。

1. 前言

作為業務研發,你是否遇到過因為 CDN 問題導致的業務圖片載入失敗,頁面開啟緩慢,頁面佈局錯亂或者頁面白屏?你是否又遇到過某些區域 CDN 域名異常導致業務停擺,客訴不斷,此時的你一臉茫然,不知所措?作為 CDN 運維,你是否常常被業務方反饋的各種 CDN 問題搞得焦頭爛額,一邊頂著各種催促和壓力尋求解決方案,一邊抱怨著服務商的不靠譜?今天,我們主要介紹一下美團外賣技術團隊端側 CDN 的容災方案,經過實踐,我們發現該產品能有效減少運維及業務開發同學的焦慮,希望我們的這些經驗也能夠幫助到更多的技術團隊。

2. 背景

CDN 因能夠有效解決因分佈、頻寬、伺服器效能帶來的網路訪問延遲等問題,已經成為網際網路不可或缺的一部分,也是前端業務嚴重依賴的服務之一。在實際業務生產中,我們通常會將大量的靜態資源如 JS 指令碼、CSS 資源、圖片、影片、音訊等託管至 CDN 服務,以享受其邊緣節點快取對靜態資源的加速。但是在享用 CDN 服務帶來更好體驗的同時,也經常會被 CDN 故障所影響。比如因 CDN 邊緣節點異常,CDN 域名封禁等導致頁面白屏、排版錯亂、圖片載入失敗。

每一次的 CDN 故障,業務方往往束手無策,只能寄希望於 CDN 團隊。而 CDN 的監控與問題排查,對 SRE 也是巨大的難題和挑戰。一方面,由於 CDN 節點的分佈廣泛,邊緣節點的監控就異常困難。另一方面,各業務匯聚得到的 CDN 監控大盤,極大程度上隱匿了細節。小流量業務、定點區域的 CDN 異常往往會被淹沒。SRE 團隊也做了很多努力,設計了多種方案來降低 CDN 異常對業務的影響,也取得了一定的效果,但始終有幾個問題無法很好解決:

  • 時效性:當 CDN 出現問題時,SRE 會手動進行 CDN 切換,因為需要人為操作,響應時長就很難保證。另外,切換後故障恢復時間也無法準確保障。
  • 有效性:切換至備份 CDN 後,備份 CDN 的可用性無法驗證,另外因為 Local DNS 快取,無法解決域名劫持和跨網訪問等問題。
  • 精準性:CDN 的切換都是大範圍的變更,無法針對某一區域或者某一專案單獨進行。
  • 風險性:切換至備份 CDN 之後可能會導致回源,流量劇增拖垮源站,從而引發更大的風險。

當前,美團外賣業務每天服務上億人次,即使再小的問題在巨大的流量面前,也會被放大成大問題。外賣的動態化架構,70%的業務資源都依賴於 CDN,所以 CDN 的可用性嚴重影響著外賣業務。如何更有效的進行 CDN 容災,降低 CDN 異常對業務的影響,是我們不斷思考的問題。

既然以上問題 SRE 側無法完美地解決,端側是不是可以進行一些嘗試呢?比如將 CDN 容災前置到終端側。不死鳥(Phoenix) 就是在這樣的設想下,通過前端能力建設,不斷實踐和完善的一套端側 CDN 容災方案。該方案不僅能夠有效降低 CDN 異常對業務的影響,還能提高 CDN 資源載入成功率,現已服務整個美團多個業務和 App。

3. 目標與場景

3.1 核心目標

為降低 CDN 異常對業務的影響,提高業務可用性,同時降低 SRE 同學在 CDN 運維方面的壓力,在方案設計之初,我們確定了以下目標:

  • 端側 CDN 域名自動切換:在 CDN 異常時,端側第一時間感知並自動切換 CDN 域名進行載入重試,減少對人為操作的依賴。
  • CDN 域名隔離:CDN 域名與服務廠商在區域維度實現服務隔離且服務等效,保證 CDN 切換重試的有效性。
  • 更精準有效的 CDN 監控:建設更細粒度的 CDN 監控,能夠按照專案維度實時監控 CDN 可用性,解決 SRE CDN 監控粒度不足,告警滯後等問題。並根據容災監控對 CDN 容災策略實施動態調整,減少 SRE 切換 CDN 的頻率。
  • 域名持續熱備:保證每個 CDN 域名的持續預熱,避免流量切換時導致回源。

3.2 適用場景

適用所有依賴 CDN ,希望降低 CDN 異常對業務影響的端側場景,包括 Web、SSR Web、Native 等技術場景。

4. Phoenix 方案

一直以來,CDN 的穩定性是由 SRE 來保障,容災措施也一直在 SRE 側進行,但僅僅依靠鏈路層面上的保障,很難處理區域性問題和實現快速止損。使用者終端作為業務的最終投放載體,對資源載入有著天然的獨立性和敏感性。如果將 CDN 容災前置到終端側,無論從時效性,精準性,都是 SRE 側無法比擬的。在端側進行容災,就需要感知 CDN 的可用性,然後實現端側自動切換的能力。我們調研整個前端領域,並未發現業內在端側 CDN 容災方面有所實踐和輸出,所以整個方案的實現是從無到有的一個過程。

4.1 總體設計

圖 1

Phoenix 端側 CDN 容災方案主要由五部分組成:

  • 端側容災 SDK:負責端側資源載入感知,CDN 切換重試,監控上報。
  • 動態計算服務:根據端側 SDK 上報資料,對多組等效域名按照城市、專案、時段等維度定時輪詢計算域名可用性,動態調整流量至最優 CDN。同時也是對 CDN 可用性的日常巡檢。
  • 容災監控平臺:從專案維度和大盤維度提供 CDN 可用性監控和告警,為問題排查提供詳細資訊。
  • CDN 服務:提供完善的 CDN 鏈路服務,在架構上實現域名隔離,併為業務方提供等效域名服務,保證端側容災的有效性。等效域名,就是能夠通過相同路徑訪問到同一資源的域名,比如:cdn1.meituan.net/src/js/test.js 和 cdn2.meituan.net/src/js/test.js 能夠返回相同內容,則 cdn1.meituan.net 和 cdn2.meituan.net 互為等效域名。
  • 容災配置平臺:對專案容災域名進行配置管理,監控上報策略管理,並提供 CDN 流量人工干預等措施。

4.2 容災流程設計

為保證各個端側容災效果和監控指標的一致性,我們設計了統一的容災流程,整體流程如下:

圖 2

4.3 實現原理

4.3.1 端側容災 SDK

Web 端實現

Web 端的 CDN 資源主要是 JS、CSS 和圖片,所以我們的容災目標也聚焦於這些。在 Web 側的容災,我們主要實現了對靜態資源,非同步資源和圖片資源的容災。

實現思路

要實現資源的容災,最主要的問題是感知資源載入結果。通常我們是在資源標籤上面新增錯誤回撥來捕獲,圖片容災可以這樣實現,但這並不適合 JS,因為它有嚴格的執行順序。為了解決這一問題,我們將傳統的標籤載入資源的方式,換成XHR來實現。通過Webpack在工程構建階段把同步資源進行抽離,然後通過PhoenixLoader來載入資源。這樣就能通過網路請求返回的狀態碼,來感知資源載入結果。

在方案的實現上,我們將 SDK 設計成了 Webpack Plugin,主要基於以下四點考慮:

  1. 通用性:美團前端技術棧相對較多,要保證容災 SDK 能夠覆蓋大部分的技術框架。
  2. 易用性:過高的接入成本會增加開發人員的工作量,不能做到對業務的有效覆蓋,方案價值也就無從談起。
  3. 穩定性:方案要保持穩定可靠,不受 CDN 可用性干擾。
  4. 侵入性:不能侵入到正常業務,要做到即插即用,保證業務的穩定性。

通過調研發現,前端有 70%的工程構建都離不開 Webpack,而 Webpack Plugin 獨立配置,即插即用的特性,是實現方案的最好選擇。整體方案設計如下:

圖 3

當然,很多團隊在做效能優化時,會採取程式碼分割,按需引入的方式。這部分資源在同步資源生成的過程中無法感知,但這部分資源的載入結果,也關係到業務的可用性。在對非同步資源的容災方面,我們主要是通過對 Webpack 的非同步資源處理方式進行重寫,使用Phoenix Loader接管資源載入,從而實現非同步資源的容災。整體分析過程如下圖所示:

圖 4

CSS 資源的處理與 JS 有所差別,但原理相似,只需要重寫 mini-css-extract-plugin 的非同步載入實現即可。

Web 端方案資源載入示意:

圖 5

容災效果

圖6 容災大盤

圖7 容災案例

Native 端容災

客戶端的 CDN 資源主要是圖片,音影片以及各種動態化方案的 bundle 資源。Native 端的容災建設也主要圍繞上述資源展開。

實現思路

重新請求是 Native 端 CDN 容災方案的基本原理,根據互備 CDN 域名,由 Native 容災基建容災域名重新進行請求資源,整個過程發生在原始請求失敗後。Native 容災基建不會在原始請求過程中進行任何操作,避免對原始請求產生影響。原始請求失敗後,Native 容災基建代理處理失敗返回,業務方仍處於等待結果狀態,重請新求結束後向業務方返回最終結果。整個過程中從業務方角度來看仍只發出一次請求,收到一次結果,從而達到業務方不感知的目的。為將重新請求效率提升至最佳,必須儘可能的保證重新請求次數趨向於最小。

調研業務的關注點和技術層面使用的網路框架,結合 Phoenix 容災方案的基本流程,在方案設計方面,我們主要考慮以下幾點:

  • 便捷性:接入的便捷性是 SDK 設計時首先考慮的內容,即業務方可以用最簡單的方式接入,實現資源容災,同時也可以簡單無殘留拆除 SDK。
  • 相容性:Android 側的特殊性在於多樣的網路框架,集團內包括 Retrofit 框架,okHttp 框架,okHttp3 框架及已經很少使用的 URLConnection 框架。提供的 SDK 應當與各種網路框架相容,同時業務方在即使變更網路框架也能夠以最小的成本實現容災功能。而 iOS 側則考慮複用一個 NSURLProtocol 去實現對請求的攔截,降低程式碼的冗餘度,同時實現對初始化項進行統一適配。
  • 擴充套件性:需要在基礎功能之上提供可選的高階配置來滿足特殊需求,包括監控方面也要提供特殊的監控資料上報能力。

基於以上設計要點,我們將 Phoenix 劃分為以下結構圖,圖中將整體的容災 SDK 拆分為兩部分 Phoenix-Adaptor 部分與 Phoenix-Base 部分。

圖 8

Phoenix-Base

Phoenix-Base 是整個 Phoenix 容災的核心部分,其包括容災資料快取,域名更換元件,容災請求執行器(區別於原始請求執行器),監控器四個對外不可見的內部功能模組,幷包含外部接入模組,提供外部接入功能。

  1. 容災資料快取:定期獲取及更新容災資料,其產生的資料只會被域名更換元件使用。
  2. 域名更換元件:連線容災資料快取,容災請求執行器,監控器的中心節點,負責匹配原始失敗 Host,過濾錯誤碼,並向容災請求執行器提供容災域名,向監控器提供整個容災過程的詳細資料副本。
  3. 容災執行器:容災請求的真正請求者,目前採用內部 OkHttp3Client,業務方也可以自主切換至自身的執行器。
  4. 監控器:分發容災過程的詳細資料,內建資料大盤的上報,若有外部自定義的監控器,也會向自定義監控器分發資料。

Phoenix-Adaptor

Phoenix-Adaptor 是 Phoenix 容災的擴充套件適配部分,用於相容各種網路框架。

  • 繫結器:生成適合各個網路框架的攔截器並繫結至原始請求執行者。
  • 解析器:將網路框架的 Request 轉換為 Phoenix 內部執行器的 Request,並將 Phoenix 內部執行器的 Response 解析為外部網路框架 Response,以此達到適配目的。

容災效果

業務成功率

以外賣圖片業務為例,Android 業務成功率對比(同版本 7512,2021.01.17 未開啟 Phoenix 容災,2021.01.19 晚開啟 Phoenix 容災)。

圖 9

iOS 業務成功率對比(同版本 7511,2021.01.17 未開啟 Phoenix 容災,2021.01.19 晚開啟 Phoenix 容災)。

圖 10

風險應對

以外賣與美團圖片做為對比 ,在 CDN 服務出現異常時,接入 Phoenix 的外賣 App 和未接入的美團 App 在圖片成功率方面的對比。

圖 11

4.3.2 動態計算服務

端側的域名重試,會在某一域名載入資源失敗後,根據容災列表依次進行重試,直至成功或者失敗。如下圖所示:

圖 12

如果域名 A 大範圍異常,端側依然會首先進行域名 A 的重試載入,這樣就導致不必要的重試成本。如何讓資源的首次載入更加穩定有效,如何為不同業務和地區動態提供最優的 CDN 域名列表,這就是動態計算服務的要解決的問題。

計算原理

動態計算服務通過域名池和專案的 Appkey 進行關聯,按照不同省份、不同地級市、不同專案、不同資源等維度進行策略管理。通過獲取 5 分鐘內對應專案上報的資源載入結果進行定時輪詢計算,對域名池中的域名按照地區(城市&&省份)的可用性監控。計算服務會根據域名可用性動態調整域名順序並對結果進行輸出。下圖是一次完整的計算過程:

圖 13

假設有 A、B、C 三個域名,成功率分別是 99%、98%、97.8%,流量佔比分別是 90%、6%、4%。基於轉移基準,進行流量轉移,比如,A 和 B 成功率差值是 1,B 需要把自己 1/2 的流量轉移給 A,同時 A 和 C 的成功率差值大於 1,C 也需要把自己 1/2 的流量轉移給 A,同時 B 和 C 的差值是 0.2,所以 C 還需要把自己 1/4 的流量轉移給 B。最終,經過計算,A 的流量佔比是 95%,B 是 3.5%,C 是 1.5%。最後,經過排序和隨機計算後將最終結果輸出。

因為 A 的佔比最大,所以 A 優先被選擇;通過隨機,B 和 C 也會有一定的流量;基於轉移基準,可以實現流量的平穩切換。

異常喚起

當某個 CDN 無法正常訪問的時候,該 CDN 訪問流量會由計算過程切換至等效的 CDN B。如果 SRE 發現切換過慢可以進行手動干預分配流量。當少量的 A 域名成功率上升後,會重複計算過程將 A 的流量加大。直至恢復初始態。

圖 14

服務效果

動態計算服務使得資源的首次載入成功率由原來的99.7%提升至99.9%。下圖為接入動態計算後資源載入成功率與未接入載入成功率對比。

圖 15

4.3.3 容災監控

在監控層面,SRE 團隊往往只關注域名、大區域、運營商等複合維度的監控指標,監控流量巨大,對於小流量業務或者小範圍區域的 CDN 波動,可能就無法被監控分析識別,進而也就無法感知 CDN 邊緣節點異常。容災監控建設,主要是為了解決 SRE 團隊的 CDN 監控告警滯後和監控粒度問題。監控整體設計如下:

圖 16

流程設計

端側容災資料的上報,分別按照專案、App、資源、域名等維度建立監控指標,將 CDN 可用性變成專案可用性的一部分。通過計算平臺對資料進行分析聚合,形成 CDN 可用性大盤,按照域名、區域、專案、時間等維度進行輸出,與天網監控互通,建立分鐘級別的監控告警機制,大大提升了 CDN 異常感知的靈敏性。同時,SRE 側的天網監控,也會對動態計算服務結果產生干預。監控整體流程如下:

圖 17

監控效果

CDN 監控不僅從專案維度更加細粒度的監測 CDN 可用性,還為 CDN 異常排查提供了區域、運營商、網路狀況、返回碼等更豐富的資訊。在監控告警方面,實現了分鐘級異常告警,靈敏度也高於美團內部的監控系統。

圖 18

4.3.4 CDN 服務

端側域名切換的有效性,離不開 CDN 服務的支援。在 CDN 服務方面,在原有 SRE 側容災的基礎上,對 CDN 服務整體做了升級,實現域名隔離,解決了單域名對應多 CDN 和多域名對應單 CDN 重試無效的弊端。

圖 19

5. 總結與展望

經過一年的建設與發展,Phoenix CDN 容災方案日趨成熟,現已成為美團在 CDN 容災方面唯一的公共服務,在多次 CDN 異常中發揮了巨大的作用。在端側,當前該方案日均容災資源3000萬+,挽回使用者35萬+,覆蓋外賣,酒旅,餐飲,優選,買菜等業務部門,服務200+個工程,外賣 App美團 App大眾點評 App均已接入。

在 SRE 側,實現了專案維度的分鐘級精準告警,同時豐富了異常資訊,大大提高了 SRE 問題排查效率。自從方案大規模落地以來,CDN 異常時鮮有手動切換操作,極大減輕了 SRE 同學的運維壓力。

由於前端技術的多樣性和複雜性,我們的 SDK 無法覆蓋所有的技術方案,所以在接下來的建設中,我們會積極推廣我們的容災原理,公開動態計算服務,希望更多的框架和服務在我們的容災思想上,貼合自身業務實現端側的 CDN 容災。另外,針對方案本身,我們會不斷優化資源載入效能,完善資源驗籤,智慧切換等能力,也歡迎對 Phoenix CDN 容災方案有興趣的同學,跟我們一起探討交流。同時更歡迎加入我們,文末附招聘資訊,期待你的郵件。

6. 作者簡介

魏磊、陳彤、張群、粵俊等,均來自美團外賣平臺-大前端團隊,丁磊、心澎,來自美團餐飲 SaaS 團隊。

7. 招聘資訊

美團外賣平臺-大前端團隊是一個開放、創新、無邊界的團隊,鼓勵每一位同學追求自己的技術夢想。團隊長期招聘Android、iOS、FE 高階/資深工程師和技術專家。歡迎感興趣的同學投遞簡歷至:[email protected](郵件標題請註明:美團外賣大前端)。

閱讀美團技術團隊更多技術文章合集

前端 | 演算法 | 後端 | 資料 | 安全 | 運維 | iOS | Android | 測試

| 在公眾號選單欄對話方塊回覆【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】等關鍵詞,可檢視美團技術團隊歷年技術文章合集。

| 本文系美團技術團隊出品,著作權歸屬美團。歡迎出於分享和交流等非商業目的轉載或使用本文內容,敬請註明“內容轉載自美團技術團隊”。本文未經許可,不得進行商業性轉載或者使用。任何商用行為,請傳送郵件至[email protected]申請授權。