ключ — значение — живой кейсkey-value — real-world case
Задача: миллионы одновременно залогиненных пользователей, каждый запрос проверяет валидность сессии, отклик должен оставаться незаметным даже под пиковой нагрузкой (начало трансляции популярного события). Ниже — почему это в принципе решаемая задача только для key-value хранилища, а не для реляционной БД напрямую.The problem: millions of simultaneously logged-in users, every request checks session validity, response time must stay imperceptible even under peak load (the start of a popular live broadcast). Below is why this is only tractable with a key-value store, not a relational DB directly.
Каждый HTTP-запрос от залогиненного пользователя (просмотр видео, переключение канала, чат) требует проверки: валиден ли токен сессии, не истёк ли он, какому пользователю принадлежит. При десятках миллионов активных сессий и тысячах запросов в секунду на пике, эта проверка должна быть однозначно быстрее самого запроса — иначе она станет узким местом всей системы, а не вспомогательной операцией.Every HTTP request from a logged-in user (watching a video, switching a channel, chatting) requires a check: is the session token valid, has it expired, which user does it belong to. With tens of millions of active sessions and thousands of requests per second at peak, this check must unambiguously be faster than the request itself — otherwise it becomes the whole system's bottleneck rather than a supporting operation.
Реляционная БД технически способна хранить сессии в таблице с индексом по токену, но при таком объёме и частоте чтения (по сути — просто point lookup по ключу, без единого JOIN или сложного условия) использование полноценной СУБД — трата её сильных сторон (транзакции, целостность связей) там, где они не нужны, при полной потере в задержке по сравнению с in-memory хранилищем.A relational DB is technically capable of storing sessions in a table indexed by token, but at this volume and read frequency (which is fundamentally just a point lookup by key, with no JOIN or complex condition at all) using a full-fledged DBMS wastes its strengths (transactions, referential integrity) where they aren't needed, while losing entirely on latency compared to an in-memory store.
Сессия хранится как хэш (Redis Hash) под ключом `session:{token}`, содержащим `user_id`, время создания, метаданные устройства — с TTL, равным политике таймаута бездействия (например, 30 минут, обновляемым при каждом активном запросе через `EXPIRE`). Проверка сессии на каждом запросе — один `GET`/`HGETALL` по ключу, O(1) в среднем случае, независимо от того, сколько всего сессий существует в системе.A session is stored as a hash (Redis Hash) under the key `session:{token}`, containing `user_id`, creation time, device metadata — with TTL equal to the inactivity-timeout policy (say, 30 minutes, refreshed on every active request via `EXPIRE`). Checking a session on every request is one `GET`/`HGETALL` by key, O(1) on average, regardless of how many sessions exist in the system overall.
Для отказоустойчивости и распределения нагрузки чтения — Redis Cluster (шардирование по хэшу ключа между узлами) с репликами на каждый шард: запись идёт на мастер шарда, чтения (в том числе те самые частые проверки сессии) можно распределять между репликами, если приложение готово мириться с секундной задержкой репликации для НЕ критичных к строгой консистентности проверок.For fault tolerance and read-load distribution — Redis Cluster (sharding by key hash across nodes) with replicas per shard: writes go to the shard's master, reads (including those very same frequent session checks) can be spread across replicas, if the application can tolerate sub-second replication lag for checks that aren't critical to strict consistency.
Ключевая деталь именно для стриминга: при старте популярной трансляции происходит резкий всплеск одновременных логинов и проверок сессий (thundering herd на уровне всей платформы, а не одного ключа) — шардирование заранее по предсказуемому ключу (`user_id` или `token`) распределяет эту нагрузку равномерно между узлами кластера вместо концентрации на одном инстансе.The detail specific to streaming: a popular broadcast starting causes a sharp spike of simultaneous logins and session checks (a platform-wide thundering herd, not a single-key one) — sharding ahead of time by a predictable key (`user_id` or `token`) spreads this load evenly across the cluster's nodes instead of concentrating it on one instance.
Хранение сессии прямо в JWT без централизованного состояния убрало бы необходимость в этом хранилище вовсе — но тогда отзыв сессии (принудительный логаут, бан аккаунта) технически невозможен до истечения токена без централизованной blacklist, которая сама становится key-value задачей. Хранение сессий в самой реляционной БД профиля пользователя добавило бы к ней нагрузку, для которой она не спроектирована, рискуя деградацией куда более критичных операций (оплата, изменение профиля).Storing the session directly in a JWT with no centralized state would remove the need for this store entirely — but then revoking a session (a forced logout, banning an account) is technically impossible before the token expires without a centralized blacklist, which itself becomes a key-value problem. Storing sessions in the user-profile relational DB itself would add load it wasn't designed for, risking degradation of far more critical operations (payments, profile changes).