11

テストデータをテーブルに追加する単純な WorkerRole を作成します。インサートのコードはこんな感じ。

var TableClient = this.StorageAccount.CreateCloudTableClient();
TableClient.CreateTableIfNotExist(TableName);
var Context = TableClient.GetDataServiceContext();

this.Context.AddObject(TableName, obj);
this.Context.SaveChanges();

このコードは、クライアントの要求ごとに実行されます。1 ~ 30 のクライアント スレッドでテストします。さまざまなサイズのインスタンスのさまざまな数を試してみました。何が間違っているのかわかりませんが、1 秒あたり 10 回以上挿入することはできません。速度を上げる方法を知っている方がいましたら教えてください。ありがとう

アップデート

  • CreateTableIfNotExist を削除しても、挿入テストに違いはありません。
  • モードを expect100Continue="false" useNagleAlgorithm="false" に切り替えると、挿入レートが 30 ~ 40 ips にジャンプしたときに短時間の効果が得られます。しかし、その後、30 秒後に挿入レートが 6 ips に低下し、50% のタイムアウトが発生します。
4

1 に答える 1

30

処理を高速化するには、バッチ トランザクション (エンティティ グループ トランザクション) を使用して、1 回のリクエストで最大 100 個のアイテムをコミットできるようにする必要があります。

foreach (var item in myItemsToAdd)
{
    this.Context.AddObject(TableName, item);
}
this.Context.SaveChanges(SaveChangesOptions.Batch);

これをPartitioner.Create (+ AsParallel) と組み合わせて、100 項目のバッチごとに異なるスレッド/コアで複数の要求を送信して、物事を非常に高速にすることができます。

ただし、これらすべてを実行する前に、バッチ トランザクションを使用する際の制限(100 アイテム、トランザクションごとに 1 パーティションなど) をお読みください。

アップデート:

ここではトランザクションを使用できないため、その他のヒントをいくつか示します。テーブル ストレージを使用する場合のパフォーマンスの向上に関するこの MSDN スレッドをご覧ください。違いを示すためにいくつかのコードを書きました:

    private static void SequentialInserts(CloudTableClient client)
    {
        var context = client.GetDataServiceContext();
        Trace.WriteLine("Starting sequential inserts.");

        var stopwatch = new Stopwatch();
        stopwatch.Start();

        for (int i = 0; i < 1000; i++)
        {
            Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId));
            context.AddObject(TABLENAME, new MyEntity()
            {
                Date = DateTime.UtcNow,
                PartitionKey = "Test",
                RowKey = Guid.NewGuid().ToString(),
                Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString())
            });
            context.SaveChanges();
        }

        stopwatch.Stop();
        Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString());
    }

したがって、これを初めて実行すると、次の出力が得られます。

Starting sequential inserts.
Adding item 0. Thread ID: 10
Adding item 1. Thread ID: 10
..
Adding item 999. Thread ID: 10
Done in: 00:03:39.9675521

1000 個のアイテムを追加するには 3 分以上かかります。ここで、MSDN フォーラムのヒントに基づいて app.config を変更しました (maxconnection は 12 * CPU コア数である必要があります)。

  <system.net>
    <settings>
      <servicePointManager expect100Continue="false" useNagleAlgorithm="false"/>
    </settings>
    <connectionManagement>
      <add address = "*" maxconnection = "48" />
    </connectionManagement>
  </system.net>

アプリケーションを再度実行すると、次の出力が得られます。

Starting sequential inserts.
Adding item 0. Thread ID: 10
Adding item 1. Thread ID: 10
..
Adding item 999. Thread ID: 10
Done in: 00:00:18.9342480

3分以上から18秒まで。なんという違いでしょう!しかし、私たちはもっとうまくやることができます。以下は、Partitioner を使用してすべての項目を挿入するコードです (挿入は並行して行われます)。

    private static void ParallelInserts(CloudTableClient client)
    {            
        Trace.WriteLine("Starting parallel inserts.");

        var stopwatch = new Stopwatch();
        stopwatch.Start();

        var partitioner = Partitioner.Create(0, 1000, 10);
        var options = new ParallelOptions { MaxDegreeOfParallelism = 8 };

        Parallel.ForEach(partitioner, options, range =>
        {
            var context = client.GetDataServiceContext();
            for (int i = range.Item1; i < range.Item2; i++)
            {
                Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId));
                context.AddObject(TABLENAME, new MyEntity()
                {
                    Date = DateTime.UtcNow,
                    PartitionKey = "Test",
                    RowKey = Guid.NewGuid().ToString(),
                    Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString())
                });
                context.SaveChanges();
            }
        });

        stopwatch.Stop();
        Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString());
    }

そして結果:

Starting parallel inserts.
Adding item 0. Thread ID: 10
Adding item 10. Thread ID: 18
Adding item 999. Thread ID: 16
..
Done in: 00:00:04.6041978

出来上がり、3 分 39 秒から 18 秒に落ち、今では 4 秒にさえ落ちています

于 2012-10-05T16:41:09.997 に答える