B 站 API 網關的發展

周佳輝

嗶哩嗶哩資深開發工程師

2017 年加入 B 站,先後從事賬號、網關、基礎庫等開發工作。編碼 C/V 技能傳授者,技術文檔背誦者。

開源社區愛好者,安全技術愛好者,雲計算行業活躍用戶,網絡工程熟練工。史詩級 bug 生產者,熟練掌握 bug 產生的各類場景。

始終以簡單爲核心設計理念,追求極致簡單有效的後端架構。

背景

如果你在 2015 年就使用 B 站,那麼你一定不會忘記那一年 B 站工作日選擇性崩潰,週末必然性崩潰的一段時間。也是那一年 B 站投稿量激增,訪問量隨之成倍上升,而過去的 PHP 全家桶也開始逐漸展露出頹勢,運維難、監控難、排查故障難、調用路徑深不見底,而也就是在這一年,B 站開始正式用 Go 重構 B 站。

B 站第一個 Go 項目:bilizone 由冠冠老師(一個週末)編碼完成。

commit 4ccb1497ca6d94cec0ea1b2555dd1859e6f4f223
Author: felixhao <g******1@gmail.com>
Date:   Wed Jul 1 18:55:00 2015 +0800
    project init
commit 6e338bc0ee638621e01918adb183747cf2a9e567
Author: 郝冠偉 <h*******@bilibili.com>
Date:   Wed Jul 1 11:21:18 2015 +0800
    readme

bilizone 其實還是一個大而全的應用,bilizone 在當時重構的主要意義是將誰也理不清的 PHP 邏輯梳理成了一個比較標準的 Go 應用。

bilizone 在當時最大的意義就是爲用戶終端提供了基本穩定的數據結構、相對可靠的接口和比較有效的監控。但因 bilizone 依舊是一個單體應用,所以它依舊繼承了單體應用所具有的缺點:

所以此時 B 站的崩潰頻率雖然已經有所降低,但一炸全炸的問題依舊是一個心腹大患。

而再接下來的一次重構,B 站微服務的全局面貌就將初具雛形。

爲了實現微服務模式下的 bilibili,我們將一個 bilizone 應用拆分成多個獨立業務應用,如賬號、稿件、廣告等等,這些業務通過 SLB 直接對外提供 API。

當時的調用模式如下圖所示:

圖片

但是隨着功能拆分後,我們對外暴露了一批微服務,但是因爲缺乏統一的出口而面臨了不少困難:

基於上述問題和我們想要將對端的處理進行內聚的想法,我們自然的而然的就想到在客戶端與後端服務之間加一個 app-interface 的組件,這就是接下來的 BFF(Backend for Frontend)模式。

app-interface 的工作模式如下圖所示:

圖片

有了這個 BFF 之後,我們可以在該服務內進行大量的數據聚合,按照業務場景來設計粗粒度的 API,給後續服務的演進帶來的很多優勢:

BFF 可以認爲是一種適配服務,將後端的微服務爲客戶端的需要進行適配(主要包括聚合裁剪和格式適配等邏輯),向終端設備暴露友好和統一的 API,方便無線設備接入訪問後端服務,在其中可能還伴隨有埋點、日誌、統計等需求。

這個時期的 BFF 還有一個致命的一個問題是整個 app-interface 屬於 single point of failure,嚴重代碼缺陷或者流量洪峯可能引發集羣宕機所有接口不可用。於是我們在上述基礎上進一步迭代,將 app-interface 進行業務拆分,進而多套 BFF 的模式橫空出世:

圖片

由此模式開始,基本確定了 B 站微服務接口的對接模式,這套模式也隨之在全公司內推廣開來。

垂直 BFF 時代 2016-2019

接上文當 B 站網關的架構發展爲多套垂直 BFF 之後,開發團隊圍繞該模式平穩迭代了相當長的一段時間。而後隨着 B 站業務的發展,團隊人員的擴充和幾次組織架構調整,此時開始出現直播、電商等獨立業務,這些業務的發展我們之後再細說。而在這些調整之後,有一個團隊的職責越來越清晰:主站網關組。

主站網關組的主要職責就是維護上述各類功能的 BFF 網關,此時 bilibili 的主要流量入口爲粉板 App,這裏可以簡單細說一下粉板 App 上的所有業務組成:

主站業務

獨立業務

主站業務的 BFF 其實被分爲兩類,一類是由網關組負責的 BFF,另一類是業務自行維護的 BFF。

而這兩類 BFF 的技術棧其實基本一致,基本功能職責也相差不多,如此劃分的原因是讓網關組可以更專注於迭代客戶端特性功能,免去理解部分獨立業務場景的接口,如登陸頁應該讓對安全更專業賬號的同學自行維護。在這裏我們也可以簡述一下一個新需求應該如何決定參與的 BFF :

當時主站技術部的後端同學遵循以上兩個規則,基本能夠滿足業務的快速開發和迭代。

我把這段時間稱爲垂直 BFF 時代,因爲基本主站每個業務或多或少都有各種形式的網關存在,大家通過這個網關向外提供接口,該網關和 SLB 進行直接交互。 

再談一談電商、直播和動態

電商和直播其實並不是同一時期衍生的,直播在主站 PHP 時期就誕生了,而電商相對更晚一些。

當時直播的技術棧組成有 C++、PHP、Go,其中早期大部分業務邏輯由 PHP 和 C++ 實現,稍晚一些也開始逐步試用主站的 Go 實現部分業務邏輯。其中 PHP 負責對終端提供接口,C++ 主要實現核心業務功能。因此我們可以簡單理解爲直播使用由 PHP 編寫的 BFF 網關。

動態團隊其實派生自直播團隊,因此技術棧和直播當時基本一致,這裏可以簡單省略。

而衆所周知,大部分電商團隊的技術棧都是 Java 和 Spring 或 Dubbo。

因這幾個業務實現上幾乎沒有相似的地方,且大家對 gRPC 協議逐漸地認同,因此技術棧上大家基本沒有大一統的想法,互相能調通即可。

而隨着 B 站團隊進一步的壯大、流量持續的增長,進而經歷了諸多線上故障、事故分析之後,大家慢慢發現了這套架構下的問題:

此時我們可能還需要一個能協調橫跨切面的組件,將路由、認證、限流、安全等組件全部上提,能夠統一更新發布,把業務集成度高的 BFF 層和通用功能服務層進行分層,進而大家開始引入 「統一 API 網關」

圖片

在新的架構中,統一網關承擔了重要的角色,它是解耦拆分和後續升級遷移的利器。在統一網關的配合下,單塊 BFF 實現瞭解耦拆分,各業務線團隊可以獨立開發和交付各自的微服務,研發效率大大提升。另外,把跨橫切面邏輯從 BFF 剝離到網關上去以後,BFF 的開發人員可以更加專注業務邏輯交付,實現了架構上的關注分離(Separation of Concerns)。

從多個網關到最後一個統一網關 2022 - 至今

圖片

在這兩三年的時間裏,各個業務團隊或多或少都有自己業務網關組建獨立的維護團隊,也爲網關的功能作出過相當多的投入。但隨着 B 站業務的發展,公司級中間件功能的不斷更替演進,如果將對接各個中間件的工作在每個網關上都實現一次的話帶來的人力投入和溝通成本會相當巨大,且實現標準不統一、運營方式不統一無法起到 API 網關所帶來的最佳收益。

因此微服務團隊開發了一款 B 站內部意義上的標準 API 網關,該 API 網關彙集以往各型網關中流量治理的優秀經驗,對相關功能做出完善設計改進。該 API 網關的目前的主要功能除了常規的限流、熔斷、降級、染色外,還會基於這些基礎功能和公司各類中間件的基礎上,提供了:

等等進階型 API 質量治理的相關功能,這些功能業務團隊在接入 API 網關後都可以一併獲得,爲業務的迅速迭代做出力所能及的保障。

不僅僅是 API 網關

在開發 API 網關的同時,我們也會更進一步關注業務團隊開發、對接 API 時的體驗,我們將以網關作爲統一標準 API 規範的起點,爲業務團隊提供更有效的 API 開發生態,如:

API 網關是我們 API 治理生態中的一個標誌性里程碑,我們希望在 API 網關的開發中能夠多多傾聽大家的意見,希望能有更多的聲音來幫助我們理清思路。本次 API 網關也以開源形式進行開發,在這裏歡迎大家指導:https://github.com/go-kratos/gateway

嗶哩嗶哩技術 提供 B 站相關技術的介紹和講解

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/-bV1gZq7GO6bGPcYGAwc9g