Go Server Race Condition Patterns¶
概念概覽
Package-level 變數 Data Race¶
核心知識¶
Package-level 變數 Data Race¶
lastCleanupTime 等 package-level time.Time 若在多個 goroutine 中存取,即使只有一個 writer 也會觸發 data race。修復方式:
- 改用 atomic.Value 包裝 time.Time
- 或用 sync.Mutex 包住所有讀寫操作
- 可用 go test -race 直接驗證
sync.Once 的 Hot-Reload 盲點¶
sync.Once 建立的 gamedata config index 只會初始化一次,hot-reload 後舊 index 不會失效。需要 hot-reload 支援時,應改用:
- 帶版本號的 sync.RWMutex 方案(讀多寫少場景)
- config observer pattern,在配置變更時主動重建 index
偵測策略¶
靜態 JIT 分析(非 runtime)可在 unit/e2e/smoke test 全過的情況下仍發現這類問題,建議納入 CI pipeline。
經驗教訓¶
-
unit/e2e/smoke test 全通過並不代表沒有 race condition,靜態分析是必要補充
-
sync.Once 適合真正的一次性初始化,不適合需要 invalidation 的 cache 場景
-
go test -race 是驗證 data race 最直接的工具,應加入 CI
常見陷阱¶
-
package-level time.Time 看似只有一個 goroutine 寫入,但讀取方也需要同步保護
-
sync.Once 用於可變 config 時會造成 stale data,熱更新場景必須換方案
最佳實踐¶
-
package-level 可變狀態一律用 atomic 或 mutex 保護
-
sync.Once 只用於真正不可變的初始化(如 singleton DB connection)
-
CI 必跑 go test -race
相關概念¶
相關視角¶
以下頁面與本概念共享主題,但從不同角度切入。保留獨立視角同時提供交叉參考:
- Config Sync Advisory Lock Pattern — 共享:
concurrency/ 獨特:advisory-lock,config-sync
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-03-17 | 10eef6a0-3a55-4d63-981c-6bc79aff1880 | 識別出 Go 遊戲伺服器中兩類典型 race condition:package-level time.Time 無鎖存取,以及 sync.Once index 在 hot-reload 後不刷新 |