複数のPostgreSQLサーバーに基づくDjangoプロジェクトがあります。
Instagram で使用されているのと同じシャーディング ロジックを使用して、これらのデータベース サーバー間でユーザーをシャーディングする必要があります。
ユーザー ID => 論理シャード ID => 物理シャード ID => データベース サーバー => スキーマ => ユーザー テーブル
- 論理シャード ID は、ユーザー ID (ユーザー ID に埋め込まれた 13 ビット) から直接計算されます。
- 論理シャード ID から物理シャード ID へのマッピングはハードコードされています (一部の構成ファイルまたは静的テーブルで)。
- 物理シャード ID からデータベース サーバーへのマッピングもハード コーディングされています。この時点で、 Instagram はPgbouncerを使用して、プールされたデータベース接続を適切なデータベース サーバーに取得します。
- 各論理シャードは独自のPostgreSQL スキーマに存在します(PostgreSQL に慣れていない方のために説明すると、これはテーブル スキーマではなく、 MySQL の「データベース」に似た名前空間のようなものです)。スキーマは単に「shardNNNN」のような名前が付けられます。ここで、NNNN は論理シャード ID です。
- 最後に、適切なスキーマのユーザー テーブルがクエリされます。
Django でこれをできるだけ簡単に実現するにはどうすればよいですか?
理想的には、次のような Django コードを書きたいと思っています。
インスタンスのフェッチ
# this gets the user object on the appropriate server, in the appropriate schema:
user = User.objects.get(pk = user_id)
関連オブジェクトの取得
# this gets the user's posted articles, located in the same logical shard:
articles = user.articles
インスタンスの作成
# this selects a random logical shard and creates the user there:
user = User.create(name = "Arthur", title = "King")
# or:
user = User(name = "Arthur", title = "King")
user.save()
ユーザーを名前で検索する
# fetches all relevant users (kings) from all relevant logical shards
# - either by querying *all* database servers (not good)
# - or by querying a "name_to_user" table then querying just the
# relevant database servers.
users = User.objects.filter(title = "King")
さらに複雑なことに、ストリーミング レプリケーションを使用して、すべてのデータベース サーバーのデータを複数のスレーブ サーバーに複製します。マスターは書き込みに使用し、スレーブは読み取りに使用する必要があります。
Django は自動データベース ルーティングのサポートを提供しますが、これはおそらく上記のほとんどに十分ですがUser.objects.get(pk = user_id)
、ルーターがクエリ パラメータにアクセスできないため、ユーザー ID が何であるかがわからないため、私は行き詰まっています。コードは User モデルを読み取ろうとしています。
シャーディングには制限があり、実際には非常に複雑になるため、シャーディングはおそらく最後の最適化手段としてのみ使用する必要があることを十分に認識しています。ほとんどの人はシャーディングを必要としません。最適化されたマスター/スレーブ アーキテクチャは、非常に長い道のりです。しかし、シャーディングが必要だとしましょう。
要するに、Django でできるだけ簡単にデータを分割するにはどうすればよいでしょうか?
ご親切にありがとうございました。
ノート
非常によく似た既存の質問がありますが、私見では一般的すぎて正確な例がありません。私が興味を持っている特定のシャーディング手法 (Instagram のやり方) に絞り込みたかったのです。