Повысить производительность Redis, чтобы уменьшить время ожидания - PullRequest
4 голосов
/ 13 октября 2019

У меня есть база данных Redis на сервере Centos, и к ней подключено 3 сервера Windows со скоростью примерно 1000 операций чтения / записи в секунду, причем все они находятся в одной локальной сети, поэтому время пинга составляет менее одной миллисекунды. Проблема в том, что по крайней мере 5 процентов операций чтения уходит в тайм-аут, в то время как я читаю максимум 3 КБ данных в операции чтения с 'syncTimeout = 15', что намного больше, чем задержка в сети.

Я установил Redis на bashна моей windows 10 и смоделировать проблему. Я также прекратил писать операции. Однако проблема все еще существует с 0,5-процентным таймаутом, в то время как нет задержки в сети. Я также использовал Centos Server в своей локальной сети для имитации проблемы, в этом случае мне нужно 100 миллисекунд для syncTimeout, чтобы убедиться, что время ожидания составляет менее 1 процента. Я подумал об использовании некоторых словарей для кэширования данных из Redis, поэтому нет необходимости запрашивать каждый элемент, и я могу воспользоваться конвейером. Но я наткнулся на StackRedis.L1, который разработан как кэш L1 для Redis, и он не уверен в обновлении кеша 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 может быть улучшен путем кластеризации или что-то еще? (Пока я тестировал его на bash на моем ПК, и я не получил ожидаемый результат)

1 Ответ

2 голосов
/ 13 октября 2019

Или Redis можно улучшить кластеризацией или чем-то еще?

Redis можно кластеризовать различными способами:

  • «обычные» redis могут быть реплицированы на вторичные узлы только для чтения, на одном и том же компьютере или на разных компьютерах;затем вы можете отправлять трафик «чтения» на некоторые из реплик
  • redis «кластер», который позволяет разделить (осколить) пространство ключей на несколько основных цветов, отправляя соответствующие запросы каждому узлу
  • redis "cluster" также может использовать реплики только для чтения заштрихованных узлов

Является ли это подходящим или полезным контекстуально и требует локальных знаний и тестирования.

Достигает ли это, считает ли кэш L1 для кэша Redis хорошим решением?

Да, это хорошее решение. Запрос, который вы не делаете, гораздо быстрее (и оказывает гораздо меньшее влияние на воздействие), чем запрос, который вы делаете . Существуют инструменты, помогающие в аннулировании кэша, в том числе использование API pub / sub для аннулирования. Redis vNext также изучает дополнительные интерфейсы API , в частности для такого сценария L1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...