Получение низкой производительности при сохранении в кэш Redis (с использованием ServiceStack.Redis)

Я получаю очень низкую производительность при сохранении данных в кэш Redis.

Сценарий:

1) Использование службы кэширования Redis (предоставляется Microsoft Azure).
2) Запуск кода на виртуальной машине, созданной в Azure.
3) Виртуальная машина и служба кэширования создаются в одном месте.

Фрагмент кода:

    public void MyCustomFunction()
    {
        Stopwatch totalTime = Stopwatch.StartNew();

        RedisEndpoint config = new RedisEndpoint();
        config.Ssl = true;
        config.Host = "redis.redis.cache.windows.net";
        config.Password = Form1.Password;
        config.Port = 6380;
        RedisClient client = new RedisClient(config);

        int j = 0;

        for (int i = 0; i < 500; i++)
        {
            var currentStopWatchTime = Stopwatch.StartNew();
            var msgClient = client.As<Message>();

            List<string> dataToUpload = ClientData.GetRandomData();
            string myCachedItem_1 = dataToUpload[1].ToString();

            Random ran = new Random();
            string newKey = string.Empty;
            newKey = Guid.NewGuid().ToString();

            Message newItem = new Message
            {
                Id = msgClient.GetNextSequence(), // Size : Long variable
                //Id = (long)ran.Next(),
                Key = j.ToString(),             // Size: Int32 variable
                Value = newKey,                 // Size : Guid string variable
                Description = myCachedItem_1    // Size : 5 KB
            };

            string listName = ran.Next(1, 6).ToString();
            msgClient.Lists[listName].Add(newItem);
            //msgClient.Store(newItem);

            Console.WriteLine("Loop Count : " + j++ + " , Total no. of items in List : " + listName + " are : " + msgClient.Lists[listName].Count);

            Console.WriteLine("Current Time: " + currentStopWatchTime.ElapsedMilliseconds + " Total time:" + totalTime.ElapsedMilliseconds);

            Console.WriteLine("Cache saved");
        }
    }

Производительность (при сохранении):

Примечание: (время указано в миллисекундах)

Количество циклов: 0, всего нет. элементов в списке: 2: 1 Текущее время: 310 Общее время:342 Кэш сохранен Количество циклов: 1, Всего нет. элементов в списке: 3: 1 Текущее время: 6 Общее время:349 Кэш сохранен Количество циклов: 2, Всего нет. элементов в списке: 5: 1 Текущее время: 3 Общее время:353 Кэш сохранен Количество циклов: 3, Всего нет. элементов в списке: 5: 2 Текущее время: 3 Общее время:356 Кэш сохранен Количество циклов: 4, Всего нет. элементов в списке: 5: 3 текущее время: 3 общее время:360 Кэш сохранен

,,,,,

Количество петель: 330, всего нет. элементов в списке: 4: 69 текущее время: 2 общее время:7057 кэш сохранен
Количество петель: 331, всего нет. элементов в списке: 4: 70 текущее время: 3 общее время:7061 кэш сохранен
Количество циклов: 332, всего нет. элементов в списке: 4: 71 текущее время: 2 общее время:7064 кэш сохранен

Производительность (при получении)

Список: 1 Количество предметов: 110 Время: 57

Список: 2 Количество предметов: 90 Время: 45

Список: 3 Количество предметов: 51 Время: 23

Список: 4 Количество предметов: 75 Время: 32

Список: 5 Количество предметов: 63 Время: 33

1 ответ

Если вы работаете в пакетном режиме, вам следует обратить внимание на уменьшение количества синхронных сетевых запросов, которые вы делаете, чтобы уменьшить задержку, которая станет основной проблемой производительности при взаимодействии с сетевыми службами.

В этом примере вы читаете, когда звоните:

msgClient.GetNextSequence();

и написать, когда вы делаете:

msgClient.Lists[listName].Add(newItem);

Это в общей сложности 1000 синхронных запросов / ответных сетевых запросов в одном потоке, где каждая операция зависит и должна быть завершена до отправки следующей, поэтому задержка в сети будет основным источником проблем с производительностью, которые следует посмотрите на оптимизацию.

Запросы дозирования

Если вы имеете дело с пакетными запросами, это можно значительно оптимизировать, уменьшив количество операций чтения и записи, извлекая все идентификаторы в одном запросе и сохраняя их, используя AddRange() пакетная операция, например:

var redisMessages = Redis.As<Message>();
const int batchSize = 500;

//fetch next 500 sequence of ids in a single request
var nextIds = redisMessages.GetNextSequence(batchSize); 

var msgBatch = batchSize.Times(i => 
    new Message {
        Id = nextIds - (batchSize - i) + 1,
        Key = i.ToString(), 
        Value = Guid.NewGuid().ToString(),
        Description = "Description"
    });

//Store all messages in a single multi operation request
redisMessages.Lists[listName].AddRange(msgBatch);

Это сократит количество операций по повторному вводу 1000 до 2 операций.

Затем, если вам нужно, вы можете получить все сообщения с помощью:

var allMsgs = redisMessages.Lists[listName].GetAll();

или конкретные диапазоны с использованием GetRange(startingFrom,endingAt) API.

Другие вопросы по тегам