Запрос миллиона ключей из кэша Redis за один вызов

#caching #redis #language-agnostic

#кэширование #redis #не зависит от языка

Вопрос:

Я использую Redis в качестве своего сервера кэша. Для наглядности я сохраняю пары ключ-значение, подобные 'S0007226_2005-07-09': '[15.3462, -1]' . Запросы касаются конкретных ключей, а не основаны на диапазоне. Для запроса я использую клиент pyredis.

Мне часто приходится извлекать ~ 1 миллион ключей из кэша. Этот тип запроса слишком тяжелый для redis и занимает до 10 секунд. Загвоздка здесь в том, что MGET для n ключей в запросе — это операция O (n) (n — количество ключей в запросе). Я добавил таблицу для времени запроса из журналов.

 | Keys   | time(ms)|
| 703732 | 6869.66 |
| 26806  | 277.21  |
| 13180  | 137.41  |
| 400    | 5.83    |
| 2589   | 29.04   |
| 180    | 3.6     |
| 98413  | 1009.84 |
| 151994 | 1524.12 |
  

Это кажется очень нормальным, так как с увеличением количества ключей время увеличивается в O (n) направлении. Кроме того, я использую конвейер redis, разбивающий список ключей на куски по 10 Тыс.

Я хочу сократить время запроса до ~ 1 секунды или меньше. Если бы это был не Redis, я мог бы попытаться запросить параллельно и объединить результаты. Но, учитывая, что redis может работать только на одном ядре, в моем понимании это нецелесообразный вариант. Возможный выход:

  1. Внесите некоторые изменения в дизайн, чтобы мне не приходилось запрашивать миллион ключей в первую очередь.
  2. Используйте какой-либо другой инструмент вместо Redis для обработки нагрузки.
  3. Некоторая оптимизация в самой текущей настройке для лучшей обработки.

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

Комментарии:

1. Просто что-то, что следует иметь в виду при отправке команд 10K в одном конвейере: когда вы используете конвейерную обработку, Redis будет помещать ответы в очередь на стороне сервера перед их отправкой обратно, что увеличит используемую память.

2. Здесь всего 100 команд, каждая с 10 тысячами ключей, но я понимаю вашу точку зрения. Однако, даже если я не использую конвейер, разве он не сохранит значения ключей в памяти перед их отправкой, которые в конечном итоге будут использовать тот же объем памяти?

3. Давайте рассмотрим приблизительную оценку в качестве примера: если у нас есть 100 ключей по 1 МБ каждый, мы используем около 100 МБ оперативной памяти. Если мы запустим конвейер и запросим эти 100 ключей в том же конвейере, мы будем использовать 100 МБ ключей плюс 100 МБ буферизованных ответов, поэтому использование оперативной памяти увеличится до ~ 200 МБ. После закрытия конвейера буферизованные 100 МБ сбрасываются, а использование оперативной памяти возвращается к ~ 100 МБ.

Ответ №1:

«Если бы это был не Redis, я мог бы попробовать запросить параллельно и объединить результаты».

Вы все еще можете запрашивать параллельно. Создайте настройку с несколькими мастерами и разделите / распределите свои ключи по нескольким мастерам. Затем вы можете параллельно запрашивать данные у нескольких основных устройств.

Я также могу сказать вам по опыту, что нет ничего быстрее, чем redis, поскольку это полностью однопоточный процесс в памяти. Итак, # 2 в вашем вопросе крайне маловероятен.

Я бы предпочел изменить дизайн, т. Е. # 1. Если нет, то выполните настройку с несколькими мастерами и запрос параллельно.

Ответ №2:

Я не думаю, что вам следует запрашивать 1 миллион ключей одновременно. Вы должны создать кэш с кешем в памяти и кешем Redis.

Вы должны запросить как:

  • Поиск в локальном кэше
  • Запрашивайте Redis только для ключей, которые недоступны.

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

Даже после выполнения этого, если вы видите проблему с производительностью с одним узлом Redis, используйте master-replica. Учитывая количество имеющихся у вас ключей, вам нужно иметь более 10 сегментов или около того.