【问题标题】:BookSleeve - Poor Performance When Setting HashesBookSleeve - 设置哈希时性能不佳
【发布时间】:2013-09-09 15:27:58
【问题描述】:

我正在更新我的 Web 服务以使用最新的 BookSleeve 库 1.3.38。以前我使用的是 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 正确设置了哈希?这是执行即发即弃命令的正确方法吗?我已经查看了 the unit tests 作为如何使用哈希的示例,但无法找到我正在做的不同之处。在这种情况下,最新版本是否可能更慢?

【问题讨论】:

    标签: c# redis booksleeve


    【解决方案1】:

    要实际测试整体速度,您需要添加等待处理最后一条消息的代码,例如:

      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);
    

    否则,您所需要的只是Set/Expire 的调用速度有多快。在这种情况下,这可能很重要。您会看到,在 1.1.0.7 中,所有消息都会立即放入队列中,然后一个单独的专用写入器线程会拾取该消息并将其写入流中。在 1.3.38 中,专用的编写器线程消失了(出于各种原因)。所以如果套接字可用,调用线程将写入底层流(如果套接字正在使用,则有一种机制来处理它)。更重要的是,在您针对 1.1.0.7 的原始测试中,可能实际上还没有发生任何有用的工作 - 不能保证工作在套接字附近的任何地方,等等。

    在大多数情况下,这不会导致任何开销(并且摊销时开销更少),但是:在您的情况下,您可能会受到有效的影响> 缓冲区运行不足 - 在 1.1.0.7 中,您会真的快速填满缓冲区,并且工作线程可能总是会发现更多等待消息 - 所以它不会刷新流直到结束;在 1.3.38 中,它可能正在刷新 between 消息。所以:让我们解决这个问题:

    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() 对非常适合在单个线程上调用大量操作以避免任何额外的刷新。复制智能感知笔记:

    //
    // 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.
    

    请注意,在大多数高吞吐量场景中,多个操作来自多个线程:在这些场景中,来自并发线程的任何工作都将自动以最小化线程数的方式排队。

    【讨论】:

    • 感谢马克的详细回答!只要我 .Wait() 完成操作,使用 Suspend/ResumeFlush 似乎确实可以使性能与 1.1.0.7 保持一致。删除专用编写器线程是 1.2.0.8 和 1.3 之间的发行说明中提到的主要更改之一吗?
    • @burnsuv 是的,基本上;引用发行说明:“1.3.*- 重大变化;1.3 删除了线程核心,以允许在多个连接上实现更大的可扩展性;”
    猜你喜欢
    • 1970-01-01
    • 2021-02-05
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2017-09-02
    相关资源
    最近更新 更多