跳至主要內容
ESC
經典架構拆解 — 第 5/6 篇

經典架構拆解 · 05 — Airbnb 搜尋排名與金流分帳

經典架構拆解 · 05 — Airbnb 搜尋排名與金流分帳

Airbnb 是個雙邊市場(marketplace):一邊是房東、一邊是房客,中間夾著搜尋排名、信任評分、跨國金流。這三件事對架構師來說,每一件單獨拿出來都夠寫一套系統,湊在一起就更難了。

這是 經典工程架構拆解 系列的第 5 篇,上一篇看了 Slack 的 WebSocket 與已讀同步


為什麼值得拆解

大部分電商平台的搜尋,講白了就是「關鍵字比對 + 排序」。Airbnb 不一樣,它每跑一次搜尋,都得同時考慮這個房客的偏好、每間房的動態定價、當前還空著的日期、平台政策——本質上是一套即時跑的個人化推薦系統,只是包了一層搜尋框的皮。

金流那邊更難。一筆訂單可能同時牽扯到房客刷卡的幣別、房東提現的幣別、平台抽成、當地稅務代繳、清潔費、押金。架構師真正要學的,是怎麼把「訂單」和「分帳」拆成兩件事來設計——這也是這篇我最想講清楚的一點。


商業規模與壓力

根據 Airbnb 2023 年報與公開技術演講:

  • 全球掛牌房源超過 770 萬間,分佈在 10 萬個城市(Airbnb 2023 10-K 年報)1
  • 2023 年全年訂房夜與體驗數超過 4.48 億晚,代表平均每秒約 14 筆預訂(同上年報)1
  • 支援超過 40 種結算幣別,信用卡收單橫跨多個地區的 PSP(payment service provider)(Airbnb Engineering Blog 多篇)2

壓力來自兩個完全不同的方向。搜尋這邊講求快,延遲要壓在 幾百毫秒內,可是每次搜尋又得對數千個候選房源跑一輪機器學習排名;金流那邊講求準,資料一筆都不能掉,事後還要能回溯審計(audit trail)。這兩種需求其實互相打架,硬塞進同一套系統,最後通常是兩邊都顧不好——這就是為什麼後面 Airbnb 把它們拆開。


架構演進簡史

階段年份(約)關鍵變化
Monolithic Rails + MySQL2008–2014整個 Airbnb.com 跑在一套 Rails monolith 上
SOA(Service Oriented Architecture)2014–2018拆成數百個服務,內部稱為 “Great Migration”(Airbnb Engineering Blog 公開系列)3
Search ML 導入 GBDT → Deep Learning2015–2019搜尋排名從手寫權重改用 Gradient Boosted Decision Tree,後改 Deep Learning(Airbnb KDD 2018 論文)4
Payment Ledger 獨立服務2015 以後把所有金流狀態變動抽成 event-sourced ledger(Airbnb Engineering Blog “Avoiding Double Payments”)5
Data Mesh 與 Dataportal2019 以後資料治理平台 Dataportal,讓搜尋與 ML 特徵共享

整理成一張圖,搜尋與金流這兩條主線的關係就清楚了:

風險檢查

用戶端

API Gateway

搜尋服務

(ML 排名)

訂房服務

Trust & Safety

(風控)

Payment Ledger

(狀態機 / 冪等)

交易資料庫

(強一致)

Airbnb 搜尋與金流:搜尋走 ML 排名,訂房寫入帶冪等的 Payment Ledger 再落交易資料庫,並串接 Trust & Safety 風控。


核心技術決策

決策為何替代方案
搜尋排名用 learning-to-rank規則太多,手寫權重無法維護純關鍵字比對(體驗差)
Payment Ledger 採 event sourcing金流要能回溯、對帳、合規稽核直接改餘額(無法追蹤歷史)
跨服務付款用冪等 key + 狀態機 + 三階段 RPC訂單成立與扣款必須一致,且要能安全重試 5兩階段提交(2PC,Airbnb 未採用,協調者單點且難擴展)
搜尋走專屬 ML 服務排名計算重,與交易型資料庫分流把 ML 放在主庫查詢(DB 會被打爆)
多幣別在 ledger 層處理避免每個服務自己轉匯、誤差累積每個服務各自轉(最後對不起來)

金流的關鍵設計: Airbnb Engineering Blog 那篇 “Avoiding Double Payments in a Distributed Payments System” 講得很清楚,他們是用冪等 key + 狀態機 + retry這組合來防重複扣款。思路其實跟 Stripe 的冪等性設計很像,只是搬到雙邊市場來用5

我自己沒做過 Airbnb 這種規模的跨國分帳,但做過一個小很多的版本——幫一個平台對帳,金額不大,邏輯卻一樣折磨人。最早團隊圖方便,付款一進來就直接改使用者餘額,加一筆、扣一筆。剛上線沒事,跑了三個月開始對不起來:有人重複按送出、有支付閘道 timeout 後又自己 retry、有筆退款被算了兩次。最痛的是事後想查「這個帳到底怎麼變成現在這樣」根本查不出來,因為餘額是直接被覆寫的,中間發生過什麼完全沒留紀錄。

後來才認真理解 event sourcing 在解什麼。把每一次金額變動都當成一筆「不可改的事件」記下來,餘額是把這些事件加總算出來的、不是直接存的——一旦這樣設計,重複扣款、退款重算、對帳這些問題突然就有地方下手了,因為每一塊錢的來龍去脈都查得到。Airbnb 那套 ledger 規模大得多、還得處理多幣別,但底層那個「狀態 = 事件的累積」骨架,跟我當時被逼著補的這課,是同一回事。所以後面講「為什麼 ledger 不能直接改餘額」,對我來說不是書上的原則,是真的賠過時間才換來的。


如果用 GCP 重新蓋

Airbnb 元件GCP 對應
搜尋排名 ML 模型訓練Vertex AI Training,特徵存 BigQuery + Feature Store
線上推論Vertex AI Prediction 或 GKE + TensorFlow Serving
候選房源索引Elasticsearch on GKEAgent Search(前身為 Vertex AI Search)
Payment LedgerCloud Spanner(跨 region 強一致 + 交易)
訂單資料Spanner 或 Cloud SQL(依跨 region 需求)
分析與對帳BigQuery + Dataflow 做 CDC 抽 ledger
信任與風控Vertex AI 訓練詐欺偵測模型 + reCAPTCHA Enterprise
PII 保護Cloud DLP 掃信用卡號、身分證;CMEK(客戶自管金鑰)加密
多區影像與房源照片Cloud Storage + Cloud CDN + Imagen API 做自動描述

搬到 PCA 考場上會怎麼考

這篇拆的兩條主線——金流要強一致、搜尋要跑 ML——剛好對上 PCA 兩類很愛考的題型。下面把考點寫成考場上能直接套的判斷,而不是另一張要你死背的對應表。

📝 考場提點:分帳、對帳這種題,看到「強一致 + 跨 region 交易」就往 Spanner 想

只要題目同時出現「金流/訂單/餘額不能算錯」加上「多個地區都要讀寫」,考的幾乎就是 OLTP 資料庫選型,答案多半是 Cloud Spanner——它給你跨 region 的強一致加交易,這正是 ledger 不能妥協的點。

陷阱在另一邊:題目後面常會接一句「業務團隊要看營收 dashboard/要跑分析」,然後選項裡偷塞「全部都放同一個資料庫」。別跳進去。交易型(OLTP)和分析型(OLAP)要分開——交易走 Spanner,分析抽到 BigQuery,中間用 Dataflow 做 CDC 把資料搬過去。PCA 反覆在考的就是這條「不要把 OLTP 跟 OLAP 塞同一個庫」。看到「強一致/交易」是一組關鍵字,「報表/分析/歷史趨勢」是另一組,兩組同時出現,答案幾乎一定是「拆兩個服務」而不是「找一個全包的」。

📝 考場提點:ML 題預設選 managed Vertex AI;PII 題記住「能用但看不到」這句

給你一個搜尋排名、推薦、詐欺偵測的場景,要你在「自建 TensorFlow on GKE」跟 managed Vertex AI 之間選——沒有明說非要極度客製,就選 Vertex AI。再細一點:要訓練模型是 Vertex AI Training、要線上推論是 Vertex AI Prediction、要管理跨模型共享的特徵是 Feature Store,題目問的是哪個階段,就答哪個,別整包混在一起。會選 GKE 自建的,通常是題目硬性要求自管框架版本或有特殊硬體需求,那是少數。

PII(personally identifiable information)這類最常見的問法是:「怎麼讓分析團隊能用資料、但看不到信用卡號或身分證?」聽到「能用但看不到」就直接想 Cloud DLP 的 de-identification(去識別化)配 BigQuery column-level security(欄位級權限)。陷阱選項通常是「複製一份遮罩過的資料給他們」——能動,但會多一份要同步、要再保護的副本,在考場上算不到位。


常見誤解

  • 「搜尋排名就是 Elasticsearch 啊。」 不全是。Elasticsearch 只做「候選召回(candidate retrieval)」——先把可能符合的房源撈出來;真正決定誰排前面的,是後面接的那層 ML ranking。Airbnb KDD 2018 論文把這兩層分得很清楚4,考試也愛在這裡設坑。
  • 「多幣別不就是下單時呼叫一下匯率 API?」 真要這樣做,你以後對帳會哭。正確做法是下單當下就把「當時匯率 + 原始幣別 + 結算幣別」三個欄位一起寫進 ledger,鎖死在那一刻。不然事後匯率一動,帳就再也對不回去了——這也是前面那段對帳故事的另一個版本。
  • 「event sourcing 就是把 log 寫進 Kafka 吧?」 Kafka 只是一種實作載體,不是 event sourcing 本身。它真正的意思是「狀態 = 所有事件摺疊(fold)出來的結果」這個設計哲學——你存的是一連串事件、不是當下的快照,餘額是算出來的。載體換成別的也成立。

來源與延伸閱讀


下一篇(本系列最終篇):經典架構拆解 · 06 — Discord 百萬人頻道與 NoSQL 選型,看另一種極端的即時通訊架構怎麼從 Cassandra 換到 ScyllaDB。

需要對照官方 case study?到 PCA 案例資料庫

🎯 換你練習

想動手設計類似系統?到 架構師設計工作坊 用這套思考步驟走一遍。

Footnotes

  1. Airbnb 2023 Annual Report (10-K) — 官方財報中揭露的房源數、訂房晚數、營收規模。 2

  2. Airbnb Engineering Blog — 官方工程部落格,搜尋、金流、ML 多篇公開文章來源。

  3. Our Journey Towards a Production-Ready Service-Oriented Architecture — Airbnb Engineering — Monolith 拆 SOA「Great Migration」的工程記事。

  4. Real-time Personalization using Embeddings for Search Ranking at Airbnb — KDD 2018 論文 — 搜尋 embedding 與排名架構的正式論文。 2

  5. Avoiding Double Payments in a Distributed Payments System — Airbnb Engineering — 官方介紹冪等性與狀態機如何避免重複扣款。 2 3

經典架構拆解 — 5/6 完成 查看系列全覽 →

留言討論

徽章解鎖!