Диагностика и устранение медленных запросов Redis с помощью команды SLOWLOG

Используйте Redis SLOWLOG для поиска медленных команд, настройки порогов, проверки клиентов и замены дорогостоящих шаблонов доступа.

Диагностика и устранение медленных запросов Redis с помощью команды SLOWLOG

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

Определение первопричины начинается с Redis SLOWLOG. Он записывает команды, время выполнения которых на стороне сервера превышает пороговое значение, что помогает найти дорогостоящие команды, такие как KEYS, широкие LRANGE, большие HGETALL или медленные Lua-скрипты.

Понимание функции SLOWLOG в Redis

SLOWLOG — это система, которая регистрирует запросы, превышающие заданное время выполнения. По сути, это журнал в памяти команд, выполнение которых заняло больше времени, чем настроенный порог. В отличие от традиционного файлового журнала, SLOWLOG хранится непосредственно в памяти Redis, что обеспечивает быстрый доступ и управление без накладных расходов на дисковый ввод-вывод.

Каждая запись содержит уникальный идентификатор, временную метку Unix, время выполнения в микросекундах, аргументы команды, а в современных версиях Redis — адрес клиента и имя клиента, если они доступны. SLOWLOG измеряет выполнение команды внутри Redis; он не включает задержку сети, ожидание на стороне клиента или время, проведенное в очереди до начала выполнения команды Redis.

Как работает SLOWLOG: параметры конфигурации

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

slowlog-log-slower-than

Этот параметр определяет порог времени выполнения (в микросекундах) для регистрации команды. Будут записаны только те команды, выполнение которых заняло больше указанного значения. Установка слишком низкого значения может привести к регистрации слишком большого количества команд, потенциально потребляя значительный объем памяти и усложняя анализ. Установка слишком высокого значения может привести к пропуску действительно медленных запросов.

  • Значение по умолчанию: 10000 (10 миллисекунд)
  • Рекомендация: Начните со значения по умолчанию и корректируйте его в соответствии с требованиями к производительности вашего приложения. Для высокопроизводительных систем вы можете снизить его до 1000 микросекунд (1 миллисекунда) или даже до 100 микросекунд.
  • Особое значение: Установка значения 0 приведет к регистрации каждой команды. Установка отрицательного значения полностью отключит SLOWLOG.

Вы можете просмотреть текущее значение этого параметра:

redis-cli config get slowlog-log-slower-than

Чтобы установить новое значение (например, 5000 микросекунд или 5 миллисекунд):

redis-cli config set slowlog-log-slower-than 5000

Чтобы сделать это изменение постоянным, вам нужно обновить файл redis.conf или использовать CONFIG REWRITE, если это поддерживается вашей версией Redis и настройками.

slowlog-max-len

Этот параметр определяет максимальное количество записей, которое Redis будет хранить в SLOWLOG. Когда журнал достигает максимальной длины, новые записи приводят к автоматическому удалению самых старых записей (FIFO — первый пришел, первый ушел).

  • Значение по умолчанию: 128 записей
  • Рекомендация: Значение по умолчанию часто слишком мало для загруженных производственных систем. Рассмотрите возможность увеличения до 1024 или даже 4096, чтобы обеспечить достаточную историю для тщательного анализа, учитывая последствия для памяти.

Вы можете просмотреть текущее значение:

redis-cli config get slowlog-max-len

Чтобы установить новое значение (например, 1024 записи):

redis-cli config set slowlog-max-len 1024

Опять же, не забудьте сохранить это изменение в файле redis.conf.

Получение и анализ записей SLOWLOG

После настройки SLOWLOG вы можете взаимодействовать с ним с помощью набора команд.

SLOWLOG GET

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

  • SLOWLOG GET: Получает все записи, находящиеся в данный момент в журнале.
  • SLOWLOG GET <count>: Получает последние <count> записей.

Пример:

# Получить 10 последних записей медленного журнала
redis-cli slowlog get 10

Пример вывода (упрощен для ясности):

1) 1) (integer) 12345        # Уникальный идентификатор записи журнала
   2) (integer) 1678886400   # Временная метка Unix (например, 15 марта 2023 г., 12:00:00 UTC)
   3) (integer) 25000        # Время выполнения в микросекундах (25 мс)
   4) 1) "LRANGE"           # Команда
      2) "mybiglist"       # Аргумент 1
      3) "0"               # Аргумент 2
      4) "-1"              # Аргумент 3
   5) "127.0.0.1:54321"  # IP-адрес и порт клиента
   6) "client-name-app" # Имя клиента (если установлено)
...

SLOWLOG LEN

Эта команда возвращает текущее количество записей в SLOWLOG.

redis-cli slowlog len

Вывод:

(integer) 5

SLOWLOG RESET

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

redis-cli slowlog reset

Вывод:

OK

Интерпретация вывода SLOWLOG

Каждая запись предоставляет критически важную информацию:

  1. Уникальный идентификатор: Последовательный идентификатор. Полезен для отслеживания конкретных событий.
  2. Временная метка: Когда была выполнена команда. Помогает соотнести медленные запросы с изменениями в развертывании приложения или определенными периодами нагрузки.
  3. Время выполнения (микросекунды): Самый важный показатель. Он показывает, сколько времени заняло выполнение команды. Высокие значения указывают на потенциальное узкое место.
  4. Команда и аргументы: Точная команда Redis и ее параметры. Это важно для понимания того, какая операция была медленной (например, KEYS *, LRANGE 0 -1 для очень большого списка, SORT без LIMIT).
  5. Адрес клиента: IP-адрес и порт клиента, выполнившего команду. Помогает проследить до исходного приложения или службы.
  6. Имя клиента: Если ваше приложение устанавливает CLIENT SETNAME (настоятельно рекомендуется для лучшей наблюдаемости), это обеспечивает дополнительный уровень контекста, указывая, какая часть вашего приложения выполнила медленный запрос.

Практический пример: выявление медленной команды

Давайте смоделируем медленную команду и посмотрим, как SLOWLOG ее захватывает.

Сначала установите slowlog-log-slower-than на низкое значение для демонстрации, например, 1000 микросекунд (1 миллисекунда):

redis-cli config set slowlog-log-slower-than 1000

Затем выполните операцию, которая, как известно, может быть медленной при применении к большому набору данных, например KEYS * или LRANGE для списка с большим количеством элементов.

Давайте создадим большой список:

for i in {1..100000}; do redis-cli LPUSH mybiglist $i; done

Теперь выполните команду LRANGE, которая извлекает все элементы из этого большого списка:

redis-cli LRANGE mybiglist 0 -1

Эта команда, вероятно, займет более 1 миллисекунды.

Наконец, проверьте SLOWLOG:

redis-cli slowlog get 1

Вы должны увидеть вывод, похожий на этот (значения будут различаться):

1) 1) (integer) 12346
   2) (integer) 1678886450
   3) (integer) 15432 # Это наше медленное время выполнения в микросекундах
   4) 1) "LRANGE"
      2) "mybiglist"
      3) "0"
      4) "-1"
   5) "127.0.0.1:54322"
   6) ""

Вывод четко показывает команду LRANGE mybiglist 0 -1, время ее выполнения (15432 микросекунды или 15,432 мс) и когда она произошла. Это сразу говорит нам о том, что выборка всего большого списка занимает значительное время.

Стратегии устранения медленных запросов

После того как вы определили медленные запросы с помощью SLOWLOG, следующим шагом будет их оптимизация. Вот распространенные стратегии:

  1. Оптимизация структур данных и шаблонов доступа:

    • Избегайте команд O(N) для больших наборов данных: Команды типа LRANGE 0 -1 (получить все элементы), SMEMBERS (получить всех членов набора), HGETALL (получить все поля/значения хэша), SORT (без LIMIT) могут быть медленными. Если вам нужно обработать большие коллекции, рассмотрите возможность итерации с помощью SCAN, SSCAN, HSCAN или ZSCAN вместо получения всего сразу.
    • Используйте подходящие структуры данных: Например, если вам часто нужно получать атрибуты объекта, используйте Hash вместо хранения отдельных ключей для каждого атрибута.
    • Ограничивайте результаты: Для списков или отсортированных наборов используйте LRANGE <start> <end> или ZRANGE <start> <end> с разумными ограничениями вместо выборки всей структуры.
  2. Конвейеризация: Вместо отправки команд по одной, объединяйте несколько команд в один запрос с помощью конвейеризации. Это снижает накладные расходы на время кругового пути (RTT) по сети, что может значительно ускорить работу приложений, даже если отдельные команды быстрые.

    # Без конвейеризации (медленнее из-за нескольких RTT)
    r.set('key1', 'value1')
    r.set('key2', 'value2')
    
    # С конвейеризацией (быстрее, один RTT)
    pipe = r.pipeline()
    pipe.set('key1', 'value1')
    pipe.set('key2', 'value2')
    pipe.execute()
    
  3. Lua-скриптинг (EVAL): Для сложных операций, включающих несколько команд Redis, которые необходимо выполнять атомарно или с минимальным RTT, рассмотрите возможность использования Lua-скриптов. Скрипты выполняются непосредственно на сервере Redis, что снижает задержку в сети и обеспечивает атомарность. Однако длительные Lua-скрипты могут блокировать Redis, поэтому их необходимо тщательно оптимизировать.

  4. Избегайте KEYS в продакшене: Команда KEYS имеет сложность O(N) (где N — количество ключей в базе данных) и может заблокировать сервер Redis на длительное время, особенно в больших базах данных. Используйте SCAN для итерации по ключам в производственных средах. SCAN предоставляет функциональность, подобную итератору, которую можно приостанавливать и возобновлять, избегая длительных блокирующих операций.

    # Плохо в продакшене
    redis-cli KEYS *
    
    # Хорошо в продакшене для итерации
    redis-cli SCAN 0 MATCH user:* COUNT 100
    
  5. Пул соединений: Убедитесь, что ваше приложение использует правильный пул соединений для эффективного управления подключениями к Redis. Открытие и закрытие соединений для каждой команды может быть ресурсоемким.

  6. Шардинг и кластеризация: Если ваш набор данных или рабочая нагрузка превышает возможности одного экземпляра Redis, рассмотрите возможность шардинга данных по нескольким экземплярам Redis или использования Redis Cluster. Это распределяет нагрузку и данные, предотвращая превращение одного экземпляра в узкое место.

  7. Реплики для чтения: Для рабочих нагрузок с интенсивным чтением перенаправляйте запросы на чтение на реплики чтения Redis. Это масштабирует пропускную способность чтения и снижает нагрузку на основной экземпляр, позволяя ему сосредоточиться на записи.

Лучшие практики использования SLOWLOG

  • Регулярный мониторинг: Не настраивайте и не забывайте. Регулярно проверяйте записи SLOWLOG, особенно после развертываний или в периоды пиковой нагрузки.
  • Соответствующие пороги: Настройте slowlog-log-slower-than в зависимости от приемлемой задержки вашего приложения. То, что медленно для одного приложения, может быть нормой для другого.
  • Достаточная длина журнала: Установите slowlog-max-len достаточно большим, чтобы сохранить значимую историю, но не настолько большим, чтобы он потреблял чрезмерный объем памяти.
  • Периодическая очистка: Используйте SLOWLOG RESET после анализа записей, чтобы получить свежие данные, или рассмотрите возможность автоматизации этого процесса, если вы интегрируете SLOWLOG с системой мониторинга.
  • Именование клиентов: Используйте CLIENT SETNAME <name> в коде вашего приложения. Это добавляет ценный контекст к записям SLOWLOG, упрощая отслеживание медленных команд до конкретных частей вашего приложения.

Вывод

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