回到部落格
2026年3月19日4 分鐘閱讀

系統設計04:Yelp / 大眾點評(LBS 附近搜尋系統)

從空間索引、流量不對稱到最終一致性,拆解 LBS 附近搜尋系統如何在海量商家資料中維持毫秒級查詢。

《從 Web 到 AI-Native:一個新鮮人的系統設計五維度推演筆記》 系列學習筆記系統設計

前言

你是否想過,當你打開 Yelp 或 Google 地圖,系統是如何在不到一秒內,從全台甚至全球數百萬家餐廳中,精準篩選出「離你最近的 10 家火鍋店」?

這類系統的核心挑戰在於空間索引(Spatial Indexing)。

這篇文章透過五維度分析法,拆解 LBS(Location-Based Service,適地性服務)系統背後的底層架構與技術取捨。

這篇你可以帶走什麼

  • LBS 系統在資料量與流量上的真實壓力點
  • 為什麼傳統 SQL 與複合索引不適合做高效附近搜尋
  • QuadTree / Geohash 如何把二維搜尋降維成可擴展結構
  • 何時該放棄強一致性,改採最終一致性與定期重建

維度一、可直接觀察的事實:系統規模與流量特徵

先從客觀量級出發。

假設系統有:

  • 5 億日活躍用戶(DAU)
  • 2 億家商家

若每筆商家資料(經緯度、地址、簡短描述等)約 10KB,總資料量約:

  • 2 億 x 10KB = 約 2TB

2TB 對現代儲存體系不是天文數字,真正困難在查詢模型。

再看流量特徵,會出現極端不對稱:

  • 讀取(Search)極高:使用者不斷拖曳地圖、搜尋附近店家,尖峰搜尋 QPS 可達 100,000
  • 寫入(Update)極低:商家搬家、更新資訊頻率很低,尖峰寫入 QPS 甚至不到 300

這代表你要優先優化讀取路徑,而不是寫入路徑。

二維空間搜尋困境:

  • 如果用傳統 SQL 語法(例如計算兩點距離 X² + Y² < 半徑),資料庫必須「全表掃描(Full Table Scan)」來進行浮點數運算,效能極差。
  • 即使建立傳統的「複合索引(Composite Index)」,也無法同時支援經度與緯度的「雙向範圍查詢」。

重點:LBS 的瓶頸不在資料量本身,而在二維空間查詢模型與極端讀多寫少的流量型態。

維度二、條件檢查:完美解法與它的邊界

一般情況下的最佳解

業界標準做法是降維打擊:使用 QuadTree 或 Geohash。

以 QuadTree 為例,做法是把地圖持續切成四個象限,直到每個網格內商家數低於 100 家。

為了控制記憶體,可在 QuadTree 節點中只放精簡資訊:

  • 店家 ID
  • 經緯度
  • 50 字短描述

在這種精簡策略下,2 億商家的索引樹約 10GB,可放入單台伺服器 RAM,查詢延遲可壓到毫秒級。

邊界條件(什麼時候失效)

當寫入變得頻繁且要求即時時,這套架構會變痛苦:

  • 因為 QuadTree 存在記憶體中,如果某個網格內的店家突然超過 100 家,該節點必須「分裂」成 4 個子節點,這牽涉到複雜的樹狀結構重組與鎖(Lock)的併發問題。

也就是說,QuadTree 很適合「讀多寫少」,不適合「高頻即時寫入」。

重點:QuadTree 的強項是快速查詢,不是高頻更新。

維度三、反證檢查:跳脫「強一致性」的直覺慣性

直覺上,我們常認為店家地址一改,地圖就要立刻更新。

但反直覺地看,這個需求在多數 LBS 場景不一定成立:

  • 店家搬家資訊晚 1 小時甚至晚 1 天顯示,對一般使用者體驗通常影響有限

因此可改採最終一致性(Eventual Consistency):

  • 把線上 QuadTree 視為唯讀(Read-only)
  • 透過排程(Cron Job)每小時或每天重建一次整棵索引樹
  • 在新樹建好後平滑替換舊樹

若整棵樹約 10GB,重建通常只需幾分鐘,卻能避開複雜即時更新與死鎖(Deadlock)風險。

維度四、不確定性與假設分析:假設與地理隔離

要先分清楚觀察事實與經驗推論:

  • 觀察事實:全域 QuadTree 約 10GB
  • 經驗推論:大多使用者搜尋是同城或同區域,跨洲附近搜尋很少見

核心假設是:區域流量可以有效隔離。

因此你不需要每個機房都載入整顆全球樹,而是可按區域部署:

  • 美東 / 美西
  • 東京 / 台灣

好處是:

  • 降低單區域負載
  • 縮小 Blast Radius(爆炸半徑,指系統故障時的影響範圍)

維度五、最終結論與行動建議

系統藍圖可以分三層:

  • 底層資料庫(RDBMS 或 NoSQL):存放約 2TB 商家完整資訊,負責低頻寫入與明細讀取
  • 應用層建構一台(或一組)搭載 QuadTree 的記憶體伺服器,專門處理 100k QPS 的附近地點搜尋。
  • 設計一個背景排程任務,定期(如每小時)重構 QuadTree 並發布到線上服務。

破關路線圖(信心度 95%)

  • 先把附近搜尋主路徑切到空間索引(QuadTree / Geohash),避免 SQL 全掃
  • 索引節點只保留必要欄位,優先確保 RAM 可承載
  • 將線上索引改為唯讀,改用排程重建與平滑替換
  • 依地理區域拆分部署,降低跨區延遲與故障擴散

引入空間索引與最終一致性,是 LBS 系統在面試與業界都非常穩健的基本盤。

脆弱點提示

若你把這套架構直接拿去做外送員即時定位追蹤(如 Uber Eats / foodpanda),它會很快崩潰。

原因是那類場景屬於:

  • 寫入頻率極高(座標每秒變動)
  • 對位置一致性要求更高

此時「定期重建 QuadTree」不再適用,通常要改成即時資料流架構,例如 Redis GEO + 串流處理。


一句話總結

LBS 附近搜尋的勝負手在空間索引與一致性策略:用 QuadTree 扛查詢、用最終一致性降複雜度,再用區域化部署控制風險半徑。