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-снепшотов.

Онлайн-курс "Корпоративна культура" від Laba.
Як з нуля побудувати стабільну корпоративну культуру, систему внутрішньої комунікації та бренд роботодавця, з якими ви підвищите продуктивність команди, — пояснить HR-директор Work.ua.
Детальніше про курс

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

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

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

Корень зла

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

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

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

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

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

Онлайн-курс "Тестування API" від robot_dreams.
Навчіться працювати з API на просунутому рівні та проводити навантажувальні тестування, щоб виявляти потенційні проблеми на ранніх етапах розробки.
Програма курсу і реєстрація

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

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

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

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

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

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

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

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

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

Итоги

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

Онлайн-курс "Чистий код та патерни проєктування" від robot_dreams.
Прискорюйте й спрощуйте процес розробки.Під менторством лектора з 15-річним досвідом ви навчитеся застосовувати 20+ шаблонів, опануєте рефакторинг і принципи чистого коду.
Детальніше
  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 для школярів від Ithillel.
Відкрийте для вашої дитини захопливий світ програмування з нашим онлайн-курсом "Програмування Python для школярів". Ми вивчимо основи програмування на прикладі мови Python, надаючи зрозумілі пояснення та цікаві практичні завдання.
Зареєструватися

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

Топ-5 самых популярных блогеров марта

PHP Developer в ScrumLaunch
Всего просмотровВсего просмотров
2434
#1
Всего просмотровВсего просмотров
2434
Founder at Shallwe, Python Software Engineer (Django/React)
Всего просмотровВсего просмотров
113
#2
Всего просмотровВсего просмотров
113
Career Consultant в GoIT
Всего просмотровВсего просмотров
95
#3
Всего просмотровВсего просмотров
95
CEO & Founder в Trustee
Всего просмотровВсего просмотров
94
#4
Всего просмотровВсего просмотров
94
Рейтинг блогеров

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

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

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