Получение низкой производительности при сохранении в кэш 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.