提高Redis性能以减少超时异常

5
我在Centos服务器上安装了Redis数据库,有3台Windows服务器连接到该数据库,每秒读/写约为1,000次,全部在同一本地局域网中,ping时间小于1毫秒。问题在于至少5%的读操作超时,而我在读操作中最多读取3KB数据,使用'syncTimeout=15',这远高于网络延迟。
我在我的Windows 10上通过Bash安装了Redis,并模拟了这个问题。我停止了写操作。然而,即使没有网络延迟,问题仍然存在0.5%的超时。
我还在我的局域网中使用了一个Centos服务器来模拟这个问题,在这种情况下,我需要100毫秒的'syncTimeout'才能确保超时量小于1%。
我考虑使用一些字典来缓存从Redis获取的数据,以便不需要逐项请求,而且可以利用管道功能。但是我发现StackRedis.L1被开发为Redis的L1缓存,并且对于更新L1缓存不太自信。
以下是我用来模拟此问题的代码:
    var connectionMulti = ConnectionMultiplexer.Connect(
            "127.0.0.1:6379,127.0.0.1:6380,allowAdmin=true,syncTimeout=15");

    // 100,000 keys
    var testKeys = File.ReadAllLines("D:\\RedisTestKeys.txt");

    for (var i = 0; i < 3; i++)
    {
        var safeI = i;
        Task.Factory.StartNew(() =>
        {
            var serverName = $"server {safeI + 1}";
            var stringDatabase = connectionMulti.GetDatabase(12);
            PerformanceTest($"{serverName} -> String: ",
                key => stringDatabase.StringGet(key), testKeys);
        });
    }

PerformanceTest方法如下:

private static void PerformanceTest(string testName, Func<string, RedisValue> valueExtractor,
        IList<string> keys)
    {
        Task.Factory.StartNew(() =>
        {
            Console.WriteLine($"Starting {testName} ...");
            var timeouts = 0;
            var errors = 0;
            long totalElapsedMilliseconds = 0;

            var stopwatch = new Stopwatch();
            foreach (var key in keys)
            {
                var redisValue = new RedisValue();
                stopwatch.Restart();
                try
                {
                    redisValue = valueExtractor(key);

                }
                catch (Exception e)
                {
                    if (e is TimeoutException)
                        timeouts++;
                    else
                        errors++;
                }
                finally
                {
                    stopwatch.Stop();
                    totalElapsedMilliseconds += stopwatch.ElapsedMilliseconds;
                    lock (FileLocker)
                    {
                        File.AppendAllLines("D:\\TestResult.csv",
                            new[]
                            {
                                $"{stopwatch.ElapsedMilliseconds.ToString()},{redisValue.Length()},{key}"
                            });
                    }
                }
            }

            Console.WriteLine(
                $"{testName} {totalElapsedMilliseconds * 1.0 / keys.Count} (errors: {errors}), (timeouts: {timeouts})");
        });
    }

我希望所有读操作都能在15毫秒内成功完成。 为了实现这一点,考虑将L1缓存用于Redis缓存是否是一个好的解决方案?(它非常快,以纳秒级别计算,但如何进行同步) 或者Redis可以通过集群或其他方式进行增强吗?(虽然我在我的PC上测试过,但没有收到预期的结果)


1
如果您能分享一个 [mcve],那将非常棒。 - mjwills
1个回答

3

Redis可以通过集群或其他方式进行增强吗?

Redis可以以不同的方式进行集群:

  • “常规”Redis可以复制到辅助只读节点上,位于同一台机器或不同的机器上。然后您可以将“读取”流量发送到某些副本。
  • 存在Redis“集群”,它允许您将键空间分片(Shard)到多个主节点上,并向每个节点发送适当的请求
  • Redis“集群”还可以使用分片节点的只读副本

这是否合适或有用取决于具体情况,需要本地知识和测试。

考虑到Redis缓存,将L1缓存视为Redis缓存的解决方案是否可行?

是的,这是一个好的解决方案。您不发出的请求比您发出的请求要快得多(并且对性能影响更小)。有一些工具可用于帮助进行缓存失效,包括使用发布/订阅API进行失效处理。 Redis vNext还在研究针对此类L1场景的附加知识API。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接