Если Redis на проекте с Битриксом упёрся в лимит памяти, не спешите делать FLUSHDB: если сессии лежат в той же базе, он разлогинит всех пользователей и очистит корзины. Сначала найдите, чем именно забита память (redis-cli --bigkeys, INFO memory), потом удаляйте только мусорные ключи по маске через SCAN и UNLINK. В этом кейсе так освободилось 97% памяти без единой потерянной сессии.
Что случилось
Проект на Битриксе упёрся в лимиты железа хостинга. Redis занимал 977 МБ из доступного 1 ГБ, INFO memory показывал критическое заполнение. Политика вытеснения LRU не справлялась: теги записывались быстрее, чем Redis успевал выбрасывать старое.
Стандартный ответ админов в такой ситуации — FLUSHDB. Проблема в том, что он уничтожает и ключи пользовательских сессий: всех мгновенно разлогинивает, корзины пустеют. А после сброса первый утренний запрос к холодному кешу собирал страницу 10 секунд. То есть «лечение» било по пользователям дважды.
Почему Redis на Битриксе забивается
Битрикс кладёт в Redis не только сам кеш, но и служебные наборы тегов, по которым потом сбрасывает связанный кеш. Если каталог часто обновляется (импорт цен и остатков, правки товаров), таких наборов становится всё больше, и многие из них давно никому не нужны. Добавьте сюда сессии — и всё это живёт в одной памяти с одним лимитом.
Отдельная ловушка — политика вытеснения. Посмотреть её можно так:
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policyПри volatile-lru Redis вытесняет только ключи с заданным временем жизни, а ключи без TTL копятся бесконечно. При allkeys-lru под вытеснение попадает всё подряд — включая сессии, если они в том же экземпляре. Ни один вариант не хорош, пока кеш и сессии делят одну память.
Шаг 1. Понять, чем занята память
Не гадать, а смотреть:
# общая картина: used_memory_human, maxmemory_human
redis-cli INFO memory
# растёт ли вытеснение
redis-cli INFO stats | grep evicted_keys
# самые крупные ключи каждого типа, без блокировки сервера
redis-cli --bigkeys
# сколько весит конкретный ключ
redis-cli MEMORY USAGE "ключ"Если evicted_keys растёт — Redis уже выбрасывает данные под давлением, и выбрасывает не обязательно то, что вы хотели бы.
Аудит через --bigkeys в этом кейсе показал причину сразу: 84% ключей оказались протухшими наборами тегов.
Шаг 2. Удалять точечно, а не всё
Вместо полного сброса я написал bash-скрипт: он находит ключи по маске и удаляет их асинхронно через UNLINK. В отличие от DEL, UNLINK освобождает память в фоне и не блокирует основной поток Redis — для живого магазина это важно.
REDIS_CLI="/usr/bin/redis-cli"
# TODO: маски подберите под свой проект по результатам --bigkeys
$REDIS_CLI --scan --pattern '*IL:*' | xargs -L 100 $REDIS_CLI unlink
$REDIS_CLI --scan --pattern '*domain.com/public_html*' | xargs -L 100 $REDIS_CLI unlinkПочему именно --scan, а не KEYS: KEYS * проходит всю базу за один вызов и на большом объёме подвешивает Redis. SCAN идёт порциями, и сервер продолжает отвечать.
Перед первым запуском прогоните маску без удаления — посмотрите, что под неё попадает, и убедитесь, что там нет ключей сессий:
redis-cli --scan --pattern '*IL:*' | head -50
redis-cli --scan --pattern '*IL:*' | wc -lСкрипт поставил в cron на часы минимальной нагрузки.
Шаг 3. Не отдавать первым посетителям холодный кеш
Очистка — половина дела: после неё кеш пустой, и кто-то должен первым дождаться тяжёлой генерации. Я добавил прогрев: сервер читает sitemap и сам запрашивает нужные страницы через curl до прихода реальных посетителей.
# TODO: замените домен и число страниц под свой sitemap
urls=$(curl -s https://domain.com/sitemap.xml | grep -oP '(?<=<loc>).*?(?=</loc>)' | head -n 10)
for url in $urls; do
curl -s -L -o /dev/null "$url"
doneЗдесь греются первые страницы из sitemap. Для большого каталога прогрев надо строить иначе — с отбором разделов и троттлингом, подробно разбирал это в кейсе про каталог на 200 тыс. SKU.
Результат
- Освобождено 97% RAM — потребление упало с 688 МБ до 19 МБ
- Пользовательские сессии полностью сохранены при очистке
- Ответ сервера для первых посетителей сокращён до миллисекунд
- Остались на текущем тарифе хостинга, апгрейд железа не понадобился
Как настроить Redis для Битрикса, чтобы это не повторилось
Что советую проверить на любом проекте:
- Развести кеш и сессии. Минимум — разные базы Redis (
db 0под кеш,db 1под сессии), лучше — разные экземпляры со своими лимитами памяти. Тогда сброс кеша физически не может задеть сессии. - Выбрать политику под назначение. Для экземпляра с кешем подходит
allkeys-lru: выбросить старый кеш не страшно. Для сессий —noevictionи запас памяти: молча терять сессии хуже, чем получить ошибку записи. - Задать
maxmemoryявно. Без лимита Redis растёт, пока его не убьёт система. - Мониторить
used_memoryиevicted_keys. Рост вытеснений — ранний сигнал, задолго до того, как закончится память. - Регулярно чистить протухшие теги по маске, как выше, и держать прогрев после очистки.
FAQ
Можно ли сделать FLUSHDB в Redis на Битриксе? Только если вы точно знаете, что сессии хранятся в другой базе или другом экземпляре. Иначе FLUSHDB разлогинит всех пользователей и очистит корзины. Безопаснее удалять ключи по маске через SCAN и UNLINK.
Как узнать, чем забита память Redis?
Команда redis-cli INFO memory показывает общее потребление, redis-cli --bigkeys — самые крупные ключи по типам, MEMORY USAGE — вес конкретного ключа. Этого обычно хватает, чтобы найти виновника.
Чем UNLINK лучше DEL? UNLINK удаляет ключ из пространства имён сразу, а память освобождает в фоновом потоке. DEL делает всё синхронно и на больших ключах может заметно подвесить Redis.
Какую maxmemory-policy выбрать для Битрикса? Для кеша — allkeys-lru. Для сессий — noeviction с запасом памяти, и лучше в отдельном экземпляре Redis, чтобы вытеснение кеша не трогало сессии.