從 ChatGPT 的 PostgreSQL 最佳實踐學到的事:規模靠的不是神話,是紀律

從 ChatGPT 的 PostgreSQL 最佳實踐學到的事:規模靠的不是神話,是紀律

最近看到 OpenAI 分享 ChatGPT 如何用 PostgreSQL 服務到「8 億用戶」等級的實務做法。

這種文章常被當成巨頭逸聞:看完覺得很猛,但跟自己無關。

我反而覺得,真正值得抄的不是規模,而是背後的工程紀律:當你把資料庫當成產品核心的一部分來經營,你會怎麼設計它的邊界、觀測、與失敗模式。

下面把九個重點拆成三層來看:

  1. 這 9 點在 ChatGPT 裡實際長什麼樣
  2. 為什麼它們特別適合「AI 時代」的 DB 使用方式
  3. 如果你是 PM + Python side project / 小型 SaaS,怎麼做縮小版

## 這 9 點在 ChatGPT 裡實際長什麼樣

### 1)單一 writer + 大量 read replicas

ChatGPT 的核心是 Azure 上單一 PostgreSQL primary,外面掛了大約 50 個跨區域 read replica。

系統把絕大多數查詢導向 replicas,只把跟寫入同一個 transaction 綁定的查詢留在 primary。這讓 primary 更像「一致性與交易的控制塔」,而讀取吞吐量交給 replica 水平擴展。

中小團隊可落地版

  • 先從「一主一從」開始也行,先把路徑切出來。
  • 把「讀歷史、讀設定、讀報表」這些查詢抽象成明確的 read-only repository/service,之後才有機會無痛切到 replica。

### 2)嚴格監控高成本查詢(特別針對 ORM)

他們特別點名 ORM 會生成又長又慢的 SQL,所以在 DB 層與 ORM 層都有慢查詢監控與封鎖機制;甚至能直接針對特定 query digest 做 block。

這背後的核心心態很明確:讓「看似方便」的查詢成本變得可見、可控、可禁止。

中小團隊可落地版

  • 在 Python / FastAPI 層把 ORM 產生的 SQL 全部 log 下來(帶 request id、route、user、feature tag)。
  • 做一張慢查詢週報:Top N 最慢、Top N 最常出現、Top N 最耗總時間。
  • 必要時針對某些 pattern 做限流或直接拒絕。

### 3)單 writer 也要 HA:把只讀關鍵路徑搬去 replicas

即便只有一個寫入節點,也會用複本做熱備援。

更重要的是:把「只讀關鍵路徑」搬到 replicas。這樣 primary 出問題時,讀流量仍然有機會繼續被服務,產品不會立刻全黑。

中小團隊可落地版

  • 不要只做備援而不演練。定期做一次「如果 primary 掛了,我們還能提供哪些功能」的桌上推演。
  • 先把登入、權限、設定、讀歷史這些路徑變成可以在 read-only 模式下提供的能力。

### 4)Workload 分級與隔離:避免 noisy neighbor

高優先級(例如關鍵查設定、核心 metadata)的查詢,與次要工作(分析、報表、後台批次)分散到不同節點。

這避免「一個 noisy neighbor 把整個叢集拖垮」的經典事故。

中小團隊可落地版

  • 先從最簡單的隔離做起:報表、批次任務走獨立資料庫或至少獨立 read replica。
  • 在應用層做 queue,把非即時工作改成背景處理。

### 5)PgBouncer 代理層:用 transaction/statement pooling 壓住連線數

在應用與 Postgres 之間插 PgBouncer,用 statement/transaction pooling 大幅減少實際 DB 連線數。

分享裡提到連線建立時間從約 50ms 壓到 5ms,跨區延遲場景特別有感。

中小團隊可落地版

  • PgBouncer 幾乎可以視為標配:Docker compose 直接加一層。
  • 先用 transaction pooling 把連線暴增問題壓住,再來談其他優化。

### 6)Cache miss 的「單一讀取者」:dogpile prevention

遇到多層快取都 miss 時,不讓所有請求一起回源打爆 DB。

只允許一個請求去資料庫補快取,其他請求等待結果(典型 request coalescing / singleflight)。

中小團隊可落地版

  • 在應用層加一個 per-key lock(Redis lock 或單機 mutex 都行),把同一個 key 的回源合併。
  • 對熱門 key 設定更短 TTL + 背景刷新,避免同一時間一起過期。

### 7)WAL 中介副本(研發中):降低 primary 的複寫扇出

他們提到一個演進方向:未來希望不是所有 replicas 都直接從 primary 拉 WAL。

先複製到中介 replica,再由中介分發給多個 read replicas,降低 primary 的 WAL 傳送負載與複製扇出壓力。

中小團隊可落地版

  • 這招多半用不到,但思路很值得記:primary 要做的事越少越好。
  • 你可以先在架構上避免把所有附加功能都掛在 primary 上(例如所有查詢都走 primary、所有報表都走 primary)。

### 8)多層級 Rate limit:避免 retry storm,必要時精準 shed load

他們在 application、PgBouncer、proxy,甚至 query 層都做 rate limiting。

同時避免太頻繁重試造成 retry storm;必要時能針對昂貴 query 的 digest 做精準的 shed load。

中小團隊可落地版

  • 在 gateway / API 層做 per-user、per-key、per-route 的 rate limit。
  • 把重試策略寫死:指數退避、上限次數、加 jitter。
  • 對「回源 DB」的路徑設更嚴的限流。

### 9)Schema 變更極度保守:DDL 5 秒 timeout、索引一律 concurrent

他們的 schema 變更政策非常克制:

  • 只允許輕量 DDL
  • 禁止會引發 full table rewrite 的變更
  • DDL 設 5 秒 timeout
  • 索引一律用 concurrent 建/刪
  • 新功能若需要更可水平擴展的寫入,會把新表丟去可 sharding 的系統(例如 Cosmos DB),而不是硬塞回主 Postgres
  • 需要 backfill 時會嚴格限流,寧可跑一週也不要把線上打爆

中小團隊可落地版

  • 設一份 migration 操作守則:線上不 drop column、不改型別、不做可能 rewrite 全表的操作。
  • 索引一律 concurrently,backfill 一律小 batch + sleep。
  • 把 migration 視為一次「線上操作」,需要 SLO、需要回滾方案。

## 為什麼這些特別適合「AI 時代」的 DB 使用方式

### AI 產品常見的型態:超 read-heavy + 少量關鍵 write

AI 產品大量讀:讀對話、讀設定、讀 usage metadata。

寫入存在,但往往是少量且關鍵(帳務、狀態、使用量、權限)。

這讓「大量 replicas 承接讀、primary 專注寫與一致性」變成非常符合直覺的配置。

### 流量尖峰更不可預測:保護 critical path 才是重點

模型側很容易突然造成尖峰:新模型上線、某國家湧入、某種 prompt pattern 爆炸式擴散。

多層 rate limit + workload isolation 的價值在於:

  • 讓核心路徑(帳務、權限、核心存取)不會被實驗性功能拖下水
  • 在壓力下仍能提供可用但降級的服務

### 演進式路線:RDB 當核心,把新 workloads 外移到可水平擴展系統

以 RDB 作為核心,再把寫得很兇或需要水平擴展的新 workloads 外移到 sharded/NoSQL(例如 Cosmos DB),對產品團隊而言是一條演進式路線。

你不需要一次性重寫所有東西去換 DB,而是逐步把不適合的負載搬出去。


## 如果你是 PM + Python side project / 小型 SaaS:縮小版怎麼做

我會照同樣精神做一個「不奢華但耐用」的配置:

  1. 早點把讀寫分離的路徑切出來:就算一開始沒有 replica,也先把 code 結構準備好。
  2. 把 ORM 成本做成可觀測性:SQL logging + tag + 慢查詢報表。
  3. 把 PgBouncer 當成標配:先解決連線暴增,再談其他。
  4. 對 burst 先從 API 層擋掉:per-user / per-key / per-route rate limit。
  5. 把 migration 當線上操作來規範:concurrent index、DDL timeout、backfill 限流。

你不需要 8 億用戶才開始做這些。

你需要的是在你還有餘裕的時候,先把「會在未來變成事故的地方」變成一份清單,並且逐步把它們系統化。


#PostgreSQL #資料庫 #SRE #架構設計 #效能優化 #ChatGPT