1

在 CentOS 6.4 上安装 redis 和 nutcracker。并尝试使用 ServiceStack.Redis 客户端进行连接。发现主要的性能问题。

测试只剩下 1 个 redis 实例

beta:
  listen: 0.0.0.0:22122
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  #timeout: 5000
  #server_retry_timeout: 2000
  #server_failure_limit: 3
  redis: true
  servers:
  #- 127.0.0.1:6379:1
   - 127.0.0.1:6380:1

在下面的单元测试中,我试图通过 nutcracker 向 redis 发送 100k 字符串。

[TestClass]
public class RedisProxyTest
{
    public string host = "192.168.56.112";
    //public int port = 6379;
    public int port = 22122;

    [TestMethod]
    public void TestMethod1()
    {
        var key = "l2";
        var count = 100000;
        using (var redisClient = new RedisClient(host, port))
        {
            var list = new List<string>();
            for (int i = 0; i < count; i++)
            {
                list.Add(Guid.NewGuid().ToString());
            }

            Utils.TimeLog("Remove", () => redisClient.Remove(key));

            Utils.TimeLog("AddRangeToList", () => redisClient.AddRangeToList(key, list));
        }

        using (var redisClient = new RedisClient(host, port))
        {
            redisClient.GetListCount(key);

            Utils.TimeLog("GetRangeFromList", () =>
            {
                var ret = redisClient.GetRangeFromList(key, count / 2, count - 1);
                Console.WriteLine(ret.Count);
            });
        }

    }
}

在胡桃夹子重新启动后的前几次运行中,AddRangeToList 的工作时间为 1-2 秒。但是随着后续运行 AddRangeToList 性能从几分钟甚至超过 20 分钟(如果没有配置超时)显着下降。直接使用redis时无法重现。我还没有尝试任何其他客户端。任何想法为什么?

这是我在单元测试运行后在控制台中看到的:

Test Name:  TestMethod1
Test Outcome:   Passed  
Remove: 0.0331171
AddRangeToList: 806.8219166
50000
GetRangeFromList: 1.741737
4

2 回答 2

2

看起来问题与传输大量数据时的高内存使用率有关。

默认情况下,胡桃夹子为每个键分配 16k 的缓冲区大小。在我的情况下,它将是16k*100000 = 1.5Gb。在观看胡桃夹子过程时,我看到了大约 2Gb 的峰值。我的 Cent OS 虚拟机超载,没有足够的内存来处理这个峰值。

于 2013-11-17T00:55:38.020 回答
1

如果胡桃夹子正在代理数万个连接或发送具有数千个键的多获取请求,则应使用 mbuf 大小为 512

以下链接讨论如何解释 mbuf 大小?- https://github.com/twitter/twemproxy/issues/141

每个客户端连接至少消耗一个 mbuf。为了服务一个请求,我们需要两个连接(一个从客户端到代理,另一个从代理到服务器)。所以我们需要两个mbuf。

像 'get foo bar\r\n' 这样的可分段请求,顺便说一句,它会被分段为 'get foo\r\n' 和 'get bar\r\n' 会消耗两个 mbuf 的请求和两个 mbuf 的响应。所以一个带有 N 个片段的可分片请求需要 N * 2 mbufs

mbuf 的好处是内存来自重用池。一旦分配了 mbuf,它就永远不会被释放,而只是放回重用池中。不好的是,一旦分配了 mbuf,它就永远不会被释放,因为释放的 mbuf 总是会回到重用池 - https://github.com/twitter/twemproxy/blob/master/src/nc_mbuf.c#L23- L24(这可以通过在重用池上放置一个阈值参数来解决)

因此,如果胡桃夹子正在处理 1K 客户端连接和 100 个服务器连接,它将消耗 (max(1000, 100) * 2 * mbuf-size) 内存用于 mbuf。如果我们假设客户端正在发送非流水线请求,那么默认 mbuf-size 为 16K,这将总共消耗 32M。

此外,如果平均每个请求有 10 个碎片,那么内存消耗将是 320M。假设您正在处理 10K,而不是处理 1K 客户端连接,那么内存消耗将为 3.2G。现在不是使用 16K 的默认 mbuf 大小,而是使用 512 字节,然后相同场景的内存消耗将下降到 1000 * 2 * 512 * 10 = 10M

这就是为什么对于“大量”连接,您要为 mbuf-size 选择一个较小的值,例如 512

于 2013-11-18T02:41:10.077 回答