Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 1 из 25 ~16 мин +20 XP

Знакомство: зачем Go-сервису Redis

Зачем нужен redis в Go-сервисе — вопрос, который встаёт, как только API начинает тормозить на запросах к базе, а сессиям пользователей некуда деться. Redis — хранилище в памяти с ответами за доли миллисекунды, и в этом уроке разберём его роли: кэш, сессии, счётчики, очереди и рейтинги. Заодно пройдёмся по границам: где Redis незаменим, а где превращается в лишнюю зависимость.

Содержание урока · 11 разделов

Сценарий знакомый каждому, кто поддерживал продакшен: Go-сервис с одним Postgres, всё работает — до первой волны нагрузки. Страница профиля дёргает базу пять раз за рендер, отчёт на главной собирает агрегаты по секундам, а ночами ботовой трафик перемалывает одни и те же запросы, которые час назад уже были посчитаны. База честно отрабатывает каждую просьбу заново, CPU растёт, p95 ползёт вверх, и из кода виден единственный путь — добавить памяти Postgres. При этом половина этих вычислений вообще не обязана быть точной до миллисекунды: топ статей за час, сессия пользователя, лимит запросов к API — это данные, которые живут недолго, а читаются часто. Для них в архитектуре любого зрелого бэкенда есть второй этаж — быстрое хранилище в памяти. В экосистеме Go этим этажом почти всегда становится Redis, а его клиентом — библиотека go-redis, через которую мы будем работать весь курс. Полный план из двадцати пяти уроков лежит на странице курса; здесь же — карта местности без лишней теории.

Что такое Redis: хранилище в памяти для Go#

Redis — сервер баз данных, который держит данные в оперативной памяти, а не на диске: чтение и запись выполняются за доли миллисекунды, тогда как даже хорошо настроенная дисковая СУБД отвечает за миллисекунды и медленнее. Команды Redis обрабатываются по одной, в одном потоке: параллельные запросы от вашего Go-приложения выстраиваются в очередь, зато каждая операция атомарна — два инкремента счётчика из разных горутин не затрут друг друга, мьютексы не понадобятся. Отсюда два практических следствия. Первое: пропускная способность одного инстанса ограничена одним ядром, хотя на обычном железе это десятки и сотни тысяч простых операций в секунду — для кэша и сессий хватает почти всегда. Второе: длинные команды блокируют всех, поэтому перебор всей базы через KEYS или гигантские значения в Redis не тащат. Данные при этом не обязаны исчезать при перезагрузке: Redis умеет сохранять снимки на диск (RDB) и вести журнал изменений (AOF), после рестарта он восстанавливает состояние. Но помнить стоит главное: Redis — про скорость и недолговечные данные, а не про гарантии хранения.

Зачем нужен redis: пять ролей в бэкенде#

Вопрос «зачем нужен redis» честнее отвечать задачами, а не определениями. Первая роль — кэш: тяжёлый SQL-запрос или ответ внешнего API кладётся в Redis на десять минут, и из десяти тысяч обращений до базы доходит десяток. Вторая — сессии: пользователь логинится, сервер пишет его данные в Redis, и любой из пяти инстансов бэкенда достаёт сессию по cookie — состояние больше не привязано к конкретной машине, балансировщик крутит трафик как хочет. Третья — счётчики и лимиты: просмотры статьи, попытки входа, rate limit — атомарные операции в один поток делают это безопасно и без блокировок. Четвёртая — очереди: списки и потоки Redis превращаются в простой механизм фоновых задач ровно до того момента, когда нагрузка оправдает Kafka. Пятая — рейтинги и тренды: сортированные множества хранят топ игроков с обновлением очка за одну команду. Заметьте закономерность: везде данные читаются часто, живут недолго и допускают восстановление после потери. Как только задача перестаёт этим свойствам соответствовать — возвращаемся в Postgres и не геройствуем.

Роли Redis одним списком#

  • Кэш запросов и ответов: база получает десяток обращений вместо десяти тысяч.
  • Сессии пользователей: состояние не привязано к конкретному инстансу бэкенда.
  • Счётчики и лимиты: атомарный INCR без мьютексов и гонок.
  • Очереди задач: списки и Streams как простой producer-consumer.
  • Pub/Sub: рассылка событий всем подписчикам в реальном времени.
  • Рейтинги и топы: сортированные множества с обновлением очка за одну команду.

Первый взгляд: go-redis в пяти строках

GO
package 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 держит только то, что восстанавливается само — пересчётом из базы или повторным запросом. Сессии на грани: потерять их можно, пользователь просто перелогинится, но решать это нужно осознанно, а не по остаточному принципу.

Клиент 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)

Соберите создание клиента

Допишите конструктор клиента, стандартный адрес и нулевую базу.

rdb := redis.(&redis.Options{ Addr: ":6379", DB: , }) rdb.Set(ctx, "greeting", "привет", 0)

Соберите скелет работы с Redis

Расставьте строки в порядке работы программы: контекст, клиент, запись, чтение, вывод, закрытие.

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: знакомство с Redis

Термин

Redis

нажмите, чтобы перевернуть
Определение

Хранилище данных в памяти: кэш, сессии, счётчики, очереди. Команды обрабатываются в одном потоке, поэтому операции атомарны.

1 / 6

Карта собрана: 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 · Знакомство: зачем Go-сервису Redis)

Вопросы и ответы по уроку

Можно ли использовать Redis как основную базу данных?

Технически да — персистентность RDB и AOF существует, но по умолчанию Redis терпит потерю последних секунд данных и держит всё в памяти. Для заказов, платежей и профилей источником правды остаётся СУБД на диске вроде Postgres; Redis — слой скорости рядом с ней.

Сколько операций в секунду выдерживает Redis?

На обычном сервере один инстанс обрабатывает десятки и сотни тысяч простых операций в секунду — узкое место почти всегда сеть и приложение, а не Redis. Потолок упирается в одно ядро: команды выполняются в единственном потоке.

Почему go-redis, а не redigo или rueidis?

go-redis — рекомендуемый клиент с самой большой базой проектов и ответов; v9 даёт единый API с контекстом в каждой команде. Redigo ближе к ручной работе с протоколом, rueidis агрессивнее по производительности, но для обучения и типовых сервисов экосистема go-redis практичнее.

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

JWT25 уроков~12 чпрактика25 уроков уже доступны

JWT-аутентификация в Go: golang-jwt и bcrypt

Разбираем JWT в Go: устройство токена, golang-jwt v5, подписи HMAC и RSA, refresh-токены, bcrypt, middleware авторизации и лучшие практики.

  • Понимать анатомию JWT и почему payload не зашифрован
  • Выпускать и проверять токены через golang-jwt v5
  • Хешировать пароли bcrypt и сравнивать безопасно
  • Писать middleware аутентификации для chi и Gin