天天看點

從0到1000萬:哔哩哔哩直播架構演進史

作者:技術聯盟總壇

原創 趙海林 哔哩哔哩技術 2022-09-23 12:00 發表于上海

本期作者

從0到1000萬:哔哩哔哩直播架構演進史

趙海林

B端技術中心資深開發工程師

01 前言

哔哩哔哩直播成立于 2014 年,經過 8 年時間的發展已經從最初的業務試水成長為公司重要的業務闆塊之一。技術架構也從一個單體服務演進為由數百個微服務組成的複雜系統。本文将回顧 8 年來哔哩哔哩直播架構演進中一步步的變化,帶你了解它是如何從 0 開始逐漸成為能夠承載千萬線上的微服務系統。

02 從0到1

和大多數網站一樣直播也是始于一套 LAMP 架構,即 Linux + Apache + MySQL + PHP 。前端、服務端、定時任務所有功能都集中在一個叫做 "live-app-web" 的項目中。

從0到1000萬:哔哩哔哩直播架構演進史

直播系統架構

一個典型直播背景架構由三部分組成:業務系統用于直播各種業務功能邏輯實作、推拉流系統用于主播推流和使用者拉流觀看、長連接配接系統用于在直播中的各類實時業務資料推送觸達。而 live-app-web 即承擔了 application server 的角色。

從0到1000萬:哔哩哔哩直播架構演進史

live-app-web 的應用架構

在 live-app-web 中既有通過 PHP 模闆引擎 Smarty 渲染的頁面,也有JS 寫的前端頁面,還有常駐背景的 PHP 消息隊列處理程式(通過 Redis List 實作的生産-消費模型),這些功能被分别放在各自的代碼目錄中,分别由前後端開發人員進行代碼開發,并最終部署到一台台實體機上。

從0到1000萬:哔哩哔哩直播架構演進史

live-app-web 最初的項目結構

雖然現在看起來這套架構非常簡陋,但在最初的 2 年裡我們在 live-app-web 實作了每個直播平台所必備的各類業務系統,而這些系統也在後續的演進中也在不斷發展壯大成為一個個重要且獨立的業務系統。

從0到1000萬:哔哩哔哩直播架構演進史

live-app-web

像任何一個高速發展的業務一樣,live-app-web 的代碼量也在急速增長,從 2015年中的 5W 行 PHP 代碼到年末的 8W 行,再到 2016 年中已經累計到了 13W 行。我們在這期間做了一定的前後端分離改造,将前端部分拆成一個個單獨的前端應用,如直播首頁、直播房間頁、直播個人中心頁等。但随着業務增長和人員擴充單體應用帶來的問題也越來越多,并行項目帶來的合并沖突、釋出排隊、某個子子產品問題導緻整站挂等問題日漸突出,而這些問題也終于在一個重要事件上集中爆發了。

從0到1000萬:哔哩哔哩直播架構演進史

2016 年某一時刻的 git 狀态

03 局座來了

不了解局座B站直播梗的同學可以先通過這個連結了解一下事件背景:如何看待張召忠将軍7月13日的b站直播?[1],一句話總結就是:局座來了直播挂了,睿總在知乎公開道歉。

從0到1000萬:哔哩哔哩直播架構演進史

當時的直播幾乎受到全網的群嘲,微網誌、知乎各類吐槽的聲音鋪天蓋地。回頭來看一方面是對觀看人數的預估不足,另一方面受到單體服務架構的制約,監控告警、資源彈性、限流降級、故障隔離等手段都非常缺乏。痛定思痛之後直播開啟了微服務化的曆程。

04 微服務化

如何做微服務?這是擺在當時團隊的一大難題,由于當時團隊成員主要是 PHP 背景,同時業務也在快速疊代,切換語言從 0 開始顯然是不現實的。而當時正好有一款在國内很火的 PHP 高性能服務架構 Swoole,通過程序常駐的方式顯著提升了 PHP 服務的運作性能。經過一定的技術調研之後團隊決定以 Swoole 為基礎建構直播的微服務架構,并定義了以下原則:

  1. 按業務領域進行微服務拆分
  2. 每個微服務擁有自己獨立的資料庫、緩存
  3. 每個微服務僅能通路自己的資料庫、緩存,服務間隻能通過 RPC 通路
  4. 微服務負責人對自己的負責業務的服務穩定性負責

服務架構:我們基于 Swoole 開發了我們自己的微服務架構,這套微服務架構實作服務程序管理、平滑重新開機、ORM、Cache、Logging 等,業務隻需要按照模闆實作 controller 和對應 service 代碼即可,能夠比較快速地上手開發。

通信協定:微服務間通信我們采用了基于 TCP 上自行封裝的 RPC 協定并稱之為 liverpc ,這個 RPC 協定非常簡單直覺,通過固定長度 Header 頭 + 變長JSON Body 實作,服務間以 TCP 短連接配接進行服務調用。

服務發現:引入微服務後還需要解決的一個問題是如何做服務發現?結合當時的背景我們選擇了 zookeeper 作為服務發現元件,同時為了隔離服務注冊、發現、健康檢查的複雜性,我們專門開發了一個叫做 Apollo 的業務伴生程式用于服務配置拉取、服務注冊、服務節點發現,業務架構通過檔案監聽的方式感覺配置變化進行熱加載。

配置管理:同樣地我們采用了 zookeeper 來儲存每個服務的配置檔案,并通過 Apollo 進行配置拉取和變更監控。

消息隊列:我們搭建專門的 kafka 機器作為消息隊列,由于 PHP 直接跟 Kafka 互動較為複雜,我們搭建了專門的投遞代理服務 publisher 和消息回調通知服務 notify。

統一網關:另一方面針對缺乏統一限流、降級能力的問題,我們單獨開發了一個網關服務 live-api ,并且要求所有外部的通路都需要經過 live-api 轉發到對應的業務服務。在這一層統一網關上我們實作了 流量轉發、URL 重寫、逾時控制、限流、緩存、降級等能力。live-api 也是基于 swoole 實作的,不同的地方在于我們是通過 swoole 提供的純異步 client 實作,在性能上有一定保證。

至此一整套微服務系統的雛形已經顯現出來。

從0到1000萬:哔哩哔哩直播架構演進史

在這一套微服務系統上我們逐漸将 live-app-web 各自業務域的邏輯重構到對應的服務中。同時我們和 DBA 一起協作完成了直播的資料庫線上拆分,将原來集中在一個庫的業務表拆分到一個個獨立的資料庫中,實作了高速路上換輪子,也徹底解除了存儲層混用的風險。

2017 年12月局座再次來到 B 站開直播,帶來了比去年多得多的流量,但這一次我們穩了。

從0到1000萬:哔哩哔哩直播架構演進史

05 容器化

一直以來直播服務均采用實體機部署的方式,這種方式存在明顯的缺陷:需要為每個服務配置設定獨立的端口避免端口沖突、部署目錄需要隔離、存在資源競争、單個服務容量無法準确評估等等。而随着 B 站業務規模的擴大,公司的基建團隊也提供了更為穩定的容器平台,在充分調研後我們啟動了服務 Docker 化改造并在很短的時間内完成了全部服務的容器化部署。

在 Docker 化部署中面臨的一個問題是:如何選擇 CPU 排程方式 ?

我們知道在 Docker 中通常有兩個方式 :1、CFS (完全公平排程)即通過按比例的 CPU 時間分片進行排程,這種資源配置設定方式比較靈活,也可以通過資源超配來提升整體的資源使用率;2、CPUSET(綁核)這種方式通過設定 CPU 親和性将 POD 綁定到指定的一個或多個 CPU,實作資源上的獨占。

我們在将 PHP 服務遷移 Docker 時發現 CFS 模式下接口逾時非常嚴重,已經達到了無法接受的程度,是以所有的 PHP 服務均采用了 CPUSET 的方式部署,同時 PHP 服務的工作程序數也通過壓測的方式得到最佳配置,為配置設定的 CPU 數量的 3~4 倍表現最佳。

在 CPUSET 模式下同樣存在的突發流量的困擾,這類突發流量在 Prometheus 的監控圖表中難以發現,因為監控資料通常是以30s 周期采集拟合生成監控曲線。但在請求日志上我們可以清晰地看到一條條秒級的請求突刺存在,而這些請求量遠遠超過了我們為服務配置的 CPUSET 數量,而要滿足這種突發流量而調高配額顯然也是不現實的,因為這會造成極大的資源浪費。

從0到1000萬:哔哩哔哩直播架構演進史

針對這種場景我們将應用資源池分成了兩個分組:固定資源池和彈性資源池,固定資源池中的服務采用 CPUSET 固定配置設定好資源量,而彈性資源池采用多個服務混部的方式,單個服務不限制其資源使用量。并通過網關對突發流量進行分流,将突發流量引入到彈性資源池,以此來解決突發流量帶來的容量瓶頸。

從0到1000萬:哔哩哔哩直播架構演進史

網關服務 live-api 會實時統計每個接口的 QPS:當 QPS 小于 X 時流量全部轉發到固定資源池分組,當 QPS > X 時超出門檻值的請求會被轉發到彈性資源池。同時我們實作了請求打标功能,在彈性資源池内的請求會優先請求同在彈性資源池的服務。我們也可以通過觀察彈性資源池的的使用率來判斷固定資源池服務是否需要擴容,最終的目的是通過少量的混部彈性資源池來解決個别服務頻繁的突發流量報錯。

關于 CFS 逾時的問題後來在阿裡雲公開的文章中有了更詳細的闡述,并通過 CPU Burst 技術将 CFS 排程導緻的逾時問題大大緩解,CPU Burst 的核心是将我們常用的令牌桶限流算法引入到了 Linux 核心 CPU 排程上,當 CPU 使用率低于設定的配額時可以累計未使用的配額,并在後續的排程中允許使用累計的這部配置設定額來應對突出流量。随後核心團隊通過核心更新、優化等方式解決了 cgoup洩露、排程不均衡、逾時等問題。同時在核心上通過排程算法優化,利用 CPU Burst、Group Identity 、SMT expeller 等技術實作了在離線業務混部互不影響、全站資源合池等重大技術特性,資源容量和使用率得到極大提升。業務應用也不再通過 CPUSET 這種相對固定的資源配置設定方式,而是在CFS排程模式下通過 VPA、HPA 這樣的彈性資源管理政策,動态、按需地獲得所需要的運作資源。

06 Golang 真香

2018 年是 Golang 大火的一年,毛老師作為 Golang 布道師在哔哩哔哩主站推進 Golang 服務化演進非常成功,并通過 Golang 開發出了一系列的微服務架構和中間件,如 Kratos(Go微服務架構)、Discovery(服務發現)、Overload (緩存代理)等,相當一部分項目也同時在 github 上進行了開源。

彼時的直播正面臨着下一步技術演進的抉擇,因為基于 swoole 建構的 PHP 微服務體系已經不能支撐更大的流量了,其主要問題集中在 :

  1. PHP 的多程序同步模型極易因為單個下遊異常而導緻整個服務挂掉,因為下遊響應變慢 PHP Worker 不能及時釋放,新的請求來了之後隻能排隊等待空閑 Worker,這樣的級聯等待進而導緻系統的雪崩。
  2. 實作 RPC 并發調用較為困難,在一些業務複雜的場景由于隻能串行調用下遊接口,導緻最終對外的接口耗時非常高。
  3. PHP 服務擴容帶來了資料庫、緩存連接配接數的壓力,當時還沒有成熟的資料庫代理,而是每個 PHP Worker 都會直連資料庫,這直接導緻了連接配接數的爆炸,進一步限制了 PHP 服務的擴容能力。

而 Golang 的協程模型正好可以解決這些問題,毛老師在主站 Golang 服務化演進基本完成的情況下親自來到直播指導 Golang 服務化演進。

對于這次 Golang 服務化演進,我們将服務劃分為了三種類型:

  1. 業務網關(interface):業務網關按業務場景進行劃分,如 App、Web 網關,在網關内完成對應場景的 API 接入,對下遊業務服務的資料聚合、App 版本差異處理、功能子產品降級等。
  2. 業務服務(service):業務服務按業務領域劃分,如房間服務、禮物服務,不同的業務服務完成各自的業務邏輯。
  3. 業務任務(job):業務JOB是依附于業務服務的,通常是用于定時任務處理、異步隊列消費等場景。
從0到1000萬:哔哩哔哩直播架構演進史

其中特别要提到業務網關的設計,在直播首頁、房間頁的場景中,由于業務邏輯複雜用戶端通常需要調用十個甚至數十個接口,部分接口還存在時序依賴。不僅用戶端代碼實作複雜,還導緻了用戶端頁面展現的延遲。是以在新的 Golang 網關實作中我們把單一場景的展示資料統一聚合到一個接口中,即打開一個頁面隻需要調用 1~2 的接口即可完成頁面功能渲染。随後我們還在業務網關實作了熱點資料主動緩存、下遊服務異常的自動降級等特性。

經過幾個服務的試點後發現基于Golang 的服務無論在接口耗時還是穩定性上均遠超 PHP 服務,特别是網關需要聚合 10幾個下遊的資料時,通過協程的并發處理接口平均耗時不到原來 PHP 服務的一半。在此後的一段時間越來越多的 Golang 服務建立,更多的 API 也通過 Golang 網關對外提供到 哔哩哔哩 Web、PC、Android、iOS 等各種裝置中。

07 live-app-web 的終結

2019年直播最早的服務 live-app-web 終于完成了它的使命,所有線上功能全部完成重構遷移,實作了 live-app-web 服務整體下線。截止下線時 live-app-web 已累計了 19W 行代碼、上百位 contributers,感謝他們!

08 新網關的誕生

回到 Goalng 微服務演進過程中,我們并沒有讓曾經的 live-api 網關承接 Golang 業務網關的流量,一方面是因為當時 swoole 沒有成熟的異步 http client,另一方面則是基于 PHP 的純異步網關也逐漸顯露出性能瓶頸。而問題在 2019 年也逐漸暴露出來了:

  1. Golang 業務網關限流需要業務在各自服務内分别接入、配置修改後需要重新開機生效。某個緊急情況下甚至發現部分服務未接入限流元件。
  2. live-api 在更大的業務流量下表現不佳,已經成為一個瓶頸,而存量 PHP 服務在相當長一段時間還需要持續疊代和提供服務。

對新網關的需求應運而生,在調研了 Kong、Tyk、Envoy 等多個開源網關,我們決定采用 Envoy 作為資料面,自研 Golang 服務作為控制面的方式來實作新網關。Envoy 在 service mesh 領域幾乎是 No.1 的存在,其非常适合作為流量轉發服務。我們将新網關命名為 Ekango。

為了進一步移除 live-api,我們将原有基于 TCP 的 liverpc 協定更新支援了 HTTP 調用,這樣就可以将請求從 Ekango 直接轉發到對應的 PHP 服務,同時也極大地便利了研發的開發、調試成本。

從0到1000萬:哔哩哔哩直播架構演進史

在 Ekango 網關中我們實作了分布式限流、接口條件 Rewrite、接口降級、統一鑒權、接口風控、多活可用區降級等特性,并提供單機 15W+ QPS 的服務能力。

同時我們基于 Ekango 的設計開發經驗,基于 Envoy 實作了 service mesh 應用:Yuumi。Yuumi 是解決 PHP、JS 等語言通路 Golang 開發的 GRPC 服務問題的解決方案,因為長期以來微服務建設圍繞 Golang 生态展開,對于其他語言的支援卻略顯薄弱。對于直播而言我們希望 PHP 服務也一樣能享受到 Golang 生态同等的服務治理能力,并且能夠友善地調用 GRPC 服務。

Yuumi 的實作解決了這一問題,通過 service mesh 的方式 PHP/JS 程序以 HTTP 協定通路本地的 sidecar 程序,由 sidecar 再将請求轉發到對應的 HTTP 或 GRPC 服務,并且業務服務無需關心服務節點發現、節點錯誤重試、節點負載均衡等等微服務治理問題。

從0到1000萬:哔哩哔哩直播架構演進史

Ekango 幫助直播支援了數個百萬級、千萬級的大型活動均有穩定的性能表現。但他也存在一些缺陷,如部署配置複雜、C++ 代碼難以二次開發,特别是流量治理和管控能力缺乏可視化的控制面,隻有少數幾個開發者才能正确配置。我們在之前的文章中有介紹過微服務團隊開發了 B 站統一的網關,其在支援正常的流量治理能力外,還提供了全流程可視化的接入方式和管控面、API 中繼資料管理、全鍊路灰階釋出等進階特性。是以在充分評估之後直播也将網關流量全量遷移到統一網關上,由統一網關對全站的入口流量進行流量管控和治理。統一網關同時也作為 Kratos 開源項目之一在 Github 上同步更新。

至此直播的架構演進基本告一段落,在此之後我們進行了消息隊列和定時任務的角色拆分、分布式任務排程的引入徹底解決服務單點部署問題。同時積極推動業務多活落地以解決更大範圍的可用性問題,服務好直播業務的快速發展。在架構演進過程中我們也碰到了一些典型問題,在這裡也對這些問題的處理作一定的總結,希望能啟發你的思考。

09 關于熱Key

熱點問題無處不在,搶購、秒殺、抽獎、一次大型活動、突發事件都會形成一個個熱點,而最直接的影響就是産生熱資料,進而導緻單節點被打挂、服務雪崩等可怕結果。對于直播業務而言,最容易産生熱 Key 的就是那些熱門房間,即我們稱之為高線上房間。随着直播架構的疊代,我們對于熱 Key 的處理方式也在發生變化,但都圍繞着多級緩存、分而治之的思路進行,同時也需要考慮資料一緻性、時效性,不能盲目地通過加緩存的方式來解決熱 Key。

9.1 PHP 服務的高線上熱點緩存

從0到1000萬:哔哩哔哩直播架構演進史

在 PHP 微服務時代我們通過一個集中的 monitor-service 收集來自 CDN 和 彈幕長連接配接資料,獲得目前線上人數較高的房間,并将這些房間資訊推送到消息隊列中。由關心熱門房間的服務 job 消費到這些熱門房間資訊,将各自業務可能涉及的熱點資料主動推送到緩存中。而服務程序内也會有一個定時器監聽這些熱門緩存 Key,并定時将這些資料直接拉到 PHP 程序的記憶體當中。這樣熱門房間的業務資料就會直接命中記憶體緩存。

9.2

Golang 服務的高線上熱點緩存

在 Golang 服務建設中我們簡化了熱門房間檢測邏輯,直接提供了一個熱門房間 SDK,業務服務可以直接通過 SDK 判斷特定的 room_id / uid 是否屬于熱點,而由 SDK 内部定時拉取熱門房間清單資訊。業務再通過定時器将熱點房間資料直接緩存到記憶體中。

從0到1000萬:哔哩哔哩直播架構演進史

這樣的好處是:

  1. 熱門的判斷門檻值可以由各個業務服務自行控制,如 A 服務認為 1W 線上屬于熱門,需要進行預熱處理;B 服務認為超過 5W 線上的屬于熱門資料才需要預熱處理。這樣對于非熱門的資料提供較高的資料時效性和一緻性、對于熱門的資料通過犧牲一定的一緻性來實作更高的可用性。
  2. 熱門的處理可模拟、可演練,通常在預期的大型活動中我們會提前将活動房間在背景标記為熱門房間,再通過壓測來驗證熱門房間處理邏輯是否生效、性能是否符合預期。

9.3 熱點資料主動探測

随着直播在 B 站主站業務的融入,我們發現熱點并非僅來自于熱門直播房間這一種場景,熱門稿件、熱門評論同樣會對部分直播服務造成熱 Key 問題。是以我們設計了一個更通用的熱點檢測和處理 SDK 。

從0到1000萬:哔哩哔哩直播架構演進史

業務在接收到使用者請求後調用計數 API,SDK 異步通過滑動視窗+LFU+優先隊列計算Top-K,定時向業務回調統計到的熱點資料 ID ,業務基于這些熱點 ID 将資料源預加載到記憶體。這樣對于熱點的統計和判斷完全取決于業務自身的 QPS 情況,而無需依賴外部資料。最終我們實作了熱點資料的秒級感覺和資料預熱緩存能力。

9.4 代理層的記憶體緩存

Redis 在 6.0 中實作了用戶端緩存機制來解決熱點資料問題。我們的中間件團隊也在内部的緩存代理上實作了用戶端資料緩存,通過中間件管理背景我們可以配置正規表達式比對一類的緩存 Key,符合規則的緩存 Key 會在代理層進行資料緩存,對該 Key 的下一次通路會直接命中本地緩存,不再需要通路緩存伺服器,直到本地緩存失效。

代理層緩存特别适合于已經發現熱 Key 的緊急處理流程中,直接将發現的熱 Key 設定為本地緩存可以極大緩解熱 Key 風險。但其并不适合作為一種通用熱 Key 處理方案進行提前配置,特别是針對一類 Key 的正則比對這會影響這類 Key 的資料一緻性。

9.5

Proxyless Redis Client

內建熱點緩存

熱點探測 SDK 需要業務主動接入,代理層的緩存方案過于簡單。在發生多次熱 Key 觸發告警後,我們與基礎架構同學交流探索出了以 Redis Client 内嵌熱點緩存 SDK 的方式來實作業務的透明接入。在該方案中基礎架構同學借鑒了 HeavyKeeper 算法重新設計了熱點探測 SDK。HeavyKeeper 用于在流式資料中以較小的記憶體開銷獲得非常精确的 TopK 計算結果,統計出的 TopK 即是我們想要知道的熱 Key。業務透明接入和緩存配置動态更新這兩個特性的結合成了熱 Key 的殺手級解決方案。

9.6 熱點寫資料的處理

在直播場景中除了讀熱點,還存在寫熱點的場景。通常是由于大量使用者向同一個主播贈送禮物、發送彈幕等行為産生的寫操作,進而對單條記錄産生大量并發寫場景。進一步分析這些并發寫的場景我們發現通常是針對單條記錄數值的增/減操作,如經驗值、積分、點贊數等,而這類場景天然是可以支援聚合的。是以我們開發了一個聚合寫入 SDK,其可以采用記憶體聚合或 Redis 聚合的方式,将業務對資料的變更操作按設定的周期進行聚合寫入,比如+1、+2、-1 這樣三個操作可以直接聚合成 +2 一個操作。實作這個 SDK 需要考慮聚合視窗大小、下遊 DB 壓力、服務異常重新開機的資料一緻性保證等。

從0到1000萬:哔哩哔哩直播架構演進史

10 關于請求放大

房間服務是直播流量最大也是最核心的服務之一,日常 QPS 維持在 20W+。在營運房間服務中我們發現了以下幾種場景的請求放大:

10.1 請求超出需要的資料

在分析房間服務高 QPS 調用來源方時我們發現部分業務僅需要房間資訊中的一部分資料卻請求了整個房間資訊,比如某些業務方僅需要判斷使用者是否擁有直播間卻調用了完整的房間資訊接口,本來一個字段能解決的問題接口傳回了數十個字段,造成不必要的帶寬消耗和接口耗時。我們參考 FieldMask( 關于FieldMask可參考 Netflix API 設計實踐: 使用FieldMask)的設計将房間資訊拆分成不同的的子產品,如播放相關、直播卡片展示相關等子產品。業務方可根據場景需要組裝 API 調用擷取對應子產品的資料實作按需請求。

10.2 重複的請求

直播間承載了直播近 80% 的業務功能,使用者在進入房間時會請求進房接口。在這個接口中網關會聚合多個下遊的資料後統一傳回給使用者,我們發現這個場景存在重複請求房間資訊的情況。

從0到1000萬:哔哩哔哩直播架構演進史

上圖所示除了 room-gateway 會請求房間資訊外,gift-panel、dm-service 也會分别再請求一次房間資訊,直接導緻了房間服務的請求放大。這樣的下遊服務越來越多後,使用者一次進房将對房間服務産生 10 倍以上的流量放大。而這種流量放大顯然是沒有必要的。解決方案也很直接将 dm-service、gift-panel 依賴的房間資訊通過接口直接傳遞給對應服務。調用時序調整為先調用房間服務擷取房間資訊,再并發調用業務服務擷取業務子產品資料,最後組裝成業務需要的資料傳回。

從0到1000萬:哔哩哔哩直播架構演進史

10.3 業務服務的請求放大

直播間承載了數十種業務功能,使用者的一次進房會分别向這數十個下遊服務進行請求。對每個下遊都要求按照進房 QPS 進行備量,即承擔至少 2W+ 的 QPS。這對于一些小衆的服務是難以承受的,從資料上看對下遊的 99% 請求都是查空的無效請求。為了降低接入房間場景業務的負載、減少資源浪費,我們在房間服務上實作了一個 TAG 機制,業務服務将資料 TAG 同步到房間服務,網關、用戶端 在請求房間資訊後根據 TAG 辨別狀态決定是否請求對應的業務服務,這樣就避免了大量業務需要承擔使用者進房級别的 QPS。

從0到1000萬:哔哩哔哩直播架構演進史

11 關于活動保障

一次大型活動的技術保障是一場技術盛宴,也是對所有研發同學的一次大考。直播技術在曆年的活動保障中沉澱了一系列的工具和方法論。圍繞場景梳理分析、服務容量預估、全鍊路壓測、降級預案、現場保障等方面有一系列标準化方案、工具和平台支援。

11.1 場景梳理

場景梳理的目的是了解一場直播活動中涉及了哪些業務功能、服務和接口,以此針對涉及的業務子產品開展後續的保障工作。通常活動直播間所使用的功能是普通直播間的子集,這就需要直播間内的功能都需要有控制開關,這裡的控制開關一定是需要在終端實作的,即開關關閉後用戶端不會對這一功能服務産生任何請求壓力。場景梳理需要基于使用者的真實操作路徑進行請求錄制,可以通過代理抓包的方式進行自動化的場景錄制,再通過錄制請求對應的 Trace 鍊路快速生成場景依賴關系圖,這個關系圖就明确了該場景下涉及的服務、資源等資訊。

11.2 容量評估

容量評估用于确定活動所需要的資源,以進行采購備量和提前擴容。容量評估一定是基于曆史資料和活動預估進行推算,其中針對不同的業務有不同的增長系數。

11.3 服務壓測

服務壓測通常是對線上服務真實容量進行摸底,一般在服務擴容前和服務擴容後都會進行壓測以驗證服務容量是否滿足活動需求。特别地針對資料寫的場景需要通過全鍊路壓測的手段實作壓測資料和真實資料的隔離,避免壓測産生的髒資料影響線上業務。

11.4 降級預案

無預案不保障,針對可能出現的技術風險都需要有對應的 SOP,且這些 SOP 都需要通過預演的方式驗證方案有效性。

11.5 現場保障

現場值班保障時通常會遇到資訊爆炸、協作難度大的問題,特别是突發的系統告警容易産生驚群效應。需要高效資訊分發、實時協作,實作保障工作的有序流轉、不重不漏、快速執行。基于保障場景的特殊性我們研發了活動實時保障平台。

從0到1000萬:哔哩哔哩直播架構演進史

在實時保障平台中按照業務場景劃分不同的場景負責人和保障值班,所有的線上服務告警、名額異常都會以實時推送的方式展示在對應保障人員的值班頁面。針對常見的告警類型,如 CPU 過高、服務限流會直接關聯到 SOP 手冊,值班人員可以基于手冊指導完成處理預案。在保障結束後我們也可以基于實時保障平台的資料記錄生成保障報告,複盤保障過程中出現的問題、響應時效、執行結果和後續 TODO。

12 高光時刻

2021 的 《英雄聯盟》全球總決賽哔哩哔哩直播實作了單平台超千萬人同時線上的記錄。整場比賽服務運作穩定、使用者觀看流暢,這是屬于直播的高光時刻。

13 未來展望

直播的技術架構仍在向前演進,持續圍繞服務穩定性和高可用建設在業務架構治理、多活和單元化方向不斷進化。期望在今年的 LOL S12 中線上人數再創新高。

如果你有想了解的細節或感興趣的話題,也歡迎留言讨論。

參考資料:

[1] https://www.zhihu.com/question/48457286

[2] https://www.infoq.cn/article/y2semvajjgxj9mbg9p00

[3] https://www.redis.com.cn/topics/client-side-caching.html

[4] https://www.computer.org/csdl/journal/nt/2019/05/08809410/1cFUZDJL2OA

[5] https://github.com/go-kratos/gateway

[6] https://zhuanlan.zhihu.com/p/436382314

繼續閱讀