Go × MongoDB 高トラフィック設計の落とし穴とベストプラクティス
MongoDBとGoを使ってアプリを開発する際、最初は 1つのDBに複数のコレクションを置くシンプルな構成で始めるケースが多いです。
ただし、将来的にスケールアウトを見据えて「コレクションごとに別のDBへ分離」する設計を検討する人もいるでしょう。
この記事では、その設計方針の注意点と、高トラフィック環境で気をつけるべき 接続・トランザクション・不整合リスク について整理します。
1. リクエストごとの Connect/Disconnect
はNG
まず最初の実装例では、HTTPリクエストを受けるたびに以下のようにDBへ接続していました。
c, err := mongo.Connect(ctx, options.Client().ApplyURI(common.Mongo1))
defer c.Disconnect(ctx)
一見正しそうですが、これは リクエストごとに新しい接続プールを作って壊す ため、非常に非効率です。
-
mongo.Connect()
は内部でTCPハンドシェイク・TLS認証を行う -
毎回数ms〜数十msのオーバーヘッドが発生
-
高トラフィック時は「接続の作成・破棄」だけでシステムが詰まる
正解は「アプリ起動時に一度だけコネクションプールを作り、全リクエストで共有する」ことです。
var client *mongo.Client
func InitMongo() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, _ = mongo.Connect(ctx, options.Client().ApplyURI(common.Mongo1))
}
func GetDB(name string) *mongo.Database {
return client.Database(name)
}
これなら、接続のオーバーヘッドはほぼゼロに抑えられます。
2. コレクションごとにDBを分けるとどうなる?
DBを「ユーザ」「セッション」などで分割すると、以下のような特徴があります。
メリット
-
データの分離が明確
-
権限管理しやすい
-
将来クラスタ単位でスケールアウトしやすい
デメリット(オーバーヘッド)
-
JOINできない(DBをまたぐ
$lookup
不可 → アプリ側で複数クエリ&結合) -
トランザクション不可(DBをまたぐ一貫性保証はできない)
-
バックアップや運用管理コスト増
性能面では「DBが増えること自体のコスト」は小さいですが、
アプリ側での結合や整合性管理がオーバーヘッドになるのが本質的な問題です。
3. トランザクションが使えないとどう不整合が起きるか?
MongoDBのマルチドキュメントトランザクションは 同じDB内のみでしか使えません。
DBを分けると、次のような不整合が現実的に発生します。
-
途中失敗で片方だけ反映
-
user
は成功、session
は失敗 → ユーザは存在するがセッションは無い状態
-
-
順序ズレ
-
セッションは更新されたが、ユーザ情報が古いまま
-
-
リトライで二重登録
-
再実行で
Insert
が重複
-
-
フェイルオーバー中の不一致
-
Primary切り替え時に一方だけコミットされる
-
-
アプリクラッシュ
-
処理途中で落ちて片方だけ成功
-
4. 実運用での「予期せぬエラー」例
-
MongoDBクラスタの Primaryフェイルオーバー
-
一時的な ネットワーク断
-
ストレージ問題(ディスクFullなど)
-
競合 (WriteConflict)
どれも本番環境で普通に起こり得ます。
5. 対策:完全な整合性を求めない設計
もし「必ず同時にコミットされなければならない」なら、1つのDBにまとめるのが必須です。
一方で「多少ズレても後から修復できる」前提にすると、DB分割も選択肢になります。
その場合の対策は:
-
冪等な設計
-
Insert
ではなくUpsert
を使う -
ユニークキー制約で二重登録防止
-
-
イベント駆動 (アウトボックスパターン)
-
「ユーザ作成イベント」をログに残し、非同期でセッション作成
-
-
不整合検知バッチ
-
定期的に「ユーザはあるのにセッションがない」ケースを検出・修復
-
まとめ
-
高トラフィックを考えるなら、コネクションは必ずアプリ全体でキャッシュする
-
コレクションごとにDBを分けると、トランザクション不可 & JOIN不可が最大のデメリット
-
運用中は フェイルオーバー・クラッシュ・ネットワーク断 などで「片方だけ成功」が起こり得る
-
多少の不整合を許容し、後で修復できる設計 にするのが現実的
💡 結論:
MongoDBを複数DBで運用するなら、
「整合性はアプリ側で工夫して担保する」
「多少のズレは後で修復する」
という思想が必要です
登録日:
更新日: