結論先講

連線池大小是最容易被忽略的效能瓶頸。 pool=5 在 10 人同時用的時候完全夠用,但在 500 人同時用的時候會成為天花板。更容易踩到的坑是水平擴展——你加了 4 台 server 但沒擴 DB 連線池,等於 4 台 server 搶同一個 pool,效能反而變差。


連線池大小:pool=5 vs 20 vs 50

Pool Max低壓 RPS高壓 RPS對比
51,7361,736基準
201,8502,450+41%
501,8702,945+70%

低壓下都一樣

10-50 人同時用的時候,pool=5 和 pool=50 的效能幾乎一樣。因為 5 個連線就夠用了——request 來了拿一個連線、做完查詢還回去,下一個 request 再拿。

高壓下差距很大

500 人同時用的時候,pool=5 代表最多 5 個查詢同時跑,其他 495 個 request 在排隊等連線。pool=50 可以同時跑 50 個查詢。

為什麼不直接設 pool=1000

因為 DB 端有 max_connections 限制。PostgreSQL 預設 100、MySQL 預設 151。

每個連線在 DB 端都佔記憶體(PG 每個連線約 5-10 MB)。1000 個連線 = 5-10 GB RAM 給 DB,還沒算資料快取。

水平擴展的數學

1 台 server × pool=20 = 20 個 DB 連線  ✅
2 台 server × pool=20 = 40 個 DB 連線  ✅
4 台 server × pool=20 = 80 個 DB 連線  ⚠️ 接近 max_connections=100
8 台 server × pool=20 = 160 個 DB 連線 ❌ 超過 max_connections

這就是為什麼 Infra 層的壓測顯示「4 台不會比 2 台更好」。 瓶頸從 application 轉移到了 DB 連線池。

解法:

  1. 調大 DB 的 max_connections(需要給 DB 更多 RAM)
  2. 用 PgBouncer 做連線池代理(application 連 PgBouncer,PgBouncer 連 DB)
  3. 減少每台 server 的 pool 大小(trade-off:單台效能下降)

MongoDB:快在哪、慢在哪

純 CRUD:MongoDB 8.6 倍快

DBCRUD RPS
MongoDB1,695
PG (ORM)197
PG (Raw SQL)215

MongoDB 的 BSON 格式天生適合 JSON-like 的 CRUD——不需要 schema mapping、不需要 SQL parse、直接讀寫 document。

但 Transaction 不行

MongoDB 4.0+ 支援 multi-document transaction,但:

  • 效能比 PG/MySQL 差很多
  • 不支援跨 shard 的 transaction(sharded cluster)
  • 語法不如 SQL 直覺

MongoDB 適合什麼

場景MongoDBPG
用戶 profile(一個 document)最佳可以(JSONB)
商品目錄(結構不固定)最佳可以(JSONB)
訂單系統(需要 Transaction)不推薦最佳
報表查詢(JOIN + GROUP BY)不推薦最佳
日誌收集(大量寫入)MySQL 更好

PG JSONB vs MongoDB 的有趣數字

在 Storage 層的測試中,PG JSONB 和 MongoDB 存同一筆 JSON 的速度只差 4%。也就是說,如果你只是想「在資料庫裡存 JSON」,PG 的 JSONB 就夠了,不需要額外維護一個 MongoDB。

MongoDB 真正快的是「純 document 操作、不需要 schema、不需要 Transaction」的場景。


連線池和後端框架的關係

回顧 Python 雙雄 的數據:Django pool=10 vs FastAPI pool=50。Django 在高 VU 時排最後——不全是 Django 的問題,pool=10 是很大的一個因素。

框架Pool Max備註
Express-TS/JS20Sequelize 預設
NestJS20TypeORM 預設
Django10CONN_MAX_AGE 機制不同
FastAPI50SQLAlchemy 可配
Go (GORM)20SetMaxOpenConns
Spring Boot50Tomcat pool
.NET Core20EF Core 預設
Laravel-PHP-FPM 每 request 新連線

Spring Boot 的 pool=50 是它在混合場景表現好的原因之一。Django 的 pool=10 是它在高 VU 表現差的原因之一。

框架選型時,不要只看框架本身的效能,也要看它的預設 DB 配置。


DB 層小結

三篇 DB 的核心 takeaway:

  1. PG vs MySQL 看場景:JSON 查詢選 PG(3.2 倍),大量寫入選 MySQL(2.5 倍)(第 36 篇
  2. Bulk INSERT 比換 DB 效果大:26 倍提升,改一行程式碼(第 37 篇
  3. 連線池要跟著擴展一起算:pool=5 低壓夠用,高壓差 70%(本篇)
  4. MongoDB 快但有侷限:純 CRUD 8.6 倍,Transaction 不如 PG
  5. ORM 沒你想的慢:和 Raw SQL 差不到 10%

接下來進入 Storage 層——Redis、Elasticsearch、Kafka 這些「DB 以外的儲存」在壓測中表現如何。


下一篇

Redis 快 2.4 倍、ES 快 2.6 倍:每種儲存的甜蜜點 — Redis 做 KV 每秒 5,346 個請求、Elasticsearch 做全文搜尋比 PG LIKE 快 2.6 倍、Kafka vs RabbitMQ vs Redis Pub/Sub。不是「裝越多越好」,是「知道什麼時候該加什麼」。


本系列文章

完整 68 篇目錄見 系列首頁

← 上一篇:Bulk Insert 快 26 倍:DB 寫入的正確姿勢 → 下一篇:Redis 快 2.4 倍、ES 快 2.6 倍:每種儲存的甜蜜點