Почему Redis медленный? Обнаружение и анализ общей проблемы с задержкой

Redis задняя часть

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

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

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

Используйте сложные команды

Как устранить неполадки, если задержка доступа внезапно увеличивается при использовании Redis?

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

Во-первых, установите порог медленного журнала Redis. Будут записаны только команды, которые превышают порог. Единица измерения здесь тонкая. Например, установите порог медленного журнала на 5 миллисекунд и установите только последние 1000 записей медленного журнала, которые будут сохранены. :

# 命令执行超过5毫秒记录慢日志
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近1000条慢日志
CONFIG SET slowlog-max-len 1000

После завершения настройки все выполняемые команды будут записываться Redis, если задержка больше 5 миллисекунд.SLOWLOG get 5Запросите последние 5 медленных журналов:

127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693       # 慢日志ID
   2) (integer) 1593763337  # 执行时间
   3) (integer) 5299        # 执行耗时(微妙)
   4) 1) "LRANGE"           # 具体执行的命令和参数
      2) "user_list_2000"
      3) "0"
      4) "-1"
2) 1) (integer) 32692
   2) (integer) 1593763337
   3) (integer) 5044
   4) 1) "GET"
      2) "book_price_1000"
...

Просматривая записи журнала медленных операций, мы можем узнать, какие команды и в какое время требуют много времени для выполнения.часто используемыйO(N)Команды вышеуказанной сложности,Напримерsort,sunion,zunionstoreили при выполненииO(N)Объем данных, обрабатываемых командой, относительно велик, и в этих случаях Redis потребуется много времени для обработки данных.

Если объем запросов на обслуживание невелик, но использование ЦП экземпляром Redis велико, это может быть вызвано использованием сложных команд.

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

хранить большие ключи

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

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

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

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

Итак, есть ли способ проверить, существуют ли сейчас данные bigkey в Redis?

Redis также предоставляет способ сканирования больших ключей:

redis-cli -h $host -p $port --bigkeys -i 0.01

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

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

Принцип использования этой команды на самом деле заключается в том, что Redis выполняет ее внутри.scanКоманда, проход по всем ключам, а затем выполнение для разных типов ключейstrlen,llen,hlen,scard,zcardчтобы получить длину строки и количество элементов типа контейнера (list/dict/set/zset).

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

В ответ на проблему bigkey Redis официально запустили в версии 4.0.lazy-freeЭтот механизм используется для асинхронного освобождения памяти большого ключа и уменьшения влияния на производительность Redis. Тем не менее, мы не рекомендуем использовать bigkey, так как Bigkey повлияет на производительность миграции во время миграции кластера, об этом будет подробно рассказано далее в статьях, посвященных кластеру.

Централизованное истечение

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

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

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

Стратегия истечения срока действия Redis использует две стратегии: активное истечение и отложенное истечение:

  • Активный срок действия: Redis поддерживает запланированную задачу внутри. По умолчанию 20 ключей случайным образом извлекаются из словаря с истекшим сроком действия каждые 100 миллисекунд, а ключи с истекшим сроком действия удаляются. Если доля ключей с истекшим сроком действия превышает 25%, продолжайте получать 20 ключей и удалять просроченные keys.key, цикл повторяется, пока процент просроченных ключей не упадет до 25% или выполнение этой задачи займет более 25 миллисекунд, цикл будет прерван
  • Ленивое истечение срока действия: только при доступе к ключу оценивается, истек ли срок действия ключа, и если срок его действия истек, он будет удален из экземпляра.

Уведомление,Активные задачи Redis с истекшим сроком действия также выполняются в основном потоке Redis., то есть если есть необходимость удалить большое количество просроченных ключей в процессе выполнения активной истечения, то при бизнес-доступе необходимо дождаться истечения срока действия задачи перед обработкой бизнес-запроса. В этот момент возникает проблема увеличения задержки доступа к сервису с максимальной задержкой 25 миллисекунд.

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

На этом этапе вам нужно проверить свой бизнес, чтобы увидеть, действительно ли существует централизованный код с истекшим сроком действия.Как правило, команда, используемая для централизованного истечения срока действия,expireatилиpexpireatкоманду, вы можете искать это ключевое слово в коде.

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

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

Псевдокод можно записать так:

# 在过期时间点之后的5分钟内随机过期掉
redis.expireat(key, expire_time + random(300))

Таким образом, Redis не будет блокировать основной поток из-за чрезмерного давления, вызванного централизованным удалением ключей при обработке истечения срока действия.

Кроме того, в дополнение к необходимости обратить внимание на эту проблему при использовании в бизнесе, эту ситуацию также можно вовремя обнаружить посредством эксплуатации и обслуживания.

Практика такова, что нам нужно следить за различными рабочими данными Redis и выполнятьinfoВы можете получить все текущие данные, здесь мы должны сосредоточиться наexpired_keysЭтот элемент представляет совокупное количество ключей с истекшим сроком действия, удаленных всем экземпляром на данный момент.

Нам нужно следить за этим показателем, когдаЗа очень короткий промежуток времени этот показатель резко выросКогда вам нужно быстро подать сигнал тревоги, сравните момент времени в бизнесе медленнее, время подтверждения будет постоянным, если оно будет постоянным, его можно учитывать, потому что это приводит к задержке.

Память экземпляра достигла верхнего предела

Иногда, когда мы используем Redis в качестве чистого кеша, мы устанавливаем лимит памяти для экземпляра.maxmemory, а затем включите стратегию исключения LRU.

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

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

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

  • allkeys-lru: удалить ключ, к которому недавно обращались, независимо от того, установлен ли срок действия ключа.
  • volatile-lru: удалить только ключи, к которым недавно обращались, и установить ключи с истекшим сроком действия
  • allkeys-random: независимо от того, установлен ли срок действия ключа или нет, он будет удален случайным образом.
  • Нестабильные-случайные: только случайно устраняют ключи с истечением срока
  • allkeys-ttl: независимо от того, истек ли срок действия ключа, срок действия ключа истек
  • noeviction: не удаляйте ключ, пишите сразу после полного заполнения и сообщайте об ошибке
  • allkeys-lfu: независимо от того, установлен ли срок действия ключа или нет, ключ с наименьшей частотой доступа исключается (поддержка 4.0+)
  • volatile-lfu: удалять только просроченные ключи с наименьшей частотой доступа (поддержка 4.0+)

Какую стратегию использовать, зависит от бизнес-сценария.

Те, которые мы используем чаще всего, этоallkeys-lruилиvolatile-lruСтратегия, их логика обработки состоит в том, чтобы каждый раз случайным образом извлекать пакет ключей (настраиваемый) из экземпляра, затем удалять наименее доступный ключ, а затем временно сохранять оставшиеся ключи в пуле и продолжать случайным образом извлекать пакет ключей. keys и сравнить его с ключом в предыдущем пуле, а затем исключить ключ с наименьшим доступом. Повторяйте это, пока память не упадет доmaxmemoryпод.

При использованииallkeys-randomилиvolatile-randomстратегия, то это будет намного быстрее, потому что это случайное исключение, поэтому оно сократит время, затрачиваемое на сравнение частоты доступа к ключу, и вы можете напрямую исключить пакет ключей после случайного извлечения пакета ключей, поэтому эта стратегия быстрее, чем описанная выше стратегия LRU.

Но приведенная выше логика при доступе к Redis,Выполняется до выполнения реальной команды, то есть это влияет на команды, которые мы выполняем при доступе к Redis.

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

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

вилка отнимает много времени

Если в вашем Redis включена функция автоматического создания перезаписей RDB и AOF, это может увеличить задержку доступа Redis при создании перезаписей RDB и AOF в фоновом режиме, и после выполнения этих задач задержка исчезнет.

В этом случае это обычно вызвано выполнением задачи генерации RDB и перезаписи AOF.

Для создания RDB и AOF требуется родительский процесс.forkРебенок обрабатывает постоянные данные,существуетforkВ процессе выполнения родительский процесс должен скопировать таблицу страниц памяти в дочерний процесс. Если весь экземпляр занимает большой объем памяти, копирование таблицы страниц памяти, которую необходимо скопировать, займет много времени. много ресурсов процессора.forkРаньше весь инстанс был заблокирован и не мог обрабатывать никакие запросы.forkВремени будет больше, даже до второго уровня. Это может серьезно повлиять на производительность Redis..

мы можем выполнитьinfoкоманда, просмотреть последнийforkвремя для выполненияlatest_fork_usec, единица тонкая. Это время, когда весь экземпляр заблокирован и не может обработать запрос.

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

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

Кроме того,forkЗатраты времени также связаны с системой, если Redis развернут на виртуальной машине, это время также увеличится. Поэтому рекомендуется выполнять развертывание на физической машине при использовании Redis, чтобы уменьшитьforkВлияние.

связанный ЦП

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

Но при использовании Redis мы не рекомендуем этого делать по следующим причинам.

Redis, привязанный к ЦП, при сохранении данных,forkИз дочернего процесса дочерний процесс унаследует настройки использования ЦП родительского процесса.В это время дочерний процесс будет потреблять много ресурсов ЦП для сохранения данных, и дочерний процесс будет конкурировать с основным процессом за ЦП. , что также приведет к увеличению задержки доступа к основному процессу Недостаточно ресурсов ЦП.

Поэтому при развертывании процесса Redis, если вам нужно включить механизмы перезаписи RDB и AOF, вы не должны выполнять операции привязки ЦП!

Необоснованное сотрудничество с AOF

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

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

Чтобы обеспечить безопасность файлов, записываемых на диск, AOF предоставляет 3 типа механизмов сброса:

  • appendfsync always: Диск сбрасывается каждый раз при записи, что оказывает наибольшее влияние на производительность, занимает большое количество дисковых операций ввода-вывода и обеспечивает максимальную безопасность данных.
  • appendfsync everysec: сбрасывать диск каждую секунду, что относительно мало влияет на производительность и приводит к потере до 1 секунды данных, когда узел не работает.
  • appendfsync no: Очистить диск в соответствии с механизмом операционной системы, который оказывает наименьшее влияние на производительность, низкий уровень безопасности данных и потерю данных из-за простоя узла зависит от механизма очистки операционной системы.

При использовании первого механизмаappendfsync alwaysКогда Redis обрабатывает команду записи, она записывает команду на диск иЭта операция выполняется в основном потоке.

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

В отличие от первого механизма,appendfsync everysecбудет обновлять диск каждую 1 секунду, иappendfsync noВ зависимости от времени перепрошивки операционной системы безопасность невысока. Поэтому мы рекомендуем использоватьappendfsync everysecТаким образом, в худшем случае будет потеряна только 1 секунда данных, но при этом может поддерживаться хорошая производительность доступа.

Конечно, для некоторых бизнес-сценариев он не чувствителен к потере данных, и AOF может быть не включен.

Использовать обмен

Если вы обнаружите, что Redis внезапно стал очень медленным,Каждый доступ занимает сотни миллисекунд или даже секунд, затем проверьте, использует ли Redis Swap.В этом случае Redis в принципе не может предоставлять высокопроизводительные сервисы.

Мы знаем, что операционная система предоставляет механизм Swap, целью которого является изменение части данных в памяти на диск, когда памяти недостаточно, чтобы добиться буферизации использования памяти.

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

Особенно для высокопроизводительной базы данных в памяти, такой как Redis, если память в Redis подкачивается на диск, это время операции неприемлемо для чувствительной к производительности базы данных, такой как Redis.

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

Если вы используете Swap, вам нужно организовать пространство памяти во времени, освободить достаточно памяти для использования Redis, а затем освободить Swap Redis, чтобы позволить Redis повторно использовать память.

Процесс выпуска Swap Redis обычно требует перезапуска экземпляра.Чтобы избежать влияния перезапуска экземпляра на бизнес, обычно сначала выполняется переключение master-slave, затем освобождается swap старого главного узла, и служба перезапущена.После завершения синхронизации данных переключиться обратно на главный узел.Можно.

Видно, что когда Redis использует Swap, высокая производительность Redis в это время в основном упраздняется, поэтому нам нужно заранее предотвратить эту ситуацию.

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

Сетевая карта перегружена

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

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

Если нагрузка на сетевую карту слишком высока, на сетевом уровне и на уровне TCP будет происходить задержка передачи данных и потеря пакетов данных. Помимо памяти, высокая производительность Redis заключается в сетевом вводе-выводе, резкое увеличение объема запросов приведет к увеличению нагрузки на сетевую карту.

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

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

Суммировать

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

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

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

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

Обратите внимание на публичный аккаунт WeChat: Songhua сказал, становитесь более захватывающим!

Адрес блога:www.liangsonghua.com

Введение в общедоступную учетную запись: делитесь техническими знаниями о работе на JD.com, а также технологиями JAVA и лучшими отраслевыми практиками, большинство из которых являются прагматичными, понятными и воспроизводимыми.