【问题标题】:servicestack.redis wrapper poor performanceservicestack.redis 包装器性能不佳
【发布时间】:2015-05-28 00:47:02
【问题描述】:

我们正在尝试使用 ServiceStack 包装器在 Redis 中存储一些大缓冲区(每个 8MB)。我们使用“RedisNativeClient.Set(string key, byte[] value)” API 来设置缓冲区。 客户端和服务器都驻留在同一台机器上。 坚持残疾人。 我们目前正在使用 ServiceStack 的评估版。

问题是我们的性能很差 - 大约 60 MB/秒。 使用一些不同的 c# 包装器(“Sider”),我们可以获得更好的性能(~400 MB/秒)。

我用于测量的代码:

 public void SimpleTest()
        {
            Stopwatch sw;
            long ms1, ms2, interval;
            int nBytesHandled = 0;
            int nBlockSizeBytes = 8000000;
            int nMaxIterations = 5;
            byte[] pBuffer = new byte[(int)(nBlockSizeBytes)];


            // Create Redis Wrapper
            ServiceStack.Redis.RedisNativeClient m_serviceStackRedisClient = new ServiceStack.Redis.RedisNativeClient();

            // Clear DB
            m_serviceStackRedisClient.FlushAll();


            sw = Stopwatch.StartNew();
            ms1 = sw.ElapsedMilliseconds;
            for (int i = 0; i < nMaxIterations; i++)
            {
                m_serviceStackRedisClient.Set("eitan" + i.ToString(), pBuffer);
                nBytesHandled += nBlockSizeBytes;
            }

            ms2 = sw.ElapsedMilliseconds;
            interval = ms2 - ms1;

            // Calculate rate
            double dMBPerSEc = nBytesHandled / 1024.0 / 1024.0 / ((double)interval / 1000.0);
            Console.WriteLine("Rate {0:N4}", dMBPerSEc);
        }

可能是什么问题?

谢谢, 艾坦。

【问题讨论】:

  • 您能否提供您用于测试 ServiceStack Redis 客户端和其他 C# Sider Redis 客户端的源代码。
  • 内嵌代码......

标签: servicestack.redis


【解决方案1】:

ServiceStack.Redis 使用可重用的缓冲池通过重用字节缓冲区池来减少内存压力。默认byte[] 缓冲区的大小为1450 字节,以适应以太网 MTU 数据包大小。虽然此默认配置对于较小负载 (1MB+),它看起来最终会变慢。

基于此,ServiceStack.Redis 客户端现已修改,现在它不再使用缓冲池来处理大于 500k 的有效负载,现在可以使用RedisConfig.BufferPoolMaxSize 进行配置,例如:

RedisConfig.BufferPoolMaxSize = 500000;

byte[] 缓冲区的默认 1450 字节大小现在也可配置为:

RedisConfig.BufferLength = 1450;

此更改现在提高了 ServiceStack.Redis 对于较大负载的吞吐量性能,如 RedisBenchmarkTests 套件中所示,该套件使用不同负载大小的基准,例如:

public void Run(string name, int nBlockSizeBytes, Action<int,byte[]> fn)
{
    Stopwatch sw;
    long ms1, ms2, interval;
    int nBytesHandled = 0;
    int nMaxIterations = 5;
    byte[] pBuffer = new byte[nBlockSizeBytes];

    // Create Redis Wrapper
    var redis = new RedisNativeClient();

    // Clear DB
    redis.FlushAll();

    sw = Stopwatch.StartNew();
    ms1 = sw.ElapsedMilliseconds;
    for (int i = 0; i < nMaxIterations; i++)
    {
        fn(i, pBuffer);
        nBytesHandled += nBlockSizeBytes;
    }

    ms2 = sw.ElapsedMilliseconds;
    interval = ms2 - ms1;

    // Calculate rate
    double dMBPerSEc = nBytesHandled / 1024.0 / 1024.0 / (interval / 1000.0);
    Console.WriteLine(name + ": Rate {0:N4}, Total: {1}ms", dMBPerSEc, ms2);
}

从我的 MacBook Pro 和在 Ubuntu VirtualBox VM 中运行的 redis-server 运行的结果:

1K 结果:

ServiceStack.Redis 1K: Rate 4.7684, Total: 1ms
Sider 1K: Rate 0.4768, Total: 10ms

10K 结果:

ServiceStack.Redis 10K: Rate 47.6837, Total: 1ms
Sider 10K: Rate 4.3349, Total: 11ms

100K 结果:

ServiceStack.Redis 100K: Rate 26.4910, Total: 18ms
Sider 100K: Rate 20.7321, Total: 23ms

1MB 结果:

ServiceStack.Redis 1MB: Rate 103.6603, Total: 46ms
Sider 1MB: Rate 70.1231, Total: 68ms

8MB 结果:

ServiceStack.Redis 8MB: Rate 77.0646, Total: 495ms
Sider 8MB: Rate 84.3960, Total: 452ms

ServiceStack.Redis 的性能对于较小的负载更快,而现在对于大于 8MB 的负载更接近。

此更改从 v4.0.41+ 可用,现在是 available on MyGet

【讨论】:

  • 非常感谢。我检查了它,它确实工作得更好。
猜你喜欢
  • 2015-06-02
  • 2012-10-29
  • 1970-01-01
  • 2012-12-31
  • 2014-07-17
  • 2013-08-02
  • 2013-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多