3

私は MongoDB に比較的慣れていませんが、レガシー サービスの前にある種のキャッシュとして使用することを検討しています。この場合、いくつかの問題に遭遇しました。

まず、いくつかの説明。

このキャッシング サービスは、レガシー サービスとクライアントの間にあります。クライアントは、レガシー サービスからデータを取得するキャッシュ サービスに接続します。キャッシング サービスは X 分ごとにデータをフェッチし、MongoDB に保持します。スキーマは非常にシンプルです。多くのキー/値を持つドキュメントです。ネストされたドキュメントなどはありません。さらに、_id を従来のサービスからの一意の ID に設定するため、これも制御できます。

キャッシング サービスがレガシー サービスからデータを取得すると、差分のみが取得されます (最後の取得以降の変更のみ)。したがって、前回から 5 つの「オブジェクト」が変更された場合、それらの 5 つの「オブジェクト」だけが取得されます (ただし、オブジェクトのデルタではなく、完全なオブジェクトが取得されます)。新しい「オブジェクト」がレガシー サービスに追加された場合、それらはもちろんデルタにも含まれます。

私たちの「問題」

私の考えでは、これはアップサートのように聞こえます。新しいオブジェクトがある場合は、それらを挿入します。既存のオブジェクトに変更がある場合は、それらを更新します。ただし、MongoDB は複数のアップサートを特に好まないようです。挿入するだけで重複キーに関するエラーが表示されますが、同じ _id を持つドキュメントが既に存在するため、これは完全に理解できます。upsert パラメーターを取ることができる update 関数は、新しいオブジェクトのリストを取ることはできません。単一のクエリは不可能であるように私には思えます。ただし、ここで何かを完全に見落としている可能性があります。

可能な解決策

さまざまな解決策がいくつかありますが、特に次の 2 つが思い浮かびます。

  • 2 つのクエリを実行します。最初に、すべての _id を含むリストを計算します (これらはレガシー サービスから取得したことを思い出してください)。次に、_id リストと一緒に $in 関数を使用してそれらを削除し、すぐに新しいドキュメントを挿入します。これにより、実際にはコレクションが新しいデータで更新されます。実装も簡単です。発生する可能性のある問題は、クライアントが削除と挿入の間にデータを要求し、そのために誤って空の結果を取得することです。これは契約違反であり、絶対に起こり得ません。
  • 変更されたオブジェクトごとに 1 つの upsert を実行します。また、実装が非常に簡単で、他のソリューションと同じ問題が発生することはありません。ただし、これには他の(おそらく架空の)問題があります。短時間で何回のアップサートを処理できますか? 毎分 5000 回のアップサートを簡単に処理できるでしょうか? これらは大きなドキュメントではなく、約 20 個のキー/値で、サブドキュメントはありません。この数字はひっそりと引き出されたものであり、実際の数字を予測することは非常に困難です。私の考えでは、このアプローチは間違っているように感じます。新しいドキュメントごとに 1 つのクエリを実行する必要がある理由がわかりません。

提案された2つの解決策とその他の解決策の両方に関して、どんな助けも大歓迎です。余談ですが、テクノロジーは議論の余地がないので、他の種類のデータベースや言語を提案しないでください。私たちが選んだものを選んだ理由は他にもあります:)

4

4 に答える 4

1

私の経験を共有します...

私の最後の仕事で、私たちは同様の状況にありました。ドキュメント/オブジェクトごとに 1 つのクエリ/書き込みを行うことになりました。Mule ESB を使用して、レガシー システムから Mongo にデータをポンプし、各書き込みはアップサートでした。

パフォーマンスはかなり良かったですが、素晴らしいものではありませんでした。数分で数千のドキュメントを Mongo に取り込むことができました。ドキュメントはかなり豊富だったので、Mongo への書き込みを抑制しなければならなかった理由の 1 つであった可能性があります。

データを一括ロードした後、「リアルタイム」のパフォーマンスは問題になりませんでした。

あなたが提案した最初のオプションは複雑すぎるように聞こえ、更新の途中で操作が停止した場合、Mongo が不明な状態になる可能性があります。upsert オプションは、挿入を何度も再生して安全にすることができたので、私たちを何度も救ってくれました。

于 2013-11-01T16:08:58.133 に答える
0

知っている。それを行う正しい方法を本当に深く掘り下げなければなりませんでした。これを試してください: /** * ドキュメント内のすべてのアイテムをコレクションに挿入します。* @param coll ターゲット コレクション * @param docs 新規または更新されたドキュメント * @param keyTag ドキュメント内のキーの名前 * @param upsert true の場合、見つからない場合は新しいドキュメントを作成します * @return BulkWriteResult または docs の場合は null。 isEmpty() */

    public static BulkWriteResult insertAll(MongoCollection<Document> coll, List<Document> docs, String keyTag, boolean upsert) {
    if(docs.isEmpty())
        return null;
    List<UpdateOneModel<Document>> requests = new ArrayList<>(docs.size());
    UpdateOptions opt = new UpdateOptions().upsert(upsert);
    for (Document doc : docs ) {
        BasicDBObject filter = new BasicDBObject(keyTag, doc.get(keyTag)); 
        BasicDBObject action = new BasicDBObject("$set", doc);
        requests.add(new UpdateOneModel<Document>(filter, action, opt));
    }
    return coll.bulkWrite(requests);
}
于 2015-05-29T15:28:01.453 に答える