Redis быстрый, и именно поэтому его добавляют в проекты, которым он не был нужен. Это вторая служба, которую нужно установить, защитить, мониторить, рассчитать и из которой можно потерять данные, и место в проекте она должна заслужить, выполняя конкретную работу, с которой ничто из уже запущенного справляется плохо. «База данных медленная» - это не такая работа; обычно это отсутствующий индекс.
Есть четыре задачи, для которых он действительно подходящий инструмент, и у всех одна и та же форма: небольшие порции состояния, общие для нескольких процессов, потерю которых в неудачный день вы переживёте. Сессии, кэши, очереди и счётчики. Если ваша причина есть в этом списке, добавляйте. Если нет, эта статья сэкономит вам один демон. А если всё же добавите, запускать его придётся самим: продукта Redis здесь нет, поэтому вторая половина статьи о том, как установить, настроить и защитить его на машине, где у вас есть root.
Что такое Redis на самом деле#
Не кэш. Кэш - это одна из вещей, которые с его помощью можно построить. Redis - это сервер структур данных в памяти: он держит ваши данные в RAM, при желании пишет копию на диск и говорит на небольшом текстовом протоколе по TCP-порту 6379. Команды работают с типизированными структурами, а не с безликими блобами, и в этом вся польза.
| Тип | Что вы храните | Типичное применение |
|---|---|---|
| String | Байты или число | Кэшированный JSON, счётчики через INCR |
| Hash | Пары «поле - значение» | Сессия, запись о пользователе |
| List | Упорядоченная последовательность | Простая очередь на LPUSH и BRPOP |
| Set | Неупорядоченные уникальные элементы | Пользователи онлайн, дедупликация |
| Sorted set | Элементы с оценками | Таблицы лидеров, отложенные задачи, скользящие окна |
| Stream | Журнал только для добавления с идентификаторами | Конвейеры событий с группами потребителей |
Команды выполняются в одном потоке. Поэтому любая команда атомарна без каких-либо ваших усилий, и именно поэтому он так хорош для счётчиков и блокировок, а заодно и поэтому одна медленная команда блокирует всё остальное на сервере. KEYS * на миллионе ключей - это не медленный запрос, а короткая авария. Всегда используйте SCAN.
Второе определяющее свойство: всё живёт в памяти. Диск - это копия, а не хранилище. В этом источник и скорости, и риска, и именно поэтому «могу ли я это потерять?» - первый вопрос, который стоит задать о любых данных, которые вы туда кладёте.
Четыре задачи, ради которых его стоит добавлять#
Сессии, общие для нескольких процессов. Как только вы запускаете больше одного процесса приложения, состояние сессии внутри процесса перестаёт работать: пользователь входит на worker 1 и остаётся анонимом на worker 2. Общее хранилище сессий решает это одной строкой конфигурации. Это самая частая честная причина добавить Redis.
Кэш для чего-то действительно дорогого. Дорогое - это запрос, который не удаётся оптимизировать индексом, отчёт, агрегирующий миллион строк, или обращение к чужому API, за которое вы платите. Шаблон называется cache-aside: смотрим в кэш, а при промахе вычисляем значение и сохраняем его с продуманным TTL.
const key = `v1:report:${teamId}:${day}`;let report = await redis.get(key);if (!report) { report = JSON.stringify(await buildReport(teamId, day)); await redis.set(key, report, "EX", 900); // 15 minutes}Две детали отличают кэш от обузы. Ставьте в ключ префикс версии, чтобы смена формы значения означала смену префикса, а не сброс всего. И задавайте TTL всему, даже тому, что, как вам кажется, никогда не меняется, потому что кэш без срока годности - это второй источник истины, за которым никто не следит.
Очередь для работы, которая не должна выполняться во время запроса. Отправка почты, изменение размера изображения, обращение к медленной внешней службе. Запрос записывает задачу и возвращается; процесс-исполнитель подхватывает её. BullMQ на Node и Celery или RQ на Python работают поверх Redis и берут на себя повторные попытки, отложенный запуск и очередь недоставленных задач, которые вы иначе написали бы плохо.
Счётчики, которые должны быть общими. Классический случай - ограничение частоты запросов: счётчик внутри процесса умножает ваш лимит на число исполнителей и сбрасывается при каждом deploy. INCR со сроком жизни - это две команды, и они корректны для всех процессов сразу. В статье ограничение частоты: где ставить лимиты разобрано, что считать и по какому ключу.
Обратите внимание, чего на этой схеме нет: ничего такого, потерю чего вы бы пережили с трудом. Истиной по-прежнему владеет база данных.
Причины, которые не являются причинами#
«База данных медленная». Сначала выясните почему. Выполните запрос с EXPLAIN ANALYZE, найдите последовательное сканирование большой таблицы, добавьте индекс и измерьте снова. Кэширование запроса без индекса прячет проблему до тех пор, пока кэш не остынет - а это случается при deploy, при перезапуске и ровно в тот момент, когда трафик подскакивает и все промахи приходят сразу. Как читать EXPLAIN ANALYZE - это день, потраченный дешевле, чем эксплуатация кэша.
«Им пользуются все». У всех ещё и больше одного сервера, график дежурств и тестовое окружение.
«Будет быстрее». Обращение к локальному Redis занимает несколько десятых миллисекунды. Как и поиск по первичному ключу в PostgreSQL с прогретым кэшем. Если ваша страница открывается за 800 мс, то обращение к базе - не те самые 800 мс.
«Он нам всё равно понадобится». Добавить его позже - дело одного дня. Эксплуатировать его год, когда он не был нужен, - это год.
И одна настоящая опасность, а не слабый довод: хранить то, что нельзя потерять. Redis можно настроить на сохранение данных, но можно и наоборот; кэш с политикой вытеснения по замыслу выбросит ваши данные, когда память на исходе, а настройки сохранения по умолчанию теряют до секунды записей при жёсткой остановке. Если на вопрос «что случится, если этот ключ исчезнет» ответ «клиент пожалуется», то данные принадлежат PostgreSQL или MongoDB, а не сюда.
Что у вас уже есть без него#
Прежде чем добавлять службу, проверьте, не делают ли эту работу те, что уже запущены. Обычно делают, и в масштабах, далеко превосходящих те, до которых доходит большинство проектов.
- Сессии в одном процессе. Память процесса корректна и быстрее всего. При нескольких процессах подписанная cookie, несущая саму сессию, вообще не требует состояния на сервере, а таблица сессий в базе данных без труда справляется с тысячами пользователей.
- Кэширование перед страницей.
Cache-Control,ETagи правильно настроенный веб-сервер вообще не пускают запросы к вашему приложению, а это быстрее любого кэша, к которому может обратиться ваш код. Нужные заголовки описаны в статье заголовки HTTP-кэширования простыми словами. - Кэш внутри процесса. Ограниченный LRU внутри приложения -
lru-cacheна Node,functools.lru_cacheилиcachetoolsна Python - ничего не стоит, не требует сетевого обращения и подходит для всего небольшого, горячего и одинакового для всех пользователей, например для конфигурации или справочной таблицы. Его предел в том, что у каждого процесса своя копия. - Очередь в PostgreSQL.
SELECT ... FOR UPDATE SKIP LOCKEDдаёт корректную транзакционную очередь задач в таблице, и у неё есть свойство, которого нет у Redis: постановка задачи в очередь и фиксация данных, которые её породили, происходят в одной транзакции. На несколько сотен задач в минуту её более чем достаточно, а как это сделать, показано в статье фоновые задачи на небольшом сервере. - Ограничение частоты в веб-сервере.
limit_reqв nginx применяет лимит ещё до того, как в дело вступит ваше приложение, и не требует вообще никакого хранилища.
-- A queue that needs no second serviceUPDATE jobs SET status = 'running', started_at = now()WHERE id = ( SELECT id FROM jobs WHERE status = 'queued' AND run_after <= now() ORDER BY run_after FOR UPDATE SKIP LOCKED LIMIT 1)RETURNING id, payload;Установка Redis на VDS#
RE:NODE не продаёт Redis: линейка баз данных - это PostgreSQL и MongoDB, а тарифы для приложений запускают стартовую команду из вашего репозитория, а не второй демон. Так что Redis вы запускаете на машине, где у вас есть root, то есть на VDS или выделенном сервере. Это не шаг назад: один экземпляр Redis - одна из самых простых вещей в эксплуатации, а на вашей собственной машине он может слушать только интерфейс loopback, что убирает большинство способов, которыми что-то идёт не так. Взамен вы берёте на себя всю машину: патчи, файрвол, мониторинг и backup, о чём сказано в статье выбор между VDS и игровой панелью.
На Debian или Ubuntu:
$ sudo apt update && sudo apt install redis-server$ sudo systemctl enable --now redis-server$ redis-cli pingPONGПакет дистрибутива кладёт конфигурацию в /etc/redis/redis.conf, запускает его под systemd от пользователя redis и уже привязывает к localhost. Если нужна версия новее, чем в вашем дистрибутиве, проект Redis публикует собственные репозитории apt и rpm; на машине, где уже работают контейнеры, docker run с именованным томом ничуть не хуже - см. Docker на VDS.
Настройки, которые стоит изменить в первый же день, все лежат в /etc/redis/redis.conf:
bind 127.0.0.1 -::1protected-mode yesport 6379requirepass a-long-random-string-from-a-password-managermaxmemory 512mbmaxmemory-policy allkeys-lruappendonly yesappendfsync everysecsave 900 1save 300 10save 60 10000Затем две настройки ядра, на отсутствие которых Redis пожалуется в собственном логе. Overcommit памяти должен быть включён, иначе фоновое сохранение может не удаться на машине с малым запасом памяти; а transparent huge pages вызывают всплески задержки.
$ echo 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/99-redis.conf$ sudo sysctl -p /etc/sysctl.d/99-redis.conf$ cat /sys/kernel/mm/transparent_hugepage/enabledПосле перезапуска посмотрите лог командой journalctl -u redis-server и исправьте всё, о чём он предупреждает, а не ждите встречи с этим под нагрузкой. У первого часа на любой новой машине более широкий чек-лист - обновления, пользователь не root, ключи SSH, файрвол - он в статье первый час на новом VDS, а как удерживать рядом с ним собственное приложение, рассказано в статье службы systemd для ваших приложений.
Замечание об имени. В 2024 году Redis сменил лицензию, из-за чего и появился Valkey - форк под крылом Linux Foundation, а в 2025 году лицензирование снова изменилось. Для одного самостоятельно размещённого экземпляра ничто из этого на практике ничего не меняет: Valkey говорит на том же протоколе на том же порту, с теми же командами и тем же файлом конфигурации, и ваша клиентская библиотека не заметит, к какому из них подключилась.
Сохранение данных: RDB, AOF и что можно потерять#
Redis предлагает два механизма, и понимание разницы между ними - это разница между осознанным риском и неприятным сюрпризом.
Снимки RDB записывают весь набор данных в один файл через заданные промежутки, которыми управляют строки save выше - «через 900 секунд, если изменился хотя бы 1 ключ» и так далее. Снимок делается форком процесса, поэтому он дёшев по процессору и потенциально дорог по памяти: дочерний процесс с copy-on-write в худшем случае может потребовать почти столько же памяти ещё раз. Восстановление быстрое, а файл легко скопировать в другое место.
AOF, журнал только для добавления, записывает каждую команду записи по мере её выполнения и проигрывает журнал при запуске. appendfsync everysec - значение по умолчанию и разумный выбор: вы можете потерять до одной секунды записей при жёсткой остановке. always выполняет fsync на каждую запись и работает намного медленнее. no оставляет это ядру и может потерять десятки секунд.
Включайте оба. RDB даёт компактный файл, который можно унести как backup; AOF даёт куда меньшее окно потерь. Ни один из них не делает Redis системой учёта: штатное завершение сохраняет данные, а kill, отключение питания или остановка процесса ядром из-за нехватки памяти - нет. Арифметика здесь та же, что у любого другого хранилища с отложенной записью: данные, которые должны пережить сбой, принадлежат тому месту, где их зафиксировала транзакция, а копии, которые должны пережить сбой, - за пределами машины, о чём подробнее сказано в статье backup и восстановление баз данных.
Память, maxmemory и вытеснение#
maxmemory - самая важная настройка в файле, а её значение по умолчанию - «без ограничений», то есть Redis будет расти, пока не вмешается ядро. Задайте её явно, заметно ниже объёма памяти машины - хорошая отправная точка это половина, когда включено сохранение, - и выберите политику, соответствующую задаче.
| Политика | Что делает | Подходит для |
|---|---|---|
noeviction | Отклоняет записи с ошибкой, когда память заполнена | Очереди, сессии, которые нельзя терять |
allkeys-lru | Вытесняет ключ, к которому дольше всего не обращались | Чистый кэш |
allkeys-lfu | Вытесняет ключ, которым реже всего пользовались | Кэш с горячим подмножеством |
volatile-lru | Вытесняет давно не использовавшийся среди ключей с TTL | Смешанное использование, если TTL заданы |
volatile-ttl | Вытесняет ключ, который истекает раньше всех | Смешанное использование |
Ловушка - в двух последних строках. Политика volatile-* рассматривает только ключи, у которых задан срок жизни. Если ни у чего в вашей базе нет TTL, она ведёт себя точно как noeviction, и записи начинают падать с ошибкой нехватки памяти, пока сервер выглядит наполовину простаивающим. Либо задайте TTL всему кэшируемому, либо используйте allkeys-lru, а то, что нельзя терять, храните в другом месте.
Расчёт размера - это измерение, а не арифметика. У каждого ключа перед значением накладные расходы около ста байт, так что миллион крошечных ключей - совсем не маленький набор данных. Инструменты:
$ redis-cli info memory | grep -E 'used_memory_human|maxmemory_human'$ redis-cli info stats | grep -E 'evicted_keys|keyspace_hits|keyspace_misses'$ redis-cli --bigkeys$ redis-cli --latencyКоэффициент попаданий - число попаданий, делённое на сумму попаданий и промахов, - это то число, которое говорит, оправдывает ли кэш своё существование. Если он ниже примерно 80 процентов, что-то не так с вашими TTL или ключами. Растущий evicted_keys означает, что maxmemory слишком мал для рабочего набора, и это настоящий сигнал, в отличие от графиков процессора. Как выбирать именно такие числа, рассказано в статье мониторинг, который что-то вам сообщает.
Защита и ошибка, из-за которой серверы майнят#
Redis без аутентификации, доступный из интернета, - это не утечка, а shell. В набор команд входит смена рабочего каталога и имени файла дампа, так что злоумышленник может записать произвольный файл от имени пользователя Redis; классический вариант записывает ключ SSH в authorized_keys и заходит по нему. Автоматические сканеры находят открытые экземпляры в течение нескольких минут после их появления, а ставят они обычно майнер.
Защита короткая, и она не необязательная:
- Привяжите к localhost, если только чему-то на другой машине он действительно не нужен.
bind 127.0.0.1 -::1- значение по умолчанию в большинстве пакетов; не трогайте его. Если другому хосту нужно подключаться, используйте приватный интерфейс или SSH-туннель, но никогда не публичный адрес. - Задайте `requirepass` длинным случайным значением и храните его в окружении вашего приложения, а не в репозитории - где ему место, описано в статье переменные окружения и секреты.
- Закройте порт на файрволе. Входящий трафик запрещён по умолчанию, разрешены несколько портов, которые вы собирались публиковать, и
6379среди них нет. Правила есть в руководстве по файрволу UFW. - Используйте пользователей ACL, если клиентов больше одного приложения. Redis 6 и новее умеет выдавать каждому клиенту имя пользователя с ограниченным набором команд, так что ваше веб-приложение не сможет вызвать
CONFIGилиFLUSHALL, даже если его взломают. - Никогда не выставляйте его через обратный прокси. Redis говорит на собственном протоколе, а не на HTTP, и то, что он окажется за веб-сервером, безопасным его не делает.
Оставленный protected-mode yes - полезная страховка: без пароля и без явного bind Redis отказывается принимать подключения откуда-либо, кроме интерфейса loopback. Это ремень безопасности, а не стратегия.
FAQ#
Нужен ли Redis для небольшого сайта?
Почти наверняка нет. Один процесс приложения с кэшем внутри процесса, заголовки HTTP-кэширования впереди и правильно проиндексированная база данных покрывают сайт с тысячами посетителей в день. Добавляйте Redis, когда у вас больше одного процесса, которым нужно общее состояние, или есть задача, которую хочется убрать из пути запроса.
Можно ли использовать Redis как основную базу данных?
Можно, и большинству не стоит. В нём есть сохранение данных, но настройки по умолчанию теряют до секунды записей при жёсткой остановке, политика вытеснения может удалять ключи по замыслу, а всё должно помещаться в память. Используйте его для состояния, которое можно восстановить, а важные записи держите в базе данных, которая фиксирует транзакции на диске.
Где запускать Redis, если мой хостинг его не продаёт?
На машине, где у вас есть root: на VDS или выделенном сервере. Установите пакет дистрибутива, привяжите его к localhost, задайте пароль и лимит maxmemory и пусть ваше приложение подключается через интерфейс loopback. Это ещё и самая безопасная из доступных конфигураций, потому что порт вообще никогда не выставляется наружу.
Redis или Valkey?
Для одного самостоятельно размещённого экземпляра подойдёт любой. Valkey - это форк под Linux Foundation, созданный после смены лицензии в 2024 году; он говорит на том же протоколе, использует тот же файл конфигурации и работает с теми же клиентами. Берите тот, что есть в пакетах вашего дистрибутива, и идите дальше.
Сколько памяти ему выделить?
Достаточно для вашего рабочего набора плюс накладные расходы и не больше примерно половины машины, потому что фоновое сохранение делает форк процесса, и копии на короткое время может понадобиться много дополнительной памяти. Задайте maxmemory явно, следите за evicted_keys и поднимайте лимит, когда это число начнёт расти.
Почему мои записи падают с ошибкой нехватки памяти?
Потому что maxmemory достигнут, а политика ничего не вытесняет. Либо политика noeviction, либо это политика volatile-*, а ни у одного из ваших ключей нет TTL, что равносильно тому же. Задайте TTL, переключитесь на allkeys-lru или поднимите лимит.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.