長連線閘道器技術專題(八):B站基於微服務的API閘道器從0到1的演進之路

JackJiang發表於2022-06-18

本文由B站微服務技術團隊資深開發工程師周佳輝原創分享。

1、引言

如果你在 2015 年就使用 B 站,那麼你一定不會忘記那一年 B 站工作日選擇性崩潰,週末必然性崩潰的一段時間。

也是那一年 B 站投稿量激增,訪問量隨之成倍上升,而過去的 PHP 全家桶也開始逐漸展露出頹勢,運維難、監控難、排查故障難、呼叫路徑深不見底。

也就是在這一年,B 站開始正式用 Go 重構 B 站,從此B站的API閘道器技術子開始了從0到1的持續演進。。。

  • 補充說明:本次 API 閘道器演進也以開源形式進行了開發,原始碼詳見本文“12、本文原始碼”。

PS:本文分享的API閘道器涉及到的主要是HTTP短連線,雖然跟長連線技術有些差異,但從架構設計思路和實踐上是一脈相承的,所以也就收錄到了本《長連線閘道器技術專題》系列文章中。

學習交流:

  • 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
  • 開源IM框架原始碼:https://github.com/JackJiang2...(備用地址點此)

(本文已同步釋出於:http://www.52im.net/thread-39...

2、關於作者


周佳輝:嗶哩嗶哩資深開發工程師。始終以簡單為核心的技術設計理念,追求極致簡單有效的後端架構。

2017 年加入 B 站,先後從事賬號、閘道器、基礎庫等開發工作。編碼 C/V 技能傳授者,技術文件背誦者。開源社群愛好者,安全技術愛好者,雲端計算行業活躍使用者,網路工程熟練工。史詩級 bug 生產者,熟練掌握 bug 產生的各類場景。

3、專題目錄

本文是專題系列文章的第8篇,總目錄如下:

《長連線閘道器技術專題(一):京東京麥的生產級TCP閘道器技術實踐總結》
《長連線閘道器技術專題(二):知乎千萬級併發的高效能長連線閘道器技術實踐》
《長連線閘道器技術專題(三):手淘億級移動端接入層閘道器的技術演進之路》
《長連線閘道器技術專題(四):愛奇藝WebSocket實時推送閘道器技術實踐》
《長連線閘道器技術專題(五):喜馬拉雅自研億級API閘道器技術實踐》
《長連線閘道器技術專題(六):石墨文件單機50萬WebSocket長連線架構實踐》
《長連線閘道器技術專題(七):小米小愛單機120萬長連線接入層的架構演進》
《長連線閘道器技術專題(八):B站基於微服務的API閘道器從0到1的演進之路》(* 本文)

4、正式用Go重構B站

鑑於引言中所列舉的各種技術問題,也是在2015年,財隊開始正式用 Go 重構 B 站。

B站第一個 Go 專案——bilizone,由冠冠老師(郝冠偉)花了一個週末時間編碼完成。

commit 4ccb1497ca6d94cec0ea1b2555dd1859e6f4f223
Author: felixhao <g[url=mailto:1@gmail.com]1@gmail.com[/url]>
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 依舊是一個單體應用,所以它依舊繼承了單體應用所具有的缺點:

1)程式碼複雜度高:方法被濫用、超時設定混亂、牽一髮而動全身;
2)一掛全掛:最常見的比如,超時設定不合理、goroutine 大量堆積、雪崩;
3)測試及維護成本高:小改動都需要測試所有 case,運維釋出膽戰心驚。

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

5、基於微服務的B站架構初具雛形

鑑於bilizone所面臨的單體應用技術缺點,接下來的一次重構,讓B站基於微服務的全域性架構面貌就將初具雛形。

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

當時的呼叫模式如下圖所示:

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

這些困難主要是:

1)客戶端與微服務直接通訊,強耦合;
2)需要多次請求,客戶端聚合資料,工作量巨大,延遲高;
3)協議不利於統一,各個部門間有差異,反而需要通過客戶端來相容;
4)面向“端”的 API 適配,耦合到了內部服務;
5)多終端相容邏輯複雜,每個服務都需要處理;
6)統一邏輯無法收斂,比如安全認證、限流。

6、基於BFF模式的微服務架構

基於上節的初階微服務架構帶來的技術問題,以及我們想要將對端的處理進行內聚的想法,我們自然的而然的就想到在客戶端與後端服務之間加一個 app-interface 的元件,這就是接下來的 BFF(Backend for Frontend)模式。

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

有了這個 BFF 之後,我們可以在該服務內進行大量的資料聚合,按照業務場景來設計粗粒度的 API。

這樣,後續服務的演進也帶來了很多優勢:

1)輕量互動:協議精簡、聚合;
2)差異服務:資料裁剪以及聚合、針對終端定製化 API;
3)動態升級:原有系統相容升級,更新服務而非協議;
4)溝通效率提升:協作模式演進為移動業務和閘道器小組。

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

然而,這個時期的 BFF 還有一個致命的一個問題是——整個 app-interface 屬於 single point of failure,嚴重程式碼缺陷或者流量洪峰可能引發叢集當機所有介面不可用。

7、基於多套BFF模式的微服務架構

針對上節中BFF模式下架構的技術問題,於是我們在上述基礎上進一步迭代,將 app-interface 進行業務拆分。

進而多套 BFF 的模式橫空出世:

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

8、垂直BFF模式時代(2016年至2019年)

接上節,當 B 站閘道器的架構發展為多套垂直 BFF 之後,開發團隊圍繞該模式平穩迭代了相當長的一段時間。

而後隨著B站業務的發展,團隊人員的擴充和幾次組織架構調整,此時開始出現直播、電商等獨立業務,這些業務的發展我們之後再細說。

而在這些調整之後,有一個團隊的職責越來越清晰:主站閘道器組。

主站閘道器組的主要職責就是維護上述各類功能的 BFF 閘道器,此時 bilibili 的主要流量入口為粉板 App。這裡可以簡單細說一下粉板 App 上的所有業務組成。

主站業務:

1)閘道器組維護的 BFF,如推薦、稿件播放頁等;
2)業務層自行維護的 BFF,如評論、彈幕、賬號等。

獨立業務:

1)電商服務;
2)直播服務;
3)動態服務。

主站業務的 BFF 其實被分為兩類:

1)一類是由閘道器組負責的 BFF;
2)另一類是業務自行維護的 BFF。

而這兩類 BFF 的技術棧其實基本一致,基本功能職責也相差不多。如此劃分的原因是讓閘道器組可以更專注於迭代客戶端特性功能,免去理解部分獨立業務場景的介面,如登陸頁應該讓對安全更專業賬號的同學自行維護。

在這裡我們也可以簡述一下,一個新需求應該如何決定參與的 BFF :

1)如果這個功能能由業務層的業務 BFF 獨立完成,則閘道器組不需介入;
2)如果該功能是一個客戶端特性需求,如推薦流等複合型業務,需要對接公司大量部門時,則由閘道器同學參與開發 BFF。

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

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

9、基於業務的統一API閘道器架構

接上節,我們再來談一談幾項重要的業務:電商、直播和動態。

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

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

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

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

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

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

這些問題主要是:

1)單個複雜模組也會導致後續業務整合的高難度,根據康威法則,複雜聚合型 BFF 和多團隊之間就出現不匹配問題,團隊之間溝通協調成本高,交付效率低下;
2)很多跨橫切面邏輯,比如安全認證,日誌監控,限流熔斷等。隨著時間的推移,功能的迭代,程式碼變得越來越複雜,技術債越堆越多。

此時:我們可能還需要一個能協調橫跨切面的元件,將路由、認證、限流、安全等元件全部上提,能夠統一更新發布,把業務整合度高的 BFF 層和通用功能服務層進行分層,進而大家開始引入基於業務的“統一API閘道器”架構(如下圖所示)。

在新的架構中:統一閘道器承擔了重要的角色,它是解耦拆分和後續升級遷移的利器。

在統一閘道器的配合下:單塊 BFF 實現瞭解耦拆分,各業務線團隊可以獨立開發和交付各自的微服務,研發效率大大提升。

另外:把跨橫切面邏輯從 BFF 剝離到閘道器上去以後,BFF 的開發人員可以更加專注業務邏輯交付,實現了架構上的關注分離(Separation of Concerns)。

10、從基於業務的多閘道器到全域性統一閘道器(2022年至今)

在這兩三年的時間裡,各個業務團隊或多或少都有自己業務閘道器組建獨立的維護團隊,也為閘道器的功能作出過相當多的投入。

但隨著 B 站業務的發展,公司級中介軟體功能的不斷更替演進,如果將對接各個中介軟體的工作在每個閘道器上都實現一次的話帶來的人力投入和溝通成本會相當巨大,且實現標準不統一、運營方式不統一無法起到 API 閘道器所帶來的最佳收益。

因此微服務團隊開發了一款 B 站內部意義上的標準 API 閘道器(全域性統一API閘道器),該 API 閘道器彙集以往各型閘道器中流量治理的優秀經驗,對相關功能做出完善設計改進。

該 API 閘道器的目前的主要功能除了常規的限流、熔斷、降級、染色外,還會基於這些基礎功能和公司各類中介軟體的基礎上,提供各種額外能力。

這些額外進階型AP 質量治理的相關功能主要是:

1)全鏈路灰度;
2)流量取樣分析、回放;
3)流量安全控制;
...

業務團隊在接入 API 閘道器後都可以一併獲得這些功能,為業務的迅速迭代做出力所能及的保障。

11、不僅僅是 API 閘道器

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

這些API 開發生態可能是:

1)規劃 API 業務域,簡化 SRE 運維;
2)標準 API 元資訊平臺;
3)精確的 API 文件和除錯工具;
4)型別安全的 API 整合 SDK;
5)API 相容性保障服務。

API 閘道器是我們 API 治理生態中的一個標誌性里程碑,我們希望在 API 閘道器的開發中能夠多多傾聽大家的意見,希望能有更多的聲音來幫助我們理清思路。

本次 API 閘道器演進也以開源形式進行了開發,在這裡歡迎大家指導(本次原始碼詳見本文“12、本文原始碼”)。

12、本文原始碼

主地址:https://github.com/go-kratos/...
備地址:https://github.com/52im/gateway
或從原文連結中下載附件:http://www.52im.net/thread-39...

13、參考資料

[1] 喜馬拉雅自研億級API閘道器技術實踐
[2] 手淘億級移動端接入層閘道器的技術演進之路
[3] 從100到1000萬高併發的架構演進之路
[4] 一文讀懂大型分散式系統設計的方方面面
[5] 零基礎理解大型分散式架構的演進歷史、技術原理、最佳實踐

(本文已同步釋出於:http://www.52im.net/thread-39...

相關文章