Содержание урока · 11 разделов
- Что такое Redis: хранилище в памяти для Go
- Зачем нужен redis: пять ролей в бэкенде
- Роли Redis одним списком
- Redis против Memcached и Postgres
- Три хранилища в одном сервисе
- Кейс из продакшена: что пропадёт при перезапуске Redis
- Клиент go-redis v9: стандарт в экосистеме Go
- Спорное мнение: не каждому Go-сервису нужен Redis
- Песочница урока
- Коротко: что запомнить
- Вопросы и ответы
Сценарий знакомый каждому, кто поддерживал продакшен: Go-сервис с одним Postgres, всё работает — до первой волны нагрузки. Страница профиля дёргает базу пять раз за рендер, отчёт на главной собирает агрегаты по секундам, а ночами ботовой трафик перемалывает одни и те же запросы, которые час назад уже были посчитаны. База честно отрабатывает каждую просьбу заново, CPU растёт, p95 ползёт вверх, и из кода виден единственный путь — добавить памяти Postgres. При этом половина этих вычислений вообще не обязана быть точной до миллисекунды: топ статей за час, сессия пользователя, лимит запросов к API — это данные, которые живут недолго, а читаются часто. Для них в архитектуре любого зрелого бэкенда есть второй этаж — быстрое хранилище в памяти. В экосистеме Go этим этажом почти всегда становится Redis, а его клиентом — библиотека go-redis, через которую мы будем работать весь курс. Полный план из двадцати пяти уроков лежит на странице курса; здесь же — карта местности без лишней теории.
Что такое Redis: хранилище в памяти для Go#
Redis — сервер баз данных, который держит данные в оперативной памяти, а не на диске: чтение и запись выполняются за доли миллисекунды, тогда как даже хорошо настроенная дисковая СУБД отвечает за миллисекунды и медленнее. Команды Redis обрабатываются по одной, в одном потоке: параллельные запросы от вашего Go-приложения выстраиваются в очередь, зато каждая операция атомарна — два инкремента счётчика из разных горутин не затрут друг друга, мьютексы не понадобятся. Отсюда два практических следствия. Первое: пропускная способность одного инстанса ограничена одним ядром, хотя на обычном железе это десятки и сотни тысяч простых операций в секунду — для кэша и сессий хватает почти всегда. Второе: длинные команды блокируют всех, поэтому перебор всей базы через KEYS или гигантские значения в Redis не тащат. Данные при этом не обязаны исчезать при перезагрузке: Redis умеет сохранять снимки на диск (RDB) и вести журнал изменений (AOF), после рестарта он восстанавливает состояние. Но помнить стоит главное: Redis — про скорость и недолговечные данные, а не про гарантии хранения.
Память дороже диска, а полную гарантию сохранности Redis не даёт: при аварии теряется всё, что не попало в последний снимок или журнал. Поэтому схема всегда одна: СУБД — источник правды, Redis — быстрая надстройка рядом. Записали заказ в Postgres, его же копию на время положили в Redis.
Зачем нужен redis: пять ролей в бэкенде#
Вопрос «зачем нужен redis» честнее отвечать задачами, а не определениями. Первая роль — кэш: тяжёлый SQL-запрос или ответ внешнего API кладётся в Redis на десять минут, и из десяти тысяч обращений до базы доходит десяток. Вторая — сессии: пользователь логинится, сервер пишет его данные в Redis, и любой из пяти инстансов бэкенда достаёт сессию по cookie — состояние больше не привязано к конкретной машине, балансировщик крутит трафик как хочет. Третья — счётчики и лимиты: просмотры статьи, попытки входа, rate limit — атомарные операции в один поток делают это безопасно и без блокировок. Четвёртая — очереди: списки и потоки Redis превращаются в простой механизм фоновых задач ровно до того момента, когда нагрузка оправдает Kafka. Пятая — рейтинги и тренды: сортированные множества хранят топ игроков с обновлением очка за одну команду. Заметьте закономерность: везде данные читаются часто, живут недолго и допускают восстановление после потери. Как только задача перестаёт этим свойствам соответствовать — возвращаемся в Postgres и не геройствуем.
Роли Redis одним списком#
- Кэш запросов и ответов: база получает десяток обращений вместо десяти тысяч.
- Сессии пользователей: состояние не привязано к конкретному инстансу бэкенда.
- Счётчики и лимиты: атомарный INCR без мьютексов и гонок.
- Очереди задач: списки и Streams как простой producer-consumer.
- Pub/Sub: рассылка событий всем подписчикам в реальном времени.
- Рейтинги и топы: сортированные множества с обновлением очка за одну команду.
Первый взгляд: go-redis в пяти строках
GOpackage main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
ctx := context.Background()
rdb.Set(ctx, "user:42:name", "Аня", time.Hour)
name, _ := rdb.Get(ctx, "user:42:name").Result()
fmt.Println(name) // Аня
}Не разбирайте пока каждую строку — это телепорт вперёд. redis.NewClient создаёт клиент с адресом сервера, ctx — контекст, который go-redis v9 требует в каждом вызове, Set кладёт значение со сроком жизни час, Get достаёт его обратно. Установку клиента, подключение и Ping разбираем в следующем уроке, а строки и сроки годности — в четвёртом и пятом.
Redis против Memcached и Postgres#
С Memcached Redis сравнивают реже, чем десять лет назад, но вопрос живой. Memcached — многопоточный кэш ключ-значение: очень быстрый, предельно простой, без структур данных, персистентности и каналов событий. Он до сих пор хорош, когда нужен тупой гигантский кэш строк и ничего больше. Redis умеет то же самое плюс структуры, срок жизни ключей с точностью до миллисекунд, снимки и журналы, репликацию и Pub/Sub — и берёт за это один процесс вместо десятка. С Postgres сравнение вообще не о скорости: это инструменты для разных слоёв архитектуры. Postgres — источник правды с транзакциями, внешними ключами и диском; Redis — слой скорости для недолговечных данных. Типичный зрелый сервис живёт с тремя хранилищами: Postgres для данных, Redis для горячего, поисковый движок для текстового поиска. Практическое правило, которое я применяю на code review: если потеря данных из хранилища ломает бизнес — это база; если просто заставит пользователей перелогиниться — Redis.
Три хранилища в одном сервисе#
| Хранилище | Где живут данные | Сильная сторона | Типовая роль |
|---|---|---|---|
| Redis | память плюс снимки и журнал на диске | структуры данных, скорость, Pub/Sub | кэш, сессии, счётчики, очереди |
| Memcached | только память | многопоточный простой кэш строк | большой плоский кэш без структур |
| Postgres | диск, журнал WAL | транзакции, ограничения, SQL | источник правды |
Кейс из продакшена: что пропадёт при перезапуске Redis#
Кейс, после которого одна команда пересмотрела всю схему хранения. В Redis жили кэш и сессии — но туда же по привычке положили корзину неавторизованного пользователя и черновик заявки: это же временные данные, у них есть TTL. В пятницу вечером оркестратор пересоздал ноду, Redis поднялся с пустой памятью — снимки на диск не были настроены, потому что там ничего важного. Кэш пережил бы это молча: он обязан уметь холодный старт. Но корзины пропали вместе с черновиками, саппорт собрал десяток тикетов, а команда потратила выходные на разбор. Разделение простое до безобразия: всё, чья потеря вызывает тикет, пишется в Postgres до того, как попадёт в Redis; Redis держит только то, что восстанавливается само — пересчётом из базы или повторным запросом. Сессии на грани: потерять их можно, пользователь просто перелогинится, но решать это нужно осознанно, а не по остаточному принципу.
Положили кэш через Set без срока годности — и через месяц столкнулись с заполненной памятью: Redis упрётся в лимит maxmemory и начнёт выселять ключи по политике LRU, включая те, что вы считали постоянными, либо начнёт отвечать ошибками на записи. Диагноз ставится задним числом и стоит ночного дежурства. Правило простое: у каждого кэш-ключа есть срок годности; как его ставить — пятый урок курса.
Клиент go-redis v9: стандарт в экосистеме Go#
За Go-кодом Redis стоит библиотека go-redis: проект вырос из личного репозитория автора и в 2022 году переехал в организацию redis на GitHub — с тех пор путь импорта выглядит как github.com/redis/go-redis/v9, и клиент числится рекомендуемым самой Redis. Девятая мажорная версия сделала контекст обязательным параметром каждой команды — примерно как database/sql давно живёт с context в сигнатурах. Для нас это значит: старые туториалы с вызовами rdb.Get(key) без контекста описывают восьмую версию, и копировать их сигнатуры не стоит. Альтернативы существуют — redigo старше и ближе к ручной работе с протоколом, rueidis моложе и агрессивнее по производительности, — но по количеству проектов, документации и ответов на Stack Overflow go-redis держит первое место, поэтому курс построен на нём. Установка и первое подключение к Redis из Go — тема следующего урока, а пока закончим обзор меню второго кода.
Три роли одной строкой
GO// счётчик просмотров статьи
rdb.Incr(ctx, "views:article:7")
// очередь: задача в конец списка
rdb.RPush(ctx, "jobs", "send-email:42")
// рейтинг: очки игрока в сортированном множестве
rdb.ZAdd(ctx, "leaderboard", &redis.Z{Score: 1500, Member: "user:42"})Это не программа, а меню: счётчик, очередь и рейтинг — по одной команде на роль. INCR атомарно увеличивает строку с числом, RPush кладёт задачу в конец списка, ZAdd записывает очко в сортированное множество. Каждый тип данных получит свой урок; здесь важно ощущение — типовая задача Redis решается одной строкой кода.
Спорное мнение: не каждому Go-сервису нужен Redis#
Спорное мнение, которое я защищаю на архитектурных созвонах: пока сервис один и трафик скромный, Redis можно не заводить вовсе. Инстанс — это не только память, но и новая точка отказа, мониторинг, бэкапы и ещё один участник дежурного чата; монолит вместо него держит горячие данные в карте с мьютексом, а тяжёлые запросы ускоряет индексом в Postgres. Граница применимости конкретная: как только инстансов становится два и больше, карта с мьютексом перестаёт работать — состояние нужно делить между процессами, и здесь Redis вне конкуренции. То же с фоновыми воркерами, очередями задач и распределёнными лимитами: один процесс решает их в памяти, несколько — уже про Redis. Проверка перед внедрением честная: назовите задачу, которую не решает текущая связка, и покажите, где она болит в цифрах. Ответа нет — не тащите второй этаж ради строчки в резюме.
Проверка: скорость Redis
Почему Redis отвечает за доли миллисекунды?
Проверка: ключи без срока годности
Кэш-ключи положили без TTL. Что произойдёт через месяцы?
Что выведет программа?
Прочитайте код и выберите, что он выведет:
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
ctx := context.Background()
rdb.Set(ctx, "greeting", "привет", 0)
val, err := rdb.Get(ctx, "greeting").Result()
fmt.Println(val, err)Соберите создание клиента
Допишите конструктор клиента, стандартный адрес и нулевую базу.
Соберите скелет работы с Redis
Расставьте строки в порядке работы программы: контекст, клиент, запись, чтение, вывод, закрытие.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Карточки: знакомство с Redis
Карта собрана: Redis — это кэш, сессии, счётчики, очереди и рейтинги в одном процессе, а go-redis v9 — способ добраться до всего этого из Go. Дальше по порядку: в уроке про установку и первое подключение соберём main.go с Ping, потом пройдёмся по типам данных Redis и дойдём до кэширования запросов, которое связывает курс с работой базы через GORM. Одна оговорка о формате: песочница сайта не умеет сеть и TCP-сокеты, поэтому redis-код в уроках не запускается в браузере — для реальной практики нужен локальный Go и Redis в Docker, обе установки занимают минуты и разбираются в следующем уроке. Домашнее задание — как раз про окружение.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Redis — хранилище в памяти: доли миллисекунды на операцию, один поток, атомарные команды.
- Главные роли: кэш, сессии, счётчики, очереди, Pub/Sub и рейтинги на ZSET.
- Postgres остаётся источником правды; Redis — слой скорости для недолговечных данных.
- Memcached — простой кэш строк; Redis добавляет структуры данных, TTL, персистентность и каналы.
- Клиент по умолчанию — go-redis v9 с контекстом в каждой команде.
- Кэш без TTL — источник утечки памяти: maxmemory и выселения придут за вами.
- Песочница не запускает redis-код: нужен локальный Go и Redis в Docker.
Домашнее задание
Подготовьте площадку: поставьте Go с go.dev и запустите Redis одной командой Docker — docker run --name go-redis-course -p 6379:6379 -d redis:7. Проверьте связь через docker exec -it go-redis-course redis-cli ping: в ответ должен прийти PONG. Песочница сайта для этого не подойдёт — нужен локальный запуск.
Личные заметкиПусто
Вопросы и ответы по уроку
Можно ли использовать Redis как основную базу данных?
Технически да — персистентность RDB и AOF существует, но по умолчанию Redis терпит потерю последних секунд данных и держит всё в памяти. Для заказов, платежей и профилей источником правды остаётся СУБД на диске вроде Postgres; Redis — слой скорости рядом с ней.
Сколько операций в секунду выдерживает Redis?
На обычном сервере один инстанс обрабатывает десятки и сотни тысяч простых операций в секунду — узкое место почти всегда сеть и приложение, а не Redis. Потолок упирается в одно ядро: команды выполняются в единственном потоке.
Почему go-redis, а не redigo или rueidis?
go-redis — рекомендуемый клиент с самой большой базой проектов и ответов; v9 даёт единый API с контекстом в каждой команде. Redigo ближе к ручной работе с протоколом, rueidis агрессивнее по производительности, но для обучения и типовых сервисов экосистема go-redis практичнее.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Изучайте дальше
Следующая ступень учебного пути
JWT-аутентификация в Go: golang-jwt и bcrypt
Разбираем JWT в Go: устройство токена, golang-jwt v5, подписи HMAC и RSA, refresh-токены, bcrypt, middleware авторизации и лучшие практики.
- Понимать анатомию JWT и почему payload не зашифрован
- Выпускать и проверять токены через golang-jwt v5
- Хешировать пароли bcrypt и сравнивать безопасно
- Писать middleware аутентификации для chi и Gin