> Почему Redis может отвечать медленно (Python)

Уровень: senior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: Sunlight

Стек: Python

> Пример ответа

Короткий ответ

Redis может отвечать медленно из-за блокирующих операций (KEYS, SMEMBERS на больших коллекциях), больших значений (big keys), частых fork при RDB-снапшотах, нехватки памяти с eviction, сетевых задержек, неправильной конфигурации (например, disable_thp=no) или конкуренции за CPU с другими процессами. Также часто причина - использование Redis как primary storage вместо кэша, что приводит к деградации при высокой нагрузке.

Подробное объяснение

Основные причины медленных ответов Redis:

  1. Блокирующие команды - O(N) операции по всей базе: KEYS, SMEMBERS, HGETALL на больших структурах, SORT, ZRANGEBYSCORE с большими диапазонами. Redis однопоточный, поэтому любая тяжёлая команда блокирует весь сервер.

  2. Big keys - значения размером более 1-10 МБ. Чтение и запись таких ключей занимает много времени, а также увеличивает сетевой трафик и память.

  3. Fork при персистентности - RDB-снапшоты и AOF rewrite вызывают fork процесса. При большом размере данных fork может занять секунды, и в это время Redis не отвечает (COW - copy-on-write).

  4. Eviction под давлением памяти - когда память заполнена, Redis начинает удалять ключи по политике eviction. При allkeys-lru это может вызывать задержки, особенно если ключей много.

  5. Сетевые проблемы - TCP backlog, медленные клиенты, отсутствие pipelining. Redis обрабатывает запросы быстро, но сеть может быть узким местом.

  6. Конфигурация ОС - transparent_hugepage включён, что увеличивает задержки при fork; своппинг (swap) Redis на диск; неправильные настройки vm.overcommit_memory.

  7. Конкуренция за ресурсы - Redis работает на той же машине с тяжёлыми приложениями, CPU или диск перегружены.

  8. Медленные Lua-скрипты - скрипты с циклами блокируют сервер.

  9. Неправильное использование - использование Redis для хранения больших объёмов данных без TTL, что приводит к росту памяти и eviction.

На практике

Диагностика начинается с SLOWLOG GET - он показывает команды, которые выполнялись дольше заданного порога (по умолчанию 10 мс). Также полезны:

  • INFO commandstats - статистика по командам, видно среднее время и количество вызовов.
  • INFO memory - проверка used_memory, fragmentation ratio.
  • redis-cli --bigkeys - поиск больших ключей.
  • MONITOR - но осторожно, он сам нагружает сервер.
  • Проверка latency: redis-cli --latency и --latency-history.

Типичный сценарий: приложение делает KEYS * для поиска по паттерну - это блокирует Redis на секунды при миллионах ключей. Решение - использовать SCAN или отдельный индекс.

Пример кода

PYTHON
import redis
import time
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
# Плохо: блокирующая команда
start = time.time()
keys = r.keys('user:*') # O(N) по всей базе
print(f"KEYS заняло: {time.time() - start:.3f}s")
# Хорошо: SCAN - не блокирует
start = time.time()
keys = []
cursor = 0
while True:
cursor, batch = r.scan(cursor, match='user:*', count=100)
keys.extend(batch)
if cursor == 0:
break
print(f"SCAN заняло: {time.time() - start:.3f}s")
# Плохо: большие значения
r.set('big_key', 'x' * 50_000_000) # 50 MB
start = time.time()
value = r.get('big_key')
print(f"GET big key заняло: {time.time() - start:.3f}s")
# Хорошо: использовать pipelining для множества мелких операций
pipe = r.pipeline()
for i in range(1000):
pipe.set(f'key:{i}', i)
pipe.execute()

Как отвечать на собеседовании

Начни с главного: Redis однопоточный, поэтому любая тяжёлая операция блокирует всё. Затем перечисли основные категории причин: команды, данные, инфраструктура, конфигурация. Для каждой причины дай конкретный пример и способ диагностики. Покажи, что знаешь инструменты: SLOWLOG, INFO, bigkeys. Упомяни trade-off между персистентностью и производительностью. Если спросят про конкретный случай - предложи алгоритм: замер latency, SLOWLOG, проверка памяти, сеть, CPU.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание однопоточной модели Redis и её следствий.
  • Знание инструментов диагностики и умение ими пользоваться.
  • Способность системно подходить к проблеме: от симптома к причине.
  • Понимание trade-off: персистентность vs скорость, память vs eviction.
  • Практический опыт: знает ли реальные кейсы, а не только теорию.
  • Умение отличать проблемы Redis от проблем сети или приложения.

Типичные ошибки

  • Называть только одну причину (например, только big keys) без системного анализа.
  • Предлагать KEYS как решение - это сразу показывает непонимание.
  • Игнорировать сетевой уровень и клиентскую сторону.
  • Не упоминать fork и COW при разговоре о персистентности.
  • Путать latency и throughput - это разные метрики.
  • Говорить "нужно больше памяти" без анализа eviction и TTL.
  • Не знать разницу между RDB и AOF в контексте производительности.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью