Redis клиент (go-redis) для Go: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в go-redis: мощный Redis клиент для Go

Redis — это высокопроизводительное хранилище данных типа "ключ-значение", работающее в оперативной памяти. Оно используется для кэширования, управления сессиями, очередей сообщений, рейтингов и многого другого. Для взаимодействия с Redis из Go существует несколько библиотек, и go-redis (пакет github.com/redis/go-redis/v9) является самой популярной, активно поддерживаемой и функциональной.

Эта библиотека предоставляет чистый, идиоматичный Go API для работы со всеми структурами данных Redis (строки, списки, множества, хеши, сортированные множества, HyperLogLog, потоки, геопространственные данные) и поддерживает такие продвинутые функции, как кластеризация, Sentinel, Pub/Sub, конвейеризация (pipelining) и Lua-скрипты. go-redis полностью поддерживает Redis 7 и 8.

В этом руководстве мы подробно разберем установку, основные методы, типичные ошибки и напишем реальный практический пример.

Установка go-redis

Установка производится стандартной командой go get:

go get github.com/redis/go-redis/v9

После выполнения этой команды в вашем go.mod появится зависимость. Убедитесь, что у вас установлен Go версии 1.18 или выше.

Также вам потребуется работающий сервер Redis (локально или удаленно). Для тестов можно запустить Redis в Docker:

docker run --name my-redis -p 6379:6379 -d redis

Быстрый старт: подключаемся и делаем первый запрос

Создайте файл main.go и напишите простейшую программу, которая подключается к Redis, записывает и читает значение.

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

func main() {
    // Создаем контекст (рекомендуется использовать context.Background())
    ctx := context.Background()

    // Создаем клиента
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379", // адрес Redis сервера
        Password: "",               // пароль (если есть)
        DB:       0,                // номер базы данных (по умолчанию 0)
    })

    // Проверяем соединение с помощью Ping
    pong, err := rdb.Ping(ctx).Result()
    if err != nil {
        panic(fmt.Sprintf("Не удалось подключиться к Redis: %v", err))
    }
    fmt.Println("Подключено:", pong)

    // Устанавливаем ключ "name" со значением "Alice"
    err = rdb.Set(ctx, "name", "Alice", 0).Err()
    if err != nil {
        panic(err)
    }

    // Читаем значение по ключу "name"
    val, err := rdb.Get(ctx, "name").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("name:", val)

    // Закрываем соединение при завершении программы
    defer rdb.Close()
}

Запустите программу:

go run main.go

Вы должны увидеть:

Подключено: PONG
name: Alice

Основные методы go-redis (8+ штук)

Все методы go-redis возвращают объект *Cmd (или его специализацию), который имеет метод .Result() для получения результата и ошибки, .Val() для получения только значения и .Err() для получения только ошибки. Это позволяет гибко обрабатывать результаты.

1. Set — установка значения ключа

Что делает: Устанавливает значение для указанного ключа. Можно задать время жизни (TTL) или 0 для бессрочного хранения.

Параметры:

  • ctx context.Context — контекст для управления временем выполнения
  • key string — имя ключа
  • value interface{} — значение (будет сериализовано)
  • expiration time.Duration — время жизни (0 — без TTL)

Пример:

err := rdb.Set(ctx, "user:100", "John Doe", 10*time.Minute).Err()
if err != nil {
    log.Fatal(err)
}

2. Get — получение значения ключа

Что делает: Возвращает строковое значение по ключу. Если ключ не существует, возвращает ошибку redis.Nil.

Параметры:

  • ctx context.Context
  • key string

Пример:

val, err := rdb.Get(ctx, "user:100").Result()
if err == redis.Nil {
    fmt.Println("Ключ не найден")
} else if err != nil {
    log.Fatal(err)
} else {
    fmt.Println("Значение:", val)
}

3. Del — удаление одного или нескольких ключей

Что делает: Удаляет указанные ключи. Возвращает количество удаленных ключей.

Параметры:

  • ctx context.Context
  • keys ...string — один или несколько ключей

Пример:

deleted, err := rdb.Del(ctx, "user:100", "temp_key").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Удалено ключей: %d\n", deleted)

4. Exists — проверка существования ключей

Что делает: Проверяет, существуют ли указанные ключи. Возвращает количество существующих ключей.

Параметры:

  • ctx context.Context
  • keys ...string

Пример:

exists, err := rdb.Exists(ctx, "user:100", "nonexistent").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Существует ключей: %d\n", exists)

5. Expire — установка времени жизни ключа

Что делает: Устанавливает время жизни (TTL) для существующего ключа. Возвращает true, если ключ существует и TTL установлен.

Параметры:

  • ctx context.Context
  • key string
  • expiration time.Duration

Пример:

ok, err := rdb.Expire(ctx, "session:abc", 30*time.Minute).Result()
if err != nil {
    log.Fatal(err)
}
if ok {
    fmt.Println("Время жизни установлено")
}

6. Incr / IncrBy — атомарное увеличение числа

Что делает: Атомарно увеличивает значение ключа на 1 (Incr) или на заданное число (IncrBy). Если ключ не существует, он создается со значением 0 перед увеличением.

Параметры (IncrBy):

  • ctx context.Context
  • key string
  • value int64 — число, на которое увеличить

Пример:

newVal, err := rdb.Incr(ctx, "counter").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Новое значение счетчика:", newVal)

// Увеличить на 10
newVal2, err := rdb.IncrBy(ctx, "counter", 10).Result()
if err != nil {
    log.Fatal(err)
}
fmt.Println("После IncrBy 10:", newVal2)

7. HSet / HGet / HGetAll — работа с хешами

Что делает: Хеши в Redis — это структура данных для хранения пар "поле-значение". HSet устанавливает одно или несколько полей, HGet получает одно поле, HGetAll получает все поля.

Параметры (HSet):

  • ctx context.Context
  • key string
  • values ...interface{} — чередующиеся поле, значение

Пример:

// Устанавливаем поля хеша "user:1"
err := rdb.HSet(ctx, "user:1", "name", "Bob", "age", 30, "city", "NYC").Err()
if err != nil {
    log.Fatal(err)
}

// Получаем одно поле
name, err := rdb.HGet(ctx, "user:1", "name").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Имя:", name)

// Получаем все поля
userData, err := rdb.HGetAll(ctx, "user:1").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Все данные пользователя:", userData)

8. LPush / RPush / LPop / RPop — работа со списками

Что делает: Списки Redis — это упорядоченные коллекции строк. LPush добавляет элемент в начало, RPush — в конец, LPop удаляет и возвращает первый элемент, RPop — последний.

Пример:

// Добавляем элементы в список "tasks"
rdb.RPush(ctx, "tasks", "task1", "task2", "task3")
rdb.LPush(ctx, "tasks", "urgent_task")

// Извлекаем первый элемент
first, err := rdb.LPop(ctx, "tasks").Result()
if err != nil {
    log.Fatal(err)
}
fmt.Println("Первый элемент:", first)

// Получаем длину списка
len, _ := rdb.LLen(ctx, "tasks").Result()
fmt.Println("Длина списка:", len)

9. SAdd / SMembers / SIsMember — работа с множествами

Что делает: Множества Redis — это неупорядоченные коллекции уникальных строк. SAdd добавляет элементы, SMembers возвращает все элементы, SIsMember проверяет наличие элемента.

Пример:

// Добавляем теги
rdb.SAdd(ctx, "tags:article:1", "go", "redis", "programming")

// Проверяем наличие тега
exists, _ := rdb.SIsMember(ctx, "tags:article:1", "go").Result()
fmt.Println("Тег 'go' существует:", exists)

// Получаем все теги
tags, _ := rdb.SMembers(ctx, "tags:article:1").Result()
fmt.Println("Все теги:", tags)

10. ZAdd / ZRangeByScore — работа с сортированными множествами

Что делает: Сортированные множества похожи на обычные, но каждый элемент имеет "вес" (score), по которому происходит сортировка. ZAdd добавляет элементы с весом, ZRangeByScore возвращает элементы в заданном диапазоне весов.

Пример:

// Добавляем игроков с их рейтингом
rdb.ZAdd(ctx, "leaderboard", 
    redis.Z{Score: 100, Member: "Alice"},
    redis.Z{Score: 200, Member: "Bob"},
    redis.Z{Score: 150, Member: "Charlie"},
)

// Получаем игроков с рейтингом от 100 до 200
players, _ := rdb.ZRangeByScore(ctx, "leaderboard", &redis.ZRangeBy{
    Min: "100",
    Max: "200",
}).Result()
fmt.Println("Игроки в диапазоне:", players)

Реальный практический пример: кэширование результатов API

Рассмотрим типичный сценарий: у нас есть функция, которая получает данные из внешнего API (например, погоду). Чтобы не делать запросы слишком часто, мы кэшируем результат в Redis на 5 минут.

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "time"

    "github.com/redis/go-redis/v9"
)

// WeatherData структура для хранения данных о погоде
type WeatherData struct {
    Temperature float64 `json:"temperature"`
    Humidity    int     `json:"humidity"`
    City        string  `json:"city"`
}

// getWeatherFromAPI имитирует запрос к внешнему                    

Рекомендаций