B站邊緣網路四層負載均衡器的探索與應用

架構師修行手冊發表於2023-12-12

來源:嗶哩嗶哩技術


01 背景介紹


B站的 CDN 下行邊緣節點過去是非叢集化架構。這種架構下有幾個弊端:

  1. 增加排程邏輯複雜性;

  2. 同機房流量/負載難以均衡;

  3. 暴露過多的公網IP,增加安全隱患 (盜鏈等);

  4. 灰度流量比例分配粒度大;

針對以上問題,我們調研了常見的四層負載均衡器, 傳統的 SLB,LVS,DPVS 這類四層負載均衡器,在功能上也能滿足我們現有的需求。但是以上幾個負載均衡器均需要獨佔機器,進而造成成本升高,資源浪費。

有沒有一種既不增加成本,又能解決邊緣節點四層負載需求的方案呢?由 Cloudflare 提出的基於 Express Data Path (XDP) 的高效能四層負載均衡器 Unimog[1]效能優異,並且可以和後端服務同機部署,在效能上也完全滿足我們邊緣場景的要求。所以我們參考 Cloudflare Unimog 的思想,在其基礎上自研了適用於B站的邊緣四層負載均衡器 Nickel (以下簡稱 Ni) 。

  • 與業務服務同機部署,更划算;

  • 只保留業務需要功能,更輕量;

  • 可針對業務特點最佳化,更靈活;

目前已部署在自建動態加速,及自建點直播 CDN 叢集化生產環境中。其支援與後端服務同機部署,底層使用 XDP、Traffic Control (TC) 進行包粒度轉發,支援 Direct Server Return (DSR) 模式,支援根據 CPU/QPS (或其他業務維度) 動態調整流量分配。

下面左圖為傳統 DSR 模式,右圖為自研負載均衡器 Ni 的 DSR 模式,不需獨佔資源,支援與服務同機部署,更符合邊緣場景。


B站邊緣網路四層負載均衡器的探索與應用

B站邊緣網路四層負載均衡器的探索與應用


02 架構設計


2.1 總體設計


四層負載均衡器 Ni 由兩部分組成,控制面和資料面。控制面主要負責服務發現、配置管理、資料上報,及LB規則的動態維護等。資料面主要由 LoadBalance (XDP) , Redirect (TC Traffic Control) 等模組組成,主要用來負責資料包的轉發。控制面和資料面根據預定義的介面傳輸資料。


B站邊緣網路四層負載均衡器的探索與應用


開始介紹之前先明確幾個下文中用的到名詞及其意義:

  • VIP (virtual IP) :用於統一接受使用者請求,代表當前叢集流量入口,下文中VIP指LB所在機器的IP(目前邊緣沒有支援真正虛擬IP的建設)。

  • DIP (direct IP) :業務服務所在機器的 IP。


2.2 控制面


控制面基於開源框架 kglb[2] 結合邊緣網路特點做的改造和開發,其核心為生成和維護供資料面使用的轉發表。為了保證轉發表的資料的正確性、實時性、高效性,控制面使用以下幾個功能和模組更新資訊:

  • 服務發現、管理

Ni 控制面需要維護同叢集邊緣節點的所有伺服器資訊 (VIP,DIP,Hostname,運營商,權重等),以及需要感知當前邊緣機房內機器或者服務的狀態變化,如標記為下線的機器不再接受新的連線請求,但是需要維護當前已經建立的連線直至其主動斷開;

  • 健康檢查

處於異常狀態的服務在確認其不可用後應該儘快從轉發表中刪除,避免影響範圍擴大。因此機房內需要有伺服器級別的健康狀態檢查。目前 Ni 提供多種協議型別的健康檢查方式,如 Http、Tcp 等。以下為 Http 健康檢查的相關配置欄位:

















{    "checker": {        "http": {            "scheme": "http",            "uri": "/",            "check_port": 9080,            "codes": [                200            ]        }    },    "fall_count": 2,    "interval_ms": 2000,    "rise_count": 2}


  • 支援基於機器使用率/QPS等做負載均衡

Ni定期收集機房內各伺服器的資源使用情況,以便於根據資源使用率做動態調整。使用收集的資訊計算機房內機器負載,讓負載偏低的服務分配更多的連線,偏高則反之,從而保證一個邊緣機房內所有伺服器的負載收斂。QPS類似。

  • 基於轉發表Beamer[3]的負載均衡

第一步首先需要一個穩定高效的 Hash 計算方法,輸入四元組 (源 IP、源 port、目的 IP、目的 port) 後得到對應的 Hash 索引值,第二步使用索引值轉換為 DIP。


B站邊緣網路四層負載均衡器的探索與應用


支援按照配置的 DIP 權重做負載均衡,也可以動態根據 DIP 所在機器的CPU進行實時的權重調整,也就是調整 Hash 值在整個轉發表中的比例。


B站邊緣網路四層負載均衡器的探索與應用


如圖所示,比例變化後 Hash 值對應的DIP也會改變。原本應該發往 DIP A 的資料包,發給了 DIP B。如果這和資料包是發起建連的 (TCP SYN) ,則B伺服器與該資料包的 Client 端三次握手建立新連線。但如果資料包屬於之前與 A 伺服器建立連線的 Client,因為 B 伺服器沒有對應的 TCP socket,會向 Client 傳送 RST 斷開連線。

要解決這個問題,需要 B 伺服器收到的資料包不屬於自己的 socket 後,將這類資料包二次轉發給A伺服器。也就是說 B 伺服器需要知道二次轉發的資料包應該發給誰,如果把這個資訊存下來,A 伺服器與 Client 的連線就可以繼續保持。

為了實現這一點,我們擴充套件了轉發表。使用四元組 Hash 之後的值,對應兩個 DIP,動態更新後的稱為第一跳,動態更新前的稱為第二跳。


B站邊緣網路四層負載均衡器的探索與應用


如果第一跳和第二跳的DIP是一樣的,即使在判斷後發現資料包不屬於第一跳伺服器,也不需要做第二跳的判斷和轉發,因此實際我們只需要保留髮生變化的部分。


B站邊緣網路四層負載均衡器的探索與應用


關於二次轉發的邏輯,主要分為以下三個部分:

  1. 如果資料包是 SYN,則在第一跳伺服器上新建一個連線,保證新連線的資料包都在第一跳伺服器上處理。

  2. 非SYN的資料包,需要檢查第一跳伺服器上是否存在相應的 socket。如果存在,則交由第一跳伺服器處理。

  3. 第一跳不存在對應的 socket,則將該資料包轉發給第二跳伺服器。如果發現第二跳為空則將該資料包丟棄。

如果出現需要轉發到第二跳的情況,因為多轉發了一次資料包,所以在一定程度上會造成頻寬的增大。但是隨著新連線的建立,老連線的斷開,需要二次轉發的資料包比例會很快降低。


B站邊緣網路四層負載均衡器的探索與應用


同時從理論上來說,只要某個 Client 的連線時間足夠長,經過多次轉發表動態調整,比如第一跳和第二跳都不是A伺服器,那麼這個 Client 會因為收到 RST 而斷開。基於當前的調整策略,這種情況是不可避免的。對此我們在調整頻率和調整策略上都做了以下最佳化:

  1. 控制最快調整時間間隔;

  2. 優先選擇透過第一跳和第二跳對換即可實現調整目標的桶;

  3. 優先選擇最近調整次數最少的桶;

  4. 避免表項大規模調整,小步迭代;

  5. 儘可能保證表項連續性,減少碎片等;


2.3 資料面


控制面維護的轉發表是來指導底層做資料轉發的,我們的資料轉發模組使用 XDP 來實現,XDP之前在 QUIC 使用其做效能收發包最佳化[4]時也有介紹,它是 Linux 核心網路棧的最底層整合的資料包處理器。當網路包到達核心時,XDP 程式會在早期被執行 ,跳過了核心協議棧,提高了包處理的效率,XDP 共有3種模式:

  1. Offload:XDP 的 eBPF 程式直接 hook 到可程式設計網路卡硬體裝置上,而不是在主機 CPU 上執行。因為該模式將執行從 CPU 上移出,並且處於資料鏈路的最前端,過濾效率與效能最高。

  2. Native:XDP的 eBPF 程式在網路驅動程式的早期接收路徑之外直接執行。

  3. Generic:可以在沒有硬體或驅動程式支援的主機上執行上執行 XDP 的 eBPF 程式。缺點:模擬執行,需要分配額外的套接字緩衝區,導致效能下降。

Offload 模式雖效能最優但需要特定硬體的支援,Native 模式為最常用的模式,掛載在驅動路徑上,需要驅動的支援,Generic 模式是核心模擬出的一種模式,不依賴於網路卡驅動,不過掛載點靠後,效能在三種模式種最差。綜合邊緣節點機器網路卡、系統等因素,我們在生產環境選用Native 模式。


B站邊緣網路四層負載均衡器的探索與應用


控制面維護的轉發表,傳遞到XDP模組時,其本身是一個型別為 map in map 的 eBPF map。外側的 map key 為使用者訪問的服務二元組,即服務的 IP 和 Port,外側的 map value 對應內側的 eBPF map物件;內側的 map key 為桶的編號,即 Hash 的索引值,value 為一個 simple C struct, 內部儲存了第一跳和第二跳的IP地址。資料面在進行相應的 hash value calculation 之後,找到一對 Hop IPs,將使用者的原始資料包封入由該 Hop IPs 組成的 GUE header 中。

GUE header[5] 為 Github LB 使用的一個私有頭格式,詳細見下圖。在封包完成後,XDP 將該資料包傳輸給對應機器,在該機器上,由 TC 透過四元組判斷該連線是否已存在;如果存在,則將該資料包解封並傳輸給上層;如果不存在,則根據 GUE header 轉發給下一跳。


B站邊緣網路四層負載均衡器的探索與應用


在 TC 解封完成後,如果此邊緣叢集支援 VIP,並且服務監聽了該 VIP,其已經可以正常透過 Linux 網路協議棧的 Socket 拿到資料包,由於目前我司邊緣叢集尚不支援 VIP,除非透過 ip_transparent 等特殊手段,否則後端伺服器上的服務無法監聽作為 LB 的機器的 IP。為了使後端服務無感,我們選擇使用過渡手段的 netfilter conntrack 對 ingress 資料包進行 SNAT (Source Network Address Translation) ,並對 egress 資料包進行 DNAT (Destination NAT) 。由於 conntrack 本身的效能瓶頸,會限制 Ni 作為 LB 的能力。不過在當前線上的業務場景下,並不會達到 conntrack 的效能瓶頸,邊緣節點支援 VIP 也在和相關部門推進中,未來支援後,去掉 NAT 轉換 Ni 的效能會進一步提高。


B站邊緣網路四層負載均衡器的探索與應用


03 應用場景


 3.1 動態加速的應用


動態加速是在傳統 CDN 基礎上實現的對資料網路加速進一步最佳化的智慧管理服務,透過全方位的 CDN 質量監控,以及智慧易用的節點排程等功能,提供穩定快速的網路訪問服務。

動態加速的節點分佈在全國的各個地區,每個節點都由多臺機器組成。如果將節點內所有機器全都對外暴露,可能會有以下問題:

  1. 增加動態智慧選路服務的運算量,一定程度上增加排查問題的複雜度;

  2. 如果單臺機器不可用時需要透過遠端探測發現並反饋到選路服務,進而計算新的路並下發,流程較長,造成路徑切換變慢;

  3. 動態加速機房多為過保機器,存在硬體配置殘次不齊的情況,效能好的機器應該處理更多的業務請求;

部署Ni之後

  1. 將機房內機器組成一個叢集,收斂流量入口;

  2. 透過主動健康檢查實時將不可用服務摘流,叢集外部無感,服務恢復後自動加回;

  3. 檢查叢集內機器的 CPU 使用情況,並根據配置引數做出實時調整;


B站邊緣網路四層負載均衡器的探索與應用


下圖為紅色部分代表機器 CPU 升高超出閾值後,自動將該機器接流佔比減小的監控。


B站邊緣網路四層負載均衡器的探索與應用


 3.2 點直播CDN叢集化場景的應用


單個點直播叢集內可能有幾臺或幾十臺機器,排程服務從感知資源池內機器狀態變化到對使用者的請求做出反應,可能會有分鐘級的延遲,存在一定的滯後性。且在多機房、多機器的排程場景下,基於排程服務的負載均衡也難以完全將流量打均。將負載均衡能力下沉到機房內之後,反應時間可以降低到秒級,靈敏度更高。同時流量排程的的控制粒度也可以做到更加精細,更有利於提升邊緣叢集的利用率。


B站邊緣網路四層負載均衡器的探索與應用


下圖為某機房部分機器部署Ni前後48小時的的 QPS 對比,可以看到部署之後可以將請求平均分配到各機器,進而平衡 CPU 使用率。


B站邊緣網路四層負載均衡器的探索與應用
B站邊緣網路四層負載均衡器的探索與應用


說明:因業務特性未開啟根據負載動態調整功能。在均衡請求量相同的情況下,因影片資源不同等因素,CPU 會存在一定的差異。


04 未來展望


目前 Ni 已在動態加速大節點及點直播 CDN 叢集化場景全量。穩定執行保障S13 直播賽事。不過仍有需要補齊和最佳化的地方。

  1. 支援黑白名單,透過 XDP 過濾邊緣的攻擊;

  2. 支援 RFC QUIC-LB 定義的規則;

  3. 支援基於 VIP 的 DSR 模式,消除因Conntrack造成的限制,進一步降低負載;


參考連結:

[1] https://blog.cloudflare.com/unimog-cloudflares-edge-load-balancer/

[2]

[3]

[4] https://mp.weixin.qq.com/s/uPHVo-4rGZNvPXLKHPq9QQ 

[5] https://github.com/github/glb-director/blob/master/docs/development/gue-header.md


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70027824/viewspace-2999666/,如需轉載,請註明出處,否則將追究法律責任。

相關文章