1

最新のBookSleeveライブラリ1.3.38を使用するように Web サービスを更新中です。以前は 1.1.0.7 を使用していました

いくつかのベンチマークを行っているときに、新しいバージョンの BookSleeve を使用して Redis でハッシュを設定すると、古いバージョンより何倍も遅いことに気付きました。次の C# ベンチマーク コードを検討してください。

public void TestRedisHashes()
{
  int numItems = 1000; // number of hash items to set in redis 
  int numFields = 30; // number of fields in each redis hash
  RedisConnection redis = new RedisConnection("10.0.0.01", 6379);
  redis.Open();

  // wait until the connection is open
  while (!redis.State.Equals(BookSleeve.RedisConnectionBase.ConnectionState.Open)) { }

  Stopwatch timer = new Stopwatch();
  timer.Start();
  for (int i = 0; i < numItems; i++)
  {
    string key = "test_" + i.ToString();

    for (int j = 0; j < numFields; j++)
    {
      // set a value for each field in the hash
      redis.Hashes.Set(0, key, "field_" + j.ToString(), "testdata");
    }
    redis.Keys.Expire(0, key, 30); // 30 second ttl
  }
  timer.Stop();

  Console.WriteLine("Elapsed time for hash writes: {0} ms", timer.ElapsedMilliseconds);
}

BookSleeve 1.1.0.7 は 1000 ハッシュを Redis 2.6 に設定するのに約 20 ミリ秒かかりますが、1.3.38 は約 400 ミリ秒かかります。それは20倍遅いです!私がテストした BookSleeve 1.3.38 の他のすべての部分は、古いバージョンと同じか、それよりも高速です。また、Redis 2.4 を使用して同じテストを試み、すべてをトランザクションにラップしました。どちらの場合も、同様のパフォーマンスが得られました。

他の誰かがこのようなことに気づいたことがありますか? 私は何か間違ったことをしているに違いありません... BookSleeve の新しいバージョンを使用してハッシュを正しく設定していますか? これは、ファイア アンド フォーゲット コマンドを実行する正しい方法ですか? ハッシュの使用方法の例として単体テストを調べましたが、別の方法を見つけることができませんでした。この場合、最新バージョンが単に遅い可能性はありますか?

4

1 に答える 1

0

全体的な速度を実際にテストするには、最後のメッセージが処理されるのを待つコードを追加する必要があります。次に例を示します。

  Task last = null;
  for (int i = 0; i < numItems; i++)
  {
    string key = "test_" + i.ToString();

    for (int j = 0; j < numFields; j++)
    {
      // set a value for each field in the hash
      redis.Hashes.Set(0, key, "field_" + j.ToString(), "testdata");
    }
    last = redis.Keys.Expire(0, key, 30); // 30 second ttl
  }
  redis.Wait(last);

それ以外の場合は、 /への呼び出しSetExpireがどれだけ速いかだけがタイミングです。そしてこの場合、それは問題になる可能性があります。1.1.0.7 では、すべてのメッセージがすぐにキューに配置され、別の専用ライター スレッドがそのメッセージを取得してストリームに書き込みます。1.3.38 では、専用のライター スレッドがなくなりました(さまざまな理由により)。したがって、ソケットが使用可能である場合、呼び出し元のスレッドは基になるストリームに書き込みます (ソケットが使用中の場合、それを処理するメカニズムがあります)。さらに重要なことに、1.1.0.7 に対する元のテストでは、実際にはまだ有用な作業が行われていない可能性があります。作業がソケットの近くにあるという保証はありません。

ほとんどのシナリオでは、これによってオーバーヘッドが発生することはありません (償却するとオーバーヘッドが少なくなります) が、実際にバッファ アンダーランの影響を受ける可能がありますワーカー スレッドは、おそらく常により多くの待機中のメッセージを見つけていたでしょう。そのため、最後までストリームをフラッシュしませんでした。1.3.38 では、おそらくメッセージ間でフラッシュしています。だから:それを修正しましょう:

Task last = null;
redis.SuspendFlush();
try {
  for (int i = 0; i < numItems; i++)
  {
    string key = "test_" + i.ToString();

    for (int j = 0; j < numFields; j++)
    {
      // set a value for each field in the hash
      redis.Hashes.Set(0, key, "field_" + j.ToString(), "testdata");
    }
    last = redis.Keys.Expire(0, key, 30); // 30 second ttl
  }
}
finally {
  redis.ResumeFlush();
}
redis.Wait(last);

SuspendFlush()/ペアは、追加のフラッシュを回避するために単一のスレッドでResumeFlush()大量の操作のバッチを呼び出す場合に理想的です。IntelliSense のメモをコピーするには:

//
// Summary:
// Temporarily suspends eager-flushing (flushing if the write-queue becomes
// empty briefly). Buffer-based flushing will still occur when the data is full.
// This is useful if you are performing a large number of operations in close
// duration, and want to avoid packet fragmentation. Note that you MUST call
// ResumeFlush at the end of the operation - preferably using Try/Finally so
// that flushing is resumed even upon error. This method is thread-safe; any
// number of callers can suspend/resume flushing concurrently - eager flushing
// will resume fully when all callers have called ResumeFlush.
//
// Remarks:
// Note that some operations (transaction conditions, etc) require flushing
// - this will still occur even if the buffer is only part full.

ほとんどの高スループット シナリオでは、複数のスレッドから複数の操作が行われることに注意してください。これらのシナリオでは、同時スレッドからのすべての作業は、スレッドの数を最小限に抑える方法で自動的にキューに入れられます。

于 2013-09-09T07:27:58.470 に答える