Рубріки: Highload

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

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

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

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

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

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

Корень зла

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итоги

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

  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.

Останні статті

Токсичные коллеги. Как не стать одним из них и прекратить ныть

В благословенные офисные времена, когда не было большой войны и коронавируса, люди гораздо больше общались…

07.12.2023

Делать что-то впервые всегда очень трудно. Две истории о начале карьеры PM

Вот две истории из собственного опыта, с тех пор, когда только начинал делать свою карьеру…

04.12.2023

«Тыжпрограммист». Как люди не из ІТ-отрасли обесценивают профессию

«Ты же программист». За свою жизнь я много раз слышал эту фразу. От всех. Кто…

15.11.2023

Почему чат GitHub Copilot лучше для разработчиков, чем ChatGPT

Отличные новости! Если вы пропустили, GitHub Copilot — это уже не отдельный продукт, а набор…

13.11.2023

Как мы используем ИИ и Low-Code технологии для разработки IT-продукта

Несколько месяцев назад мы с командой Promodo (агентство инвестировало в продукт более $100 000) запустили…

07.11.2023

Университет или курсы. Что лучше для получения IT-образования

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

19.10.2023