作者 | 黃逸偲
BFF — Backend For Frontends,經(jīng)典分布式架構(gòu)設(shè)計模式之一。我在學(xué)習(xí)和工作經(jīng)驗累積中,逐漸加深了對 BFF 的理解。作為一種模式,它具有一些更加確切的使用場景,和一些能匹配的特定問題。
在本篇文章中,你們會與我一起穿越回BFF誕生的歷史中,尋找其起源。并一同探索和學(xué)習(xí)這個在分布式系統(tǒng)中出鏡率極高的架構(gòu)模式。
尋找歷史的線頭
在毫無頭緒的情況下,我們可以首先從Thoughtworks技術(shù)雷達中 BFF 的條目入手,去找到一些歷史的蛛絲馬跡。BFF 條目的發(fā)布時間是在 2015 年 11 月10 日。從這個信息我們可以獲知,BFF 在歷史嶄露頭角應(yīng)該是在 2015 年 。
緊接著,在谷歌搜索關(guān)鍵字Backend for Frontends 以及將時間范圍限定在 2015 年 1 月 1 日到 2015 年 11 月 10 日。通過對比搜索結(jié)果的時間,我們可以輕易發(fā)現(xiàn)最早出現(xiàn) Backend for Frontends 詞條的文章。文中提到,BFF 這個名字是由當(dāng)時團隊 Tech Leader Nick Fisher首次提出,通過投票獲得了內(nèi)部團隊的認可。好了,我們現(xiàn)在獲得了一個非常具體的證據(jù)。作為嚴(yán)謹?shù)募夹g(shù)工作者,我們找到其他的交叉證據(jù),提高這個結(jié)論的置信度。
非常幸運的是,在另一篇2015 年的 Thoughtworks 洞見文章中也提到了與上面證據(jù)相同的內(nèi)容。終于,我們可以說 BFF 模式是在解決 SoundCloud的分布式系統(tǒng)問題中首次出現(xiàn)。下面,讓我們一起回到BFF第一次發(fā)揮威力的現(xiàn)場吧。
神功初成
為了能讓大家更容易了解到SoundCloud 當(dāng)年究竟遇到了什么樣的挑戰(zhàn),我會在下面通過分類分項來列舉情況以及進行分析。
背景:
- SoundCloud主要是通過付費訂閱與廣告進行盈利(也就是說,越多的曝光渠道,會給SoundCloud 帶來更多的盈利)
- SoundCloud 是一個單體系統(tǒng),通過暴露共享 API 的方式為 Web 客戶端、Android 和 iOS 應(yīng)用程序以及互聯(lián)網(wǎng)、合作伙伴等渠道提供服務(wù)。這些共享 API 隨著功能和特性一起增長,最終變成了平臺與客戶端之間的集成點。
- 將 2007 年開始運行的 SoundCloud 從單體模式轉(zhuǎn)變至微服務(wù)模式, 這里是具體改造過程。此時,單體服務(wù)已經(jīng)被拆分為多個微服務(wù)。
- 支持在 iOS 平臺上新增的應(yīng)用程序(原來的產(chǎn)品主要是在 Web 端提供服務(wù))
主要動機:
- 減少產(chǎn)品發(fā)布上線的時間
- 支持 iOS 平臺新的應(yīng)用程序,隔離新用戶體驗設(shè)計帶來的風(fēng)險。
- 增加后端團隊與客戶端團隊合作的節(jié)奏,提高工作效率。
挑戰(zhàn):
- 為了讓第三方開發(fā)人員能更自由地集成,需要 API 設(shè)計不對數(shù)據(jù)的使用方式做出任何假設(shè)。所以,為了提供簡單的體驗,也需要許多不同的 HTTP API 提供具有高數(shù)據(jù)寬容度的服務(wù)。最終,獲取構(gòu)建一個簡單的頁面的數(shù)據(jù),也需要上百個 API 請求。
- 當(dāng)團隊需要變更現(xiàn)有 API 時,需要確保不會破壞現(xiàn)有的任何客戶端以及重要的第三方集成。所以,一旦需要添加新內(nèi)容,都必須投入巨大工作量來確保新功能不只適用于特定客戶端。上面這些情況使協(xié)調(diào)日常工作變得更加困難,最終導(dǎo)致了新功能發(fā)布緩慢。
- 開始準(zhǔn)備開發(fā)新 iOS 應(yīng)用程序, 新平臺上應(yīng)用程序的用戶體驗會全部被重塑
通過分析上面的各種情況,可以得出當(dāng)時SoundCloud 后端團隊面對如下幾個問題:
- 問題一:需要為第三方客戶提供合適粒度的 API,結(jié)果提供的 API 數(shù)據(jù)粒度過細,導(dǎo)致想完成一個業(yè)務(wù)服務(wù)需要請求的 API 太多。
- 問題二:對外 API 與特定的使用方耦合嚴(yán)重,邊界模糊,復(fù)雜度高導(dǎo)致維護 API 的工作量巨大,新功能發(fā)布緩慢。
- 問題三:iOS 平臺新客戶端改 進了用戶體驗和交互方式,需要隔離新App帶來的風(fēng)險,并且還要找到與多個客戶端團隊更好的合作方式。
這三個問題在后端團隊進行微服務(wù)改造中往往也會遇到。讓我們一起看看,當(dāng)年的 SoundCloud 團隊在面臨同樣的問題時,是如何一步步見招拆招,摸索出 BFF模式 這個內(nèi)功心法的。
演進之路
接下來,BFF 模式演進這一分是由客戶端團隊獲得的。由于他們是 API 的消費者, 可以將不同服務(wù)進行多次邏輯調(diào)用,混合到后端的用戶配置(UserProfile)文件中。這樣避免了對后端服務(wù)多次不同的調(diào)用,實現(xiàn)客戶端對單個資源的簡單請求。這將簡化客戶端代碼并提高整體性能,例如:
- GET /user-profile/123.json
后端團隊接受了這個邏輯,并開始試驗這個方式。他們在 BFF 中編寫了很多 Presentation Model。在完成一部分任務(wù)后,后端團隊突然意識到 BFF 不只是被客戶端使用的 API ,它本身就是申請的一部分。BFF 新的形態(tài)出現(xiàn)了,具體如下圖所示:
隨著時間推移,SoundCloud 的 BFF 也在增加。他們已經(jīng)在生產(chǎn)環(huán)境同時維護著 5 個 BFF 了。為了進一步提高生產(chǎn)力,減少不必要的重復(fù)。用戶配置(User Profile) 被從每個不同的微服務(wù)中抽取出來,變成一個獨立的在 Services 與 BFF 之間的應(yīng)用服務(wù)(Application Service)。
SoundCloud 的 BFF 依然隨著時間在橫向增長,不同的是這種橫向增長不會再引起任何問題了。最終,BFF 模式的架構(gòu)演變成與我們現(xiàn)在使用的幾乎一致了。架構(gòu)如下圖:
總結(jié)
我們在維護和使用分布式架構(gòu),同時面對多客戶端時,BFF 模式提供了一種很好的架構(gòu)模式,使后端團隊在構(gòu)建面向客戶端的復(fù)雜需求時,能夠掌控自己的命運。并且,這種自主性對于快速迭代的客戶端應(yīng)用程序,能夠提供快速而良好的體驗。通過支持持續(xù)的演進和變化,這種模式可以將相同變化趨勢的消費者行為,限制在一個可控范圍內(nèi)。使他們變得更容易合作和改變,并且更好滿足不同客戶端的特性需求。
在系統(tǒng)架構(gòu)中,因為離需求頻繁變化的前端比較近(網(wǎng)絡(luò)和組織架構(gòu)上),BFF很容易野蠻生長,成為各種“妥協(xié)”的自留地,在使用的過程中,我們需要明確架構(gòu)中各層相關(guān)的職能和邊界。同時,如果確實有不得不去做的一些“妥協(xié)”,我們也一定要用技術(shù)債的方式,繼續(xù)跟蹤和管理,避免“妥協(xié)”越來越多以后,BFF從一個解決不同變化速率和需求的適配器,變成分布式單體的一個轉(zhuǎn)化器。
我們往往會在系統(tǒng)設(shè)計之初犯下一個錯誤,那便是希望所有東西在一開始都是可復(fù)用的。這種思路會給系統(tǒng)后續(xù)的開發(fā)和維護帶來巨大的挑戰(zhàn),挑戰(zhàn)可能是來自應(yīng)用間的協(xié)調(diào),也可能是兼顧復(fù)用帶來的高工作量。特別是在維護多個客戶端或消費者的場景下會帶來更大的困難。我們應(yīng)該在考慮通用用法之前,先專注于功能和特定用例。在了解系統(tǒng)現(xiàn)狀的主次和具體情況后,再針對性地區(qū)分需要通用和特殊處理的部分。這種系統(tǒng)設(shè)計和開發(fā)的思路和方式,使我們能夠擁抱變化,立于演進的不敗之地。