MatchRPG Server 生產就緒稽核:1M CCU 評分 82/100 與 JIT 盲點測試全流程¶
文檔資訊
- 分類: architecture
- 難度: advanced
- 預估閱讀時間: 25 分鐘
- 標籤:
production-readiness,1M-CCU,Go,PostgreSQL,Redis,concurrency,JIT-testing,architecture-audit,P0-findings,graceful-shutdown
摘要¶
針對 MatchRPG Server(Go + Twirp + pgxpool + Redis)進行完整生產就緒稽核,派遣 4 支並行 Agent 分別審查啟動路徑、資料庫寫入路徑、並發安全和架構合規,並額外執行 JIT 盲點測試。最終評分 82/100(Game Server 75/100、Publisher 80/100),發現 6 個 P0 阻斷問題和 12 個 P1 高優先問題。
關鍵學習¶
-
1M CCU 的 DB 寫入估算:20K writes/s × 10 queries/op = 200K queries/s,超過單節點 PostgreSQL 上限 7-10x,需分片或讀寫分離
-
CAS 樂觀鎖重試最多 3x,EndBattle + ConsumeItems 嵌套 CAS 可達 9x 查詢放大,Worst Case 600K queries/s
-
連接池預設值 DBMaxConns=30 嚴重不足,1M CCU 場景需要 100-150
-
Middleware 順序 P1 問題:Rate limiting 應在 JWT auth 之前執行,否則 S2S endpoint 只受 IP 級別限制
-
Fire-and-forget goroutine(Admin Audit、GDPR Export、Dungeon S3 Upload)是 P0 風險:無 WaitGroup 追蹤、無背壓、無 graceful shutdown
-
security_events 日期分區只到 2035 年,無滾動策略,P1 運維風險
-
JIT 盲點:StartBattle 沒有 DB 層唯一約束,同一用戶並發兩個 battle session 可導致重複獎勵
-
架構合規總分 9.6/10;P2 問題僅為 SQL string concatenation for whitelisted table/column names,無真實安全風險
-
Publisher 9 階段 graceful shutdown 優於 Game Server 的 3 階段,更細粒度
技術細節¶
Game Server (cmd/twirpserver)¶
- Redis optional fallback — 允許在 Redis 不可用時降級運作
- ConfigManager FATAL required — 配置載入失敗直接終止
- 3-stage shutdown: PreStop 5s → HTTP drain → infra cleanup
Publisher¶
- 9-stage shutdown — 比 Game Server 更細粒度的優雅關閉
- JWT keys loaded unconditionally
- Production-only IAP webhook verifier enforcement
DB 寫入路徑(每次操作的查詢數)¶
| 操作 | 查詢數 |
|---|---|
| ConsumeItems | 7q |
| EndBattle Victory | 16q |
| CompleteChapter | 12q |
| SellItem | 5q |
| CreateAccount | 4q |
並發問題(P0)¶
- GDPR export — 無 semaphore 上界,可同時啟動數千 goroutine
- Admin audit — fire-and-forget 無 WaitGroup 追蹤
- Dungeon S3 upload — pool 滿時 silent drop,不報錯
架構合規¶
10 個 module 全部通過合規掃描:無 Nakama import 洩漏、Wire DI 正確、Twirp adapter compile-time check 全部存在。
What Changed¶
對整個 MatchRPG Server 專案進行了完整的生產就緒稽核,派遣 4 支專門 Agent 並行執行:(1) 啟動路徑追蹤,(2) DB Schema 與寫入路徑量化,(3) 並發與失敗模式分析,(4) 架構合規全掃描,加上 1 支 JIT 盲點測試 Agent。識別出 6 個 P0 生產阻斷問題、12 個 P1 高優先問題,評定最終分數 82/100。
So What¶
這次稽核揭示了系統在 1M CCU 下會遇到的真實瓶頸:DB 寫入容量缺口(7-10x)、CAS 重試放大、無界 goroutine 三大核心問題。沒有這次稽核,這些問題只會在生產壓測時才暴露,代價極高。
Trade-offs¶
並行 Agent 策略可在同等時間內覆蓋更多審查維度,但每個 Agent 的上下文是獨立的,跨 Agent 的交叉驗證需要主 Agent 彙整。CAS 樂觀鎖 vs 悲觀鎖:CAS 在低衝突下效能優,但高並發熱點(同一用戶快速連點)會造成重試風暴。Redis optional fallback 設計允許降級運作,但 rate limiting 和 session caching 同時失效,生產環境應強制要求 Redis。
Try It Fast¶
快速驗證 CAS 重試放大問題 — 計算 1M CCU 下的 DB 查詢負載:
ccu = 1_000_000
writers = ccu * 0.1 # 10% 寫入活躍
writes_per_sec = writers / 5 # 每 5 秒一次寫入
avg_queries = 10 # 平均查詢數
print(f'Normal load: {writes_per_sec * avg_queries:,.0f} queries/sec')
print(f'With 3x CAS retry: {writes_per_sec * avg_queries * 3:,.0f} queries/sec')
print(f'PG capacity: ~20,000 queries/sec')
print(f'Gap: {writes_per_sec * avg_queries / 20000:.1f}x over capacity')
Recommendation¶
P0 — 立即修復¶
- Admin audit — 插入外層加
sync.WaitGroup+ shutdown hook - GDPR export — 加 semaphore 上界(建議 50)
- Dungeon S3 upload — pool 滿時改為 fail-fast 而非 silent drop
- StartBattle — 加 DB 唯一約束防止並發雙 session
- Publisher Redis — production 環境改為強制要求
- Game Server — production 環境強制要求
PUBLISHER_S2S_URL
P1 — 優先處理¶
- 連接池擴至
DBMaxConns=100 - 加
dungeon_player_stats(user_id, last_mismatch_at)複合索引 - 調整 Middleware 順序使 rate limiting 在 JWT auth 之前
長期¶
- 規劃讀寫分離(已有
readerPool架構) - 實作 in-process fallback rate limiter