Ответ
Redis (REmote DIctionary Server) — это высокопроизводительное in-memory хранилище данных типа «ключ-значение», которое часто используется как база данных, кэш или брокер сообщений.
Ключевые аспекты архитектуры:
- Хранение в памяти (In-Memory): Все данные хранятся в оперативной памяти, что обеспечивает сверхнизкие задержки при чтении и записи.
- Однопоточная модель (Single-Threaded Event Loop): Redis использует один поток для обработки всех команд. Это исключает гонки данных и необходимость в блокировках, но для утилизации многоядерных процессоров запускают несколько экземпляров Redis. Для операций ввода-вывода используется мультиплексирование (epoll, kqueue), что позволяет эффективно обрабатывать тысячи одновременных подключений.
- Персистентность (сохранение на диск): Для сохранности данных при перезапуске Redis предлагает два механизма:
- RDB (Redis Database): Создание снимков (snapshots) всей базы данных через определённые интервалы. Оптимально для бэкапов.
- AOF (Append-Only File): Запись каждой операции изменения данных в лог-файл. Обеспечивает лучшую сохранность данных.
Основные типы данных:
Redis — это не просто хранилище строк. Он поддерживает сложные структуры данных:
- Strings: Строки, числа, битовые поля.
- Lists: Списки, реализующие двустороннюю очередь (deque).
- Hashes: Хеш-таблицы (аналог
map
в Go). - Sets: Неупорядоченные множества уникальных строк.
- Sorted Sets (ZSETs): Упорядоченные множества, где у каждого элемента есть вес (score). Идеально для рейтингов и таблиц лидеров.
- Streams: Структура для реализации логов и очередей сообщений.
- HyperLogLogs, Bitmaps, Geospatial indexes.
Пример использования в Go (с библиотекой go-redis
):
Библиотека go-redis/redis
является современным стандартом для работы с Redis в Go.
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
var ctx = context.Background()
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Адрес Redis сервера
Password: "", // Пароль, если есть
DB: 0, // Номер базы данных
})
// Устанавливаем значение ключа
err := rdb.Set(ctx, "user:1", "Alex", 0).Err()
if err != nil {
panic(err)
}
// Получаем значение ключа
val, err := rdb.Get(ctx, "user:1").Result()
if err != nil {
panic(err)
}
fmt.Println("user:1 ->", val)
// Пример работы с Hash
rdb.HSet(ctx, "user:2", "name", "Bob", "age", 30)
name, _ := rdb.HGet(ctx, "user:2", "name").Result()
age, _ := rdb.HGet(ctx, "user:2", "age").Result()
fmt.Printf("User 2: Name - %s, Age - %sn", name, age)
}
Основные сценарии использования:
- Кэширование: Снижение нагрузки на основную базу данных.
- Хранение сессий: Быстрое сохранение и получение данных о пользовательских сессиях.
- Очереди задач: Использование
Lists
илиStreams
для создания фоновых очередей. - Pub/Sub: Реализация системы обмена сообщениями в реальном времени.
- Счётчики и рейтинги: Атомарные операции (
INCR
) и упорядоченные множества (Sorted Sets
).