sql >> データベース >  >> NoSQL >> MongoDB

フォロワー-mongodbデータベース設計

    これは境界線であるという他の回答の一般的な概念に同意します 関係の問題。

    MongoDBデータモデルの鍵は書き込みの重さですが、これはこのユースケースでは扱いにくい場合があります。これは主に、ユーザーをアイテムに直接リンクする場合に必要となる簿記のためです(グループへの変更の後にロットが続きます)。のユーザーには膨大な数の書き込みが発生するため、これを行うにはワーカーが必要です。

    ここでは、読み取りが多いモデルが適用できないのか、それとも時期尚早の最適化を行っているのかを調べてみましょう。

    リードヘビーアプローチ

    主な懸念事項は、次のユースケースです。

    実際のパフォーマンスの問題は、特定のアイテムについてユーザーがフォローしているすべてのグループを取得したい場合です[...]その場合、ユーザーがフォローしているすべてのグループを検索し、そこからすべてを検索する必要があるためです。 group_id $inのitem_groups とアイテムID。

    これを分析しましょう:

    • ユーザーがフォローしているすべてのグループを取得する

      これは単純なクエリです:db.followers.find({userId : userId})userIdのインデックスが必要になります これにより、この操作の実行時間はO(log n)になり、nが大きい場合でも非常に高速になります。

    • そこから、group_id $inを持つすべてのitem_groupsを検索します とアイテムID

      さて、これは難しい部分です。アイテムが多数のグループの一部になる可能性は低いと少しの間仮定しましょう。次に、複合インデックス{ itemId, groupId } 最初の基準で候補セットを劇的に減らすことができるため、最も効果的です-アイテムが800グループのみで共有され、ユーザーが220グループをフォローしている場合、mongodbはこれらの共通部分を見つけるだけで済みます。これは、両方が比較的簡単であるためです。セットは小さいです。

    ただし、これよりも深く掘り下げる必要があります:

    データの構造はおそらく 複雑ネットワークのそれ 。複雑なネットワークにはさまざまな種類がありますが、フォロワーグラフがほぼスケールフリーであると想定するのは理にかなっています。これも、ほとんど最悪のケースです。スケールフリーネットワークでは、非常に少数のノード(有名人、スーパーボウル、ウィキペディア)が多くの「注意」を引き付けます(つまり、多くの接続があります)が、はるかに多くのノードが同じ量の注意を引くのに問題があります組み合わせ

    小さなノードは心配する必要はありません 、データベースへのラウンドトリップを含む上記のクエリは、2ミリ秒の範囲です。 数千万の接続と5GBを超えるデータを含むデータセット上の開発マシンで。データセットは巨大ではありませんが、どのテクノロジーを選択しても、インデックスはどのような場合でもRAMに存在する必要があるため(ネットワークのデータの局所性と分離性は一般に不十分です)、設定された交差サイズはRAMにバインドされます。定義上小さい。言い換えれば、この体制はハードウェアのボトルネックによって支配されています。

    スーパーノードはどうですか でも?

    それは当て推量であり、ネットワークモデルに非常に興味があるので、データモデルに基づいて劇的に簡略化されたネットワークツールを自由に実装して、いくつかの測定を行いました。 (申し訳ありませんが、C#ですが、適切に構造化されたネットワークを生成することは、私が最も流暢な言語では十分に困難です...)

    スーパーノードにクエリを実行すると、7msトップの範囲の結果が得られます。 (これは、1.3GBデータベースの1200万エントリにあり、最大のグループには133,000アイテムが含まれています および143のグループをフォローしているユーザー。)

    仮定 このコードでは、ユーザーが従うグループの数はそれほど多くありませんが、ここではそれが妥当なようです。そうでない場合は、書き込みが多いアプローチを選択します。

    コードを自由に試してみてください。残念ながら、数GBを超えるデータでこれを試してみたい場合は、少し最適化する必要があります。これは、単に最適化されておらず、あちこちで非常に非効率的な計算が行われるためです(特に、ベータ加重ランダムシャッフルは改善される可能性があります)。 。

    言い換えると、読み取りが多いアプローチのパフォーマンスについては心配しません 多くの場合、問題はユーザー数が増えるほどではありませんが、ユーザーが予期しない方法でシステムを使用していることです。

    書き込みヘビーアプローチ

    別のアプローチは、おそらくリンクの順序を逆にすることです:

    UserItemLinker
    {
     userId,
     itemId,
     groupIds[]  // for faster retrieval of the linker. It's unlikely that this grows large
    }
    

    これはおそらく最もスケーラブルなデータモデルですが、シャーディングが重要な要件である大量のデータについて話しているのでない限り、私はそれを選びません。ここでの主な違いは、シャードキーの一部としてuserIdを使用することで、データを効率的にコンパートメント化できることです。これは、クエリを並列化し、効率的にシャーディングし、マルチデータセンターシナリオでのデータの局所性を向上させるのに役立ちます。

    これは、より精巧なバージョンのテストベッドでテストできますが、まだ時間がわかりませんでした。率直に言って、ほとんどのアプリケーションではやり過ぎだと思います。



    1. デフォルトでMongoDBシェルできれいに印刷

    2. センチネルでRedisをアップグレードするためのベストプラクティス?

    3. ClusterControlのパフォーマンスとヘルスモニタリング

    4. Meteorにはどのようなセキュリティメカニズムがありますか?