web-dev-qa-db-ja.com

Stackexchange.Redisでのパイプライン処理とバッチ処理

可能な限り短い時間で多数の要素を挿入しようとしていますが、次の2つの方法を試しました。

1)パイプライン:

List<Task> addTasks = new List<Task>();
for (int i = 0; i < table.Rows.Count; i++)
{
    DataRow row = table.Rows[i];
    Task<bool> addAsync = redisDB.SetAddAsync(string.Format(keyFormat, row.Field<int>("Id")), row.Field<int>("Value"));
    addTasks.Add(addAsync);
}
Task[] tasks = addTasks.ToArray();
Task.WaitAll(tasks);

2)バッチ処理:

List<Task> addTasks = new List<Task>();
IBatch batch = redisDB.CreateBatch();
for (int i = 0; i < table.Rows.Count; i++)
{
    DataRow row = table.Rows[i];
    Task<bool> addAsync = batch.SetAddAsync(string.Format(keyFormat, row.Field<int>("Id")), row.Field<int>("Value"));
    addTasks.Add(addAsync);
}
batch.Execute();
Task[] tasks = addTasks.ToArray();
Task.WaitAll(tasks);

大きな時間差に気づいていません(実際には、バッチ方式の方が速いと思っていました)。約250Kのインサートの場合、パイプライン処理で約7秒、バッチ処理で約8秒かかります。

パイプラインに関するドキュメントを読んで、

「パイプラインを使用すると、両方のリクエストをすぐにネットワークに取り込むことができ、レイテンシのほとんどを排除できます。さらに、パケットの断片化を減らすのにも役立ちます。個別に送信される20のリクエスト(各応答を待機)には少なくとも20のパケットが必要ですが、20のリクエストが送信されます。パイプラインでは、はるかに少ないパケット(おそらく1つだけ)に収まる可能性があります。」

私には、これはバッチ処理の動作によく似ています。 procmonで簡単にチェックすると、両方のバージョンでほぼ同じ数のTCP Sendが表示されるため、舞台裏で2つの間に大きな違いがあるのではないかと思います。

21
CyberDude

舞台裏では、SE.Redisはパケットの断片化を回避するためにかなりの作業を行っているため、あなたの場合と非常に似ていることは驚くことではありません。バッチ処理とフラットパイプラインの主な違いは次のとおりです。

  • バッチが同じマルチプレクサで競合する操作とインターリーブされることはありません(ただし、サーバーでインターリーブされる場合があります。multi/execトランザクションまたはLuaスクリプトを使用する必要がないようにするため)
  • バッチはすべてのデータを事前に知っているため、サイズが小さいパケットの可能性を常に回避します
  • ただし、同時に、何かを送信する前にバッチ全体を完了する必要があるため、メモリ内のバッファリングがさらに必要になり、人為的にレイテンシが発生する可能性があります。

ほとんどの場合、SE.Redisは単に作業を追加するだけで、ほとんどのことを実行するため、バッチ処理を回避することでより良い結果が得られます自動的に

最後に、ローカルオーバーヘッドを回避したい場合、最後のアプローチの1つは次のとおりです。

redisDB.SetAdd(string.Format(keyFormat, row.Field<int>("Id")),
    row.Field<int>("Value"), flags: CommandFlags.FireAndForget);

これにより、応答を待つことも、将来の値を表すために不完全なTasksを割り当てることもなく、すべてがネットワークに送信されます。最後にPingのようなことをしたいと思うかもしれませんなしファイアアンドフォーゲット、サーバーがまだあなたと話していることを確認するために。ファイアアンドフォーゲットを使用すると、報告されるサーバーエラーに気付かないことに注意してください。

27
Marc Gravell