ru:https://highload.today/blogs/redis-bolshoe-potreblenie-ram-i-pri-chem-tut-ttl/ ua:https://highload.today/uk/blogs/redis-bolshoe-potreblenie-ram-i-pri-chem-tut-ttl/
logo
Highload      22/03/2021

Redis: большое потребление RAM, и при чем тут TTL?

Назим Сулейманов BLOG

Team Lead в Jooble

Мы в Jooble активно используем Redis как кеш и быструю базу данных. У нас два master-slave-кластера, которые выполняют в среднем 12 000 операций в секунду. А дальше — история о том, как наш кластер стал падать по «out of memory», и о сложном поиске причины.

Предыстория

На тот момент в Redis кешировались в основном такие данные:

  • Пользовательские результаты поиска. Каждая запись занимает много памяти, с недолгим временем жизни (20 минут).
  • Части HTML. Каждая запись занимает много памяти, короткое время жизни (до 10 минут).
  • Тестовые группы пользователя. Мы используем A/B тесты (UI, тесты релевантности и т.д.) и в Redis храним розданные группы для пользователя. Записей очень много, и храним мы их долго (до 14 дней). Каждая запись имеет очень маленький размер.

В какой-то момент мы заметили, что наш кластер становится нестабильным. Redis часто падал по «out of memory».

Мы рассчитали, что на каждом из серверов должно быть занято около 20 Гб RAM. Вот только info memory показывала совсем другое. В пиковые моменты Redis занимал 80 Гб оперативной памяти:

used_memory:59681435584
used_memory_human:55.58G
used_memory_rss:65407717376
used_memory_rss_human:60.92G
used_memory_peak:85893162568
used_memory_peak_human:79.99G
total_system_memory:134991085568
total_system_memory_human:125.72G
used_memory_lua:71680
used_memory_lua_human:70.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.10
mem_allocator:jemalloc-3.6.0

Поиск проблемы

Вначале мы решили разобраться, из-за чего падал кластер. Redis занимал максимум 80 Гб RAM, но на сервере доступно 126 Гб. В чем тогда проблема?

Ответ нашли довольно быстро – это RDB Snapshots. В момент создания снепшота Redis делает fork() текущего процесса, а это может потребовать выделения дочернему процессу такого же количества памяти, как и у родителя.

Пока проблема с большим потреблением ОЗУ не была решена — мы просто выключили сохранение RDB-снепшотов.

Онлайн-курс "Android Developer" від robot_dreams.
Курс для всіх, хто хоче навчитися розробляти застосунки для Android з нуля, створити власний пет-проєкт для портфоліо та здобути професію, актуальну наступні 15–20 років.
Програма курсу і реєстрація

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

К счастью, свою утилиту для анализа писать не пришлось — мы воспользовались Redis Memory Analyzer и командой DEBUG OBJECT для этих целей.

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

Корень зла

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

Из документации мы знали, что Redis удаляет просроченные объекты двумя способами:

  1. Если вы запрашиваете просроченный объект, Redis его удаляет в этот же момент (пассивный механизм).
  2. Активный механизм очистки “устаревших” данных в бекграунде. Он работает постоянно.

Все указывало на то, что Redis Memory Analyzer активирует первый способ. Мы провели простой тест: просканировали все ключи в Redis и снизили объем потребляемой ОЗУ до ожидаемого размера (20 Гб).

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

Онлайн-курс "Маркетолог" від Laba.
Пройдіть повний шлях розробки маркетингових стратегій на практиці та з фідбеком від CEO бренд-маркетингової агенції.
Програма курсу і реєстрація

Документация к EXPIRE описывает активный механизм очистки ключей:

Redis 10 раз в секунду проделывает следующее:

1. Тестирует 20 случайных ключей из всего набора ключей в БД с проставленным TTL.

2. Удаляет все ключи с просроченным сроком жизни.

3. Если более 25% ключей удалены, возвращаемся к пункту 1.

Значит, большое количество долгоживущих ключей могло влиять на качество очистки ключей в целом.

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

В этот раз мы попали в точку:

  1. В Redis появилось очень много долгоживущих ключей (14 дней).
  2. Redis брал 20 случайных ключей, большая часть из которых относилась к «долгожителям». Алгоритм стал часто недобирать 25% удаленных ключей для запуска следующей итерации.
  3. В памяти стало хранится гораздо больше просроченных результатов поиска, которые зря занимают память.
  4. Мы получили большее потребление ОЗУ и нестабильный кластер.

Итоги

В результате для решения проблемы с очисткой ключей мы сделали следующее:

Психологічний профорієнтаційний тест для IT-фахівців від Ithillel.
Пройдіть психологічний профорієнтаційний тест для IT-фахівців щоб дізнатися ваші сильні сторони, вподобання і інтереси і з'ясувати, яка IT-спеціальність вам підходить.
Пройти тест
  1. Уменьшили время жизни этих записей.
  2. Перенесли долгоживущие записи в отдельную логическую DB в рамках того же Redis кластера. Таким образом, Redis проводит активную очистку в рамках каждой из логических баз, что в нашем случае агрессивнее очищает просроченые результаты поиска.
  3. Просканировали все ключи в Redis, чтобы очистить все просроченные (пассивный механизм очистки).

Теперь один экземпляр Redis занимает в 2-3 раза меньше места, как мы и ожидали изначально:

used_memory:23734192088
used_memory_human:22.10G
used_memory_rss:27195826176
used_memory_rss_human:25.33G
used_memory_peak:45282896632
used_memory_peak_human:42.17G
total_system_memory:134991085568
total_system_memory_human:125.72G
used_memory_lua:59392
used_memory_lua_human:58.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.15
mem_allocator:jemalloc-3.6.0

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Курс Python розробки від Mate academy.
Python — найпопулярніша мова 2024 року. Наш курс допоможе вам стати професіоналом, готовим до викликів сучасного IT ринку. Ви навчитеся створювати вебсайти, аналізувати дані, розробляти алгоритми, та навіть створювати штучний інтелект. .
Отримати деталі про курс

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: