15 KiB
Схема данных Redis в Discours.io
Обзор
Redis используется как основное хранилище для кэширования, сессий, токенов и временных данных. Все ключи следуют структурированным паттернам для обеспечения консистентности и производительности.
Принципы именования ключей
Общие правила
- Использование двоеточия
:
как разделителя иерархии - Формат:
{category}:{type}:{identifier}
или{entity}:{property}:{value}
- Константное время поиска через точные ключи
- TTL для всех временных данных
Категории данных
- Аутентификация:
session:*
,oauth_*
,env_vars:*
- Кэш сущностей:
author:*
,topic:*
,shout:*
- Поиск:
search_cache:*
- Просмотры:
migrated_views_*
,viewed_*
- Уведомления: publish/subscribe каналы
1. Система аутентификации
1.1 Сессии пользователей
Структура ключей
session:{user_id}:{jwt_token} # HASH - данные сессии
user_sessions:{user_id} # SET - список активных токенов пользователя
{user_id}-{username}-{token} # STRING - legacy формат (deprecated)
Данные сессии (HASH)
HGETALL session:123:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Поля:
user_id
: ID пользователя (string)username
: Имя пользователя (string)token_type
: "session" (string)created_at
: Unix timestamp создания (string)last_activity
: Unix timestamp последней активности (string)auth_data
: JSON строка с данными авторизации (string, optional)device_info
: JSON строка с информацией об устройстве (string, optional)
TTL: 30 дней (2592000 секунд)
Список токенов пользователя (SET)
SMEMBERS user_sessions:123
Содержимое: JWT токены активных сессий пользователя TTL: 30 дней
1.2 OAuth токены
Структура ключей
oauth_access:{user_id}:{provider} # STRING - access токен
oauth_refresh:{user_id}:{provider} # STRING - refresh токен
oauth_state:{state} # HASH - временное состояние OAuth flow
Access токены
Провайдеры: google
, github
, facebook
, twitter
, telegram
, vk
, yandex
TTL: 1 час (3600 секунд)
Пример:
GET oauth_access:123:google
# Возвращает: access_token_string
Refresh токены
TTL: 30 дней (2592000 секунд) Пример:
GET oauth_refresh:123:google
# Возвращает: refresh_token_string
OAuth состояние (временное)
HGETALL oauth_state:a1b2c3d4e5f6
Поля:
redirect_uri
: URL для перенаправления после авторизацииcsrf_token
: CSRF защитаprovider
: Провайдер OAuthcreated_at
: Время создания
TTL: 10 минут (600 секунд)
1.3 Токены подтверждения
Структура ключей
verification:{user_id}:{type}:{token} # HASH - данные токена подтверждения
Типы подтверждения
email_verification
: Подтверждение emailphone_verification
: Подтверждение телефонаpassword_reset
: Сброс пароляemail_change
: Смена email
Поля токена:
user_id
: ID пользователяtoken_type
: Тип токенаverification_type
: Тип подтвержденияcreated_at
: Время созданияdata
: JSON с дополнительными данными
TTL: 1 час (3600 секунд)
2. Переменные окружения
Структура ключей
env_vars:{variable_name} # STRING - значение переменной
Примеры переменных
GET env_vars:JWT_SECRET # Секретный ключ JWT
GET env_vars:REDIS_URL # URL Redis
GET env_vars:OAUTH_GOOGLE_CLIENT_ID # Google OAuth Client ID
GET env_vars:FEATURE_REGISTRATION # Флаг функции регистрации
Категории переменных:
- database: DB_URL, POSTGRES_*
- auth: JWT_SECRET, OAUTH_*
- redis: REDIS_URL, REDIS_HOST, REDIS_PORT
- search: SEARCH_API_KEY, ELASTICSEARCH_URL
- integrations: GOOGLE_ANALYTICS_ID, SENTRY_DSN, SMTP_*
- security: CORS_ORIGINS, ALLOWED_HOSTS
- logging: LOG_LEVEL, DEBUG
- features: FEATURE_*
TTL: Без ограничения (постоянное хранение)
3. Кэш сущностей
3.1 Авторы (пользователи)
Структура ключей
author:id:{author_id} # STRING - JSON данные автора
author:slug:{author_slug} # STRING - ID автора по slug
author:followers:{author_id} # STRING - JSON массив подписчиков
author:follows-topics:{author_id} # STRING - JSON массив отслеживаемых тем
author:follows-authors:{author_id} # STRING - JSON массив отслеживаемых авторов
author:follows-shouts:{author_id} # STRING - JSON массив отслеживаемых публикаций
Данные автора (JSON)
{
"id": 123,
"email": "user@example.com",
"name": "Имя Пользователя",
"slug": "username",
"pic": "https://example.com/avatar.jpg",
"bio": "Описание автора",
"email_verified": true,
"created_at": 1640995200,
"updated_at": 1640995200,
"last_seen": 1640995200,
"stat": {
"topics": 15,
"authors": 8,
"shouts": 42
}
}
Подписчики автора
[123, 456, 789] // Массив ID подписчиков
Подписки автора
// author:follows-topics:123
[1, 5, 10, 15] // ID отслеживаемых тем
// author:follows-authors:123
[45, 67, 89] // ID отслеживаемых авторов
// author:follows-shouts:123
[101, 102, 103] // ID отслеживаемых публикаций
TTL: Без ограничения (инвалидация при изменениях)
3.2 Темы
Структура ключей
topic:id:{topic_id} # STRING - JSON данные темы
topic:slug:{topic_slug} # STRING - JSON данные темы
topic:authors:{topic_id} # STRING - JSON массив авторов темы
topic:followers:{topic_id} # STRING - JSON массив подписчиков темы
topic_shouts_{topic_id} # STRING - JSON массив публикаций темы (legacy)
Данные темы (JSON)
{
"id": 5,
"title": "Название темы",
"slug": "tema-slug",
"description": "Описание темы",
"pic": "https://example.com/topic.jpg",
"community": 1,
"created_at": 1640995200,
"updated_at": 1640995200,
"stat": {
"shouts": 150,
"authors": 25,
"followers": 89
}
}
Авторы темы
[123, 456, 789] // ID авторов, писавших в теме
Подписчики темы
[111, 222, 333, 444] // ID подписчиков темы
TTL: Без ограничения (инвалидация при изменениях)
3.3 Публикации (Shouts)
Структура ключей
shouts:{params_hash} # STRING - JSON массив публикаций
topic_shouts_{topic_id} # STRING - JSON массив публикаций темы
Примеры ключей публикаций
shouts:limit=20:offset=0:sort=created_at # Последние публикации
shouts:author=123:limit=10 # Публикации автора
shouts:topic=5:featured=true # Рекомендуемые публикации темы
TTL: 5 минут (300 секунд)
4. Поисковый кэш
Структура ключей
search_cache:{normalized_query} # STRING - JSON результаты поиска
Нормализация запроса
- Приведение к нижнему регистру
- Удаление лишних пробелов
- Сортировка параметров
Данные поиска (JSON)
{
"query": "поисковый запрос",
"results": [
{
"type": "shout",
"id": 123,
"title": "Заголовок публикации",
"slug": "publication-slug",
"score": 0.95
}
],
"total": 15,
"cached_at": 1640995200
}
TTL: 10 минут (600 секунд)
5. Система просмотров
Структура ключей
migrated_views_{timestamp} # HASH - просмотры публикаций
migrated_views_slugs # HASH - маппинг slug -> id
viewed:{shout_id} # STRING - счетчик просмотров
Мигрированные просмотры (HASH)
HGETALL migrated_views_1640995200
Поля:
{shout_id}
: количество просмотров (string)_timestamp
: время создания записи_total
: общее количество записей
Маппинг slug -> ID
HGETALL migrated_views_slugs
Поля: {shout_slug}
-> {shout_id}
TTL: Без ограничения (данные аналитики)
6. Pub/Sub каналы
Каналы уведомлений
notifications:{user_id} # Персональные уведомления
notifications:global # Глобальные уведомления
notifications:topic:{topic_id} # Уведомления темы
notifications:shout:{shout_id} # Уведомления публикации
Структура сообщения (JSON)
{
"type": "notification_type",
"user_id": 123,
"entity_type": "shout",
"entity_id": 456,
"action": "created|updated|deleted",
"data": {
"title": "Заголовок",
"author": "Автор"
},
"timestamp": 1640995200
}
7. Временные данные
Ключи блокировок
lock:{operation}:{entity_id} # STRING - блокировка операции
TTL: 30 секунд (автоматическое снятие блокировки)
Ключи состояния
state:{process}:{identifier} # HASH - состояние процесса
TTL: От 1 минуты до 1 часа в зависимости от процесса
8. Мониторинг и статистика
Ключи метрик
metrics:{metric_name}:{period} # STRING - значение метрики
stats:{entity}:{timeframe} # HASH - статистика сущности
Примеры метрик
metrics:active_sessions:hourly # Количество активных сессий
metrics:cache_hits:daily # Попадания в кэш за день
stats:topics:weekly # Статистика тем за неделю
TTL: От 1 часа до 30 дней в зависимости от типа метрики
9. Оптимизация и производительность
Пакетные операции
Используются Redis pipelines для атомарных операций:
# Пример создания сессии
commands = [
("hset", (token_key, "user_id", user_id)),
("hset", (token_key, "created_at", timestamp)),
("expire", (token_key, ttl)),
("sadd", (user_tokens_key, token)),
]
await redis.execute_pipeline(commands)
Стратегии кэширования
- Write-through: Немедленное обновление кэша при изменении данных
- Cache-aside: Lazy loading с обновлением при промахе
- Write-behind: Отложенная запись в БД
Инвалидация кэша
- Точечная: Удаление конкретных ключей при изменениях
- По префиксу: Массовое удаление связанных ключей
- TTL: Автоматическое истечение для временных данных
10. Мониторинг
Команды диагностики
# Статистика использования памяти
redis-cli info memory
# Количество ключей по типам
redis-cli --scan --pattern "session:*" | wc -l
redis-cli --scan --pattern "author:*" | wc -l
redis-cli --scan --pattern "topic:*" | wc -l
# Размер конкретного ключа
redis-cli memory usage session:123:token...
# Анализ истечения ключей
redis-cli --scan --pattern "*" | xargs -I {} redis-cli ttl {}
Проблемы и решения
- Память: Использование TTL для временных данных
- Производительность: Pipeline операции, connection pooling
- Консистентность: Транзакции для критических операций
- Масштабирование: Шардирование по user_id для сессий
11. Безопасность
Принципы
- TTL для всех временных данных предотвращает накопление мусора
- Раздельное хранение секретных данных (токены) и публичных (кэш)
- Использование pipeline для атомарных операций
- Регулярная очистка истекших ключей
Рекомендации
- Мониторинг использования памяти Redis
- Backup критичных данных (переменные окружения)
- Ограничение размера значений для предотвращения OOM
- Использование отдельных баз данных для разных типов данных