web-dev-qa-db-ja.com

MongoDB接続の.NETベストプラクティス

最近、GitHubでC#ドライバーを使用してMongoDBで遊んでいます(驚くほど高速です)。私がテストしている小さなシングルスレッドコンソールアプリでは、すべてがうまく機能しています。シングルスレッドを実行して、8秒未満で1,000,000のドキュメント(はい、100万)を追加できます。 forループのスコープ外で接続を使用する場合にのみ、このパフォーマンスが得られます。言い換えると、各挿入ごとに接続するのではなく、各挿入ごとに接続を開いたままにします。明らかにそれは不自然です。

複数のスレッドでどのように機能するかを確認するために、ノッチを上げると思いました。これは、複数の同時リクエストを含むWebサイトをシミュレートする必要があるためです。私は15〜50のスレッドをスピンアップしていますが、すべての場合で合計150,000のドキュメントを挿入しています。スレッドを実行させるだけで、挿入操作ごとに新しい接続が作成されると、パフォーマンスは停止します。

明らかに、接続を共有、ロック、またはプールする方法を見つける必要があります。そこに疑問があります。 MongoDBへの接続に関するベストプラクティスは何ですか?アプリの存続期間中、接続を開いたままにしておく必要があります(各操作でTCP接続を開いたり閉じたりするのにかなりの遅延があります)?

MongoDBの実際の使用経験や実稼働経験はありますか。具体的には基礎となる接続はありますか

これは、挿入操作のためにロックされている静的接続を使用した私のスレッドサンプルです。 Webコンテキストでパフォーマンスと信頼性を最大化する提案を提供してください!

private static Mongo _mongo;

private static void RunMongoThreaded()
{
    _mongo = new Mongo();
    _mongo.Connect();

    var threadFinishEvents = new List<EventWaitHandle>();

    for(var i = 0; i < 50; i++)
    {
        var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
        threadFinishEvents.Add(threadFinish);

        var thread = new Thread(delegate()
            {
                 RunMongoThread();
                 threadFinish.Set();
            });

        thread.Start();
    }

    WaitHandle.WaitAll(threadFinishEvents.ToArray());
    _mongo.Disconnect();
}

private static void RunMongoThread()
{
    for (var i = 0; i < 3000; i++)
    {
        var db = _mongo.getDB("Sample");
        var collection = db.GetCollection("Users");
        var user = GetUser(i);
        var document = new Document();
        document["FirstName"] = user.FirstName;
        document["LastName"] = user.LastName;

        lock (_mongo) // Lock the connection - not ideal for threading, but safe and seemingly fast
        {
            collection.Insert(document);
        }
    }
}
59
Tyler Brinks

ここでの回答のほとんどは時代遅れであり、. netドライバが成熟し、無数の機能が追加されたため、もはや適用できません。

ここにある新しい2.0ドライバーのドキュメントを参照してください: http://mongodb.github.io/mongo-csharp-driver/2.0/reference/driver/connecting/

.netドライバーはスレッドセーフになり、接続プーリングを処理します。ドキュメントによると

MongoClientインスタンスは、静的変数として、または寿命がシングルトンのIoCコンテナのいずれかとして、グローバルな場所に保存することをお勧めします。

95

静的接続について覚えておくべきことは、すべてのスレッドで共有されるということです。必要なのは、スレッドごとに1つの接続です。

9
Joel Coehoorn

Mongodb-csharpを使用する場合は、ADO接続。接続をプールに戻すブロックMongoオブジェクトの作成は安価で高速です。

for(var i=0;i<100;i++) 
{ 
        using(var mongo1 = new Mongo()) 
        using(var mongo2 = new Mongo()) 
        { 
                mongo1.Connect(); 
                mongo2.Connect(); 
        } 
} 

データベースログ
Wed Jun 02 20:54:21接続は127.0.0.1:58214#1から受け入れられました
Wed Jun 02 20:54:21接続は127.0.0.1:58215#2から受け入れられました
Wed Jun 02 20:54:21 MessagingPort recv()errno:0エラーなし127.0.0.1:58214
Wed Jun 02 20:54:21接続終了127.0.0.1:58214
Wed Jun 02 20:54:21 MessagingPort recv()errno:0エラーなし127.0.0.1:58215
Wed Jun 02 20:54:21接続終了127.0.0.1:58215

接続が2つしか開かれていないことに注意してください。

Mongodb-csharpフォーラムを使用してこれをまとめました。 http://groups.google.com/group/mongodb-csharp/browse_thread/thread/867fa78d726b1d4

5
Donny V.

CSMongo、 jLinqの開発者が作成したMongoDB用のC#ドライバーです。サンプルを次に示します。

//create a database instance
using (MongoDatabase database = new MongoDatabase(connectionString)) {

    //create a new document to add
    MongoDocument document = new MongoDocument(new {
        name = "Hugo",
        age = 30,
        admin = false
    });

    //create entire objects with anonymous types
    document += new {
        admin = true,
        website = "http://www.hugoware.net",
        settings = new {
            color = "orange",
            highlight = "yellow",
            background = "abstract.jpg"
        }
    };

    //remove fields entirely
    document -= "languages";
    document -= new[] { "website", "settings.highlight" };

    //or even attach other documents
    MongoDocument stuff = new MongoDocument(new {
        computers = new [] { 
            "Dell XPS", 
            "Sony VAIO", 
            "Macbook Pro" 
            }
        });
    document += stuff;

    //insert the document immediately
    database.Insert("users", document);

}
1
David Robbins

接続プールが答えになるはずです。

この機能は開発中です(詳細は http://jira.mongodb.org/browse/CSHARP-9 をご覧ください)。

現在、Webアプリケーションのベストプラクティスは、BeginRequestで接続し、EndRequestで接続を解放することです。しかし、私にとっては、接続プールを使用しない場合、リクエストごとに操作が高すぎると思います。そのため、グローバルMongoオブジェクトを用意し、それをすべてのスレッドの共有リソースとして使用することにします(現在githubから最新のC#ドライバーを入手すると、同時実行のパフォーマンスが少し向上します)。

Global Mongoオブジェクトを使用することのデメリットはわかりません。それで、別の専門家がこれについてコメントするのを待ちましょう。

しかし、機能(接続プール)が完了するまで、私はそれで生きていけると思います。

0
ensecoz

私はcsharp-mongodbドライバーを使用していますが、それは彼の接続プールに役立ちません:(Webリクエストごとにmongodbに約10-20のリクエストがあります。シェルからmongodbにそれは私に例外をスローします。

リクエストごとに接続を開いて破棄するリポジトリを作成しました。 1)ドライバーに接続プールがある2)私の調査の後(これについてユーザーグループに質問を投稿しました)-mongoオブジェクトを作成して接続を開くことは重い操作ではないので、重い操作です。

しかし、今日、私の生産はダウンします:(リクエストごとに開いている接続を保存する必要があるかもしれません...

ユーザーグループへのリンクはこちら http://groups.google.com/group/mongodb-user/browse_thread/thread/3d4a4e6c5eb48be3#

0
Antony Blazer