Что такое Redis и зачем используют этот инструмент?

Что такое Redis и зачем используют этот инструмент?
Redis рано или поздно появляется почти в каждом веб-проекте: как кеш, очередь фоновых задач, хранилище сессий или счётчик в реальном времени. В мире Rails он долгое время был обязательным спутником Sidekiq и Action Cable. В этой статье разберём, что такое Redis, как он работает, какие структуры данных предлагает, самые частые сценарии использования с примерами на Ruby и Rails, его ограничения, а также что изменилось с лицензией Redis и в Rails 8.
Что такое Redis?
Redis (REmote DIctionary Server) — это хранилище данных в оперативной памяти (in-memory). Он держит данные в RAM и обращается к ним по ключу, поэтому чтение и запись происходят очень быстро: типичная операция занимает заметно меньше миллисекунды.
Redis создал Сальваторе Санфилиппо в 2009 году. Его часто называют key-value базой данных, но это преуменьшение: Redis — это сервер структур данных. Значением может быть не только строка, но и список, хеш, множество, сортированное множество, поток и многое другое, а для каждого типа Redis предоставляет атомарные команды.
Почему Redis такой быстрый?
- Данные живут в памяти. При чтении нет обращений к диску.
- Простые и эффективные структуры данных, реализованные на C.
- Однопоточное выполнение команд. Команды выполняются по одной, поэтому внутри Redis нет блокировок и состояний гонки: каждая команда атомарна. Начиная с Redis 6, сетевой ввод-вывод может использовать дополнительные потоки, но сами команды по-прежнему выполняются последовательно.
- Лёгкий протокол (RESP) и поддержка конвейерной обработки (pipelining), которая позволяет клиенту отправить много команд за один сетевой обмен.
Основные типы данных
Тип Что это Типичное применение String Текст, число или бинарные данные до 512 МБ Кеш, счётчики, флаги List Упорядоченный список строк Простые очереди, последние элементы Hash Пары «поле–значение» внутри одного ключа Объекты, профили пользователей, настройки Set Уникальные неупорядоченные значения Теги, уникальные посетители, «кто лайкнул» Sorted set Уникальные значения с весом, отсортированные по весу Рейтинги, таблицы лидеров, планирование Stream Журнал событий, в который можно только дописывать Event sourcing, обработка сообщений Bitmap, HyperLogLog, Geo Специализированные структуры Флаги активности, приблизительный подсчёт уникальных, поиск поблизостиВ Redis 8 в основной дистрибутив также вошли JSON-документы, поиск и векторные множества, для которых раньше требовались отдельные модули.
Коротко о redis-cli
$ redis-cli
127.0.0.1:6379> SET greeting "Hello"
OK
127.0.0.1:6379> GET greeting
"Hello"
127.0.0.1:6379> SET session:abc123 "user_42" EX 3600 # истекает через 1 час
OK
127.0.0.1:6379> TTL session:abc123
(integer) 3600
127.0.0.1:6379> INCR page:views
(integer) 1
127.0.0.1:6379> HSET user:42 name "Anna" city "Warsaw"
(integer) 2
127.0.0.1:6379> HGETALL user:42
1) "name"
2) "Anna"
3) "city"
4) "Warsaw"
Одна из важнейших возможностей здесь — TTL (time to live, время жизни): любому ключу можно задать срок действия, после которого Redis удалит его автоматически. Это именно то, что нужно для кеша, сессий и временных токенов.
Зачем используют Redis? Основные сценарии
В Ruby с Redis работают через гем redis:
# Gemfile: gem "redis"
require "redis"
REDIS = Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0"))
1. Кеширование
Самый популярный сценарий. Тяжёлые SQL-запросы, результаты обращений к внешним API или отрендеренные фрагменты HTML сохраняются в Redis и при следующем запросе возвращаются мгновенно. В Rails достаточно настроить хранилище кеша:
# config/environments/production.rb
config.cache_store = :redis_cache_store, {
url: ENV.fetch("REDIS_URL", "redis://localhost:6379/1"),
expires_in: 1.day
}
# В любом месте приложения
def dashboard_stats
Rails.cache.fetch("dashboard/stats/#{Date.current}", expires_in: 10.minutes) do
{
users: User.count,
orders: Order.where(created_at: Date.current.all_day).count,
revenue: Order.paid.sum(:total)
}
end
end
Первый вызов выполняет запросы и сохраняет результат, а следующие вызовы в течение 10 минут читают его прямо из Redis.
2. Очереди фоновых задач
Sidekiq, самый популярный обработчик фоновых задач для Ruby, хранит свои очереди в Redis. Отправка писем, генерация отчётов, обработка изображений — всё это выносится из веб-запроса и выполняется воркерами.
# app/sidekiq/welcome_email_job.rb
class WelcomeEmailJob
include Sidekiq::Job
sidekiq_options queue: :mailers, retry: 5
def perform(user_id)
user = User.find(user_id)
UserMailer.with(user: user).welcome.deliver_now
end
end
# В контроллере или модели
WelcomeEmailJob.perform_async(user.id)
3. Сессии и временные данные
Хранение сессий в Redis позволяет нескольким серверам приложения разделять их, а TTL автоматически удаляет старые сессии. Тот же подход подходит для одноразовых кодов, токенов сброса пароля и ссылок подтверждения email.
4. Ограничение частоты запросов (rate limiting)
Атомарные счётчики с TTL позволяют легко ограничить количество запросов, например 100 обращений к API в минуту на пользователя:
class RateLimiter
def initialize(redis: REDIS, limit: 100, period: 60)
@redis = redis
@limit = limit
@period = period
end
def allowed?(identifier)
window = Time.now.to_i / @period
key = "rate:#{identifier}:#{window}"
count, _ = @redis.multi do |tx|
tx.incr(key)
tx.expire(key, @period)
end
count <= @limit
end
end
limiter = RateLimiter.new
limiter.allowed?("user:42") # => true
Поскольку INCR атомарен, это корректно работает, даже когда много серверов приложения одновременно обращаются к одному ключу. Начиная с Rails 7.2 в контроллерах есть встроенный метод rate_limit, который под капотом использует хранилище кеша.
5. Реальное время и pub/sub
Redis поддерживает модель «издатель–подписчик»: один процесс публикует сообщение в канал, и все подписчики мгновенно его получают. Action Cable использует это для доставки WebSocket-сообщений между несколькими серверами:
# config/cable.yml
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL", "redis://localhost:6379/2") %>
channel_prefix: myapp_production
6. Таблицы лидеров и рейтинги
Сортированные множества хранят элементы упорядоченными по весу, поэтому топ-10 — это одна команда:
REDIS.zincrby("leaderboard", 50, "anna")
REDIS.zincrby("leaderboard", 30, "oleg")
REDIS.zincrby("leaderboard", 70, "maria")
REDIS.zrevrange("leaderboard", 0, 9, with_scores: true)
# => [["maria", 70.0], ["anna", 50.0], ["oleg", 30.0]]
REDIS.zrevrank("leaderboard", "anna") # => 1 (позиция, начиная с 0)
7. Распределённые блокировки
Когда задача не должна выполняться дважды одновременно на нескольких серверах (например, импорт по расписанию), можно использовать блокировку на основе SET с опцией NX:
def with_lock(name, ttl: 30)
token = SecureRandom.uuid
acquired = REDIS.set("lock:#{name}", token, nx: true, ex: ttl)
return false unless acquired
begin
yield
ensure
# Удаляем блокировку, только если она всё ещё наша
REDIS.eval(<<~LUA, keys: ["lock:#{name}"], argv: [token])
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
end
return 0
LUA
end
end
with_lock("daily_import") { DailyImport.run }
Персистентность: теряет ли Redis данные при перезапуске?
Хотя Redis держит данные в памяти, он умеет сохранять их на диск:
- RDB (снимки): Redis периодически сохраняет полный снимок данных. Компактно и быстро восстанавливается, но изменения после последнего снимка могут потеряться.
- AOF (append-only file): каждая команда записи дописывается в журнал. Риск потери данных гораздо меньше (по умолчанию не более примерно одной секунды), но файл больше.
- Оба вместе: частый выбор, когда данные важны.
- Без персистентности: подходит для чистого кеша, который можно пересоздать.
Когда заканчивается память: вытеснение
Настройка maxmemory ограничивает объём RAM, который может использовать Redis, а maxmemory-policy определяет, что происходит при достижении лимита:
allkeys-lruилиallkeys-lfu— удалять ключи, которые дольше всего не использовались или используются реже всего. Хороший выбор для кеша.noeviction— отказывать в новых записях. Обязательно для Sidekiq и других очередей, потому что молча удалённые задачи гораздо хуже ошибки.
Поэтому в продакшене кеш и очередь задач часто держат в отдельных экземплярах Redis с разными настройками.
Установка Redis на Ubuntu
sudo apt update
sudo apt install redis-server
sudo systemctl enable --now redis-server
redis-cli ping # => PONG
Ключевые строки в /etc/redis/redis.conf:
bind 127.0.0.1 -::1 # слушать только localhost
protected-mode yes
requirepass a-long-random-password # или используйте ACL-пользователей
maxmemory 512mb
maxmemory-policy allkeys-lru # для кеша; noeviction для Sidekiq
appendonly yes # включить AOF, если данные важны
После изменения конфигурации перезапустите сервис: sudo systemctl restart redis-server.
Ограничения и подводные камни
- Оперативная память дорогая и ограниченная. Все данные должны помещаться в память, поэтому Redis не подходит для хранения больших объёмов данных.
- Не замена основной базе данных. Нет связей, SQL и сложных запросов, а гарантии сохранности слабее, чем у PostgreSQL или MySQL. Redis дополняет базу данных, а не заменяет её.
- Безопасность. Никогда не открывайте порт 6379 в интернет. Открытые экземпляры Redis без пароля регулярно находят и атакуют.
- Медленные команды блокируют всех. Так как команды выполняются по одной,
KEYS *на большой базе или огромныйSMEMBERSостановят всех остальных клиентов. ИспользуйтеSCANвместоKEYS. - Инвалидация кеша. Кеш может вернуть устаревшие данные. Тщательно продумывайте TTL и момент очистки ключей.
Redis, лицензии и Valkey
Много лет Redis распространялся под свободной лицензией BSD. В 2024 году Redis Inc. перешла на лицензии с открытым исходным кодом, но не open source (RSALv2 и SSPL). В ответ Linux Foundation и крупные облачные провайдеры создали Valkey — полностью открытый форк Redis 7.2, совместимый с клиентами и командами Redis.
В 2025 году с выходом Redis 8 в качестве одного из вариантов добавилась открытая лицензия AGPLv3. Сегодня активно развиваются и Redis, и Valkey. Для типичного Rails-приложения выбор редко важен: гем redis, Sidekiq и кеш Rails работают с обоими.
Нужен ли Redis в Rails 8?
В Rails 8 появилась тройка «Solid», которая по умолчанию использует основную базу данных вместо Redis:
- Solid Cache — кеш в таблице базы данных (на диске, поэтому может быть намного больше RAM).
- Solid Queue — фоновые задачи для Active Job.
- Solid Cable — адаптер для Action Cable.
Это значит, что новое Rails-приложение может работать вообще без Redis, что упрощает деплой на небольшой VPS. Redis по-прежнему отличный выбор, когда вам нужны:
- Sidekiq и его экосистема (возможности Pro/Enterprise, веб-интерфейс, множество плагинов);
- минимальные задержки для кеша и счётчиков;
- сортированные множества, потоки, pub/sub, атомарные счётчики, rate limiting и блокировки;
- очень высокая нагрузка с большим количеством WebSocket-сообщений в реальном времени.
Лучшие практики
- Всегда задавайте TTL для кеша и временных данных.
- Используйте понятные имена ключей с префиксами:
user:42:profile,rate:api:42. - Разделяйте кеш и очереди по разным экземплярам или хотя бы разным базам с подходящими политиками вытеснения.
- Настройте
maxmemory, чтобы Redis не занял всю память сервера. - Защищайте Redis: слушайте только localhost или приватную сеть, задайте пароль или ACL, используйте TLS между серверами.
- Избегайте
KEYSи огромных значений; используйтеSCANи держите значения небольшими. - Мониторьте:
INFO,SLOWLOG, использование памяти и процент попаданий в кеш. - Не храните единственную копию важных данных в Redis. Источником истины должна быть основная база данных.
Заключение
Redis — очень быстрое хранилище данных в памяти с богатыми структурами данных. Его используют для кеширования, очередей фоновых задач, сессий, ограничения частоты запросов, обмена сообщениями в реальном времени, рейтингов и распределённых блокировок. Он не заменяет реляционную базу данных, но берёт на себя всё, что должно быть быстрым, временным или общим для нескольких серверов. В Rails 8 можно начать без Redis благодаря Solid Cache, Solid Queue и Solid Cable, но с ростом нагрузки и требований Redis (или Valkey) остаётся одним из самых полезных инструментов веб-разработчика.
Назад



