Что делать с горячими ключами, на которые приходится непропорционально большая нагрузка?
- Как справиться с проблемой знаменитостей в соцсети?
- Один шард перегружен, остальные простаивают — что делать?
- Как распределить нагрузку на популярный товар на распродаже?
Горячий ключ не делится ни хешем, ни consistent hashing: все запросы к нему идут в один узел. Нужно размножить ключ для чтения или разбить его для записи.
- Чтение: локальный кэш на серверах приложений, реплики ключа под разными суффиксами, CDN
- Запись: шардированный счётчик (key#1…key#N), агрегирование пачками, очередь
- Сначала обнаружить: топ ключей по нагрузке (count-min, мониторинг Redis hotkeys)
А ещё Знаменитости в ленте: их посты не раскладываем всем подписчикам, а подмешиваем при чтении
Подробно
Хеширование делит ключи равномерно, но не нагрузку: если один ключ получает 30% запросов, его узел получает минимум 30%. Примеры: популярный товар на распродаже, пост знаменитости, глобальный счётчик, конфигурация, которую читает каждый запрос, крупный клиент в мультитенантной базе.
Горячее чтение:
- локальный кэш в памяти сервиса с коротким TTL (секунды) — запросы к горячему ключу вообще не доходят до общего кэша. Caffeine, словарь с TTL; согласованность — в пределах TTL;
- реплики ключа — хранить копии под
key#1 … key#Nна разных узлах кэша и читать случайную. Запись обновляет все копии; - CDN и кэш на краю для публичных данных;
- объединение запросов (request coalescing, single flight) — при промахе один запрос идёт в базу, остальные ждут его результат.
Горячая запись:
- шардированный счётчик — лайки поста храним в N подсчётчиках
likes:post#k, инкремент — в случайный, чтение — сумма. N выбирают по нагрузке, можно увеличивать динамически для горячих; - агрегирование — копить инкременты в памяти или очереди и писать пачками раз в секунду;
- очередь вместо прямой записи — сглаживает пики, если результат не нужен мгновенно;
- остаток товара — разбить остаток на части по узлам (как бакеты токенов) или резервировать пачками.
Перекос в шардировании:
- вынести крупного клиента в отдельный шард (справочник);
- составной ключ:
(tenant_id, user_id)вместоtenant_id; - для временных рядов — добавить к ключу случайную «соль» из небольшого числа значений, а при чтении опрашивать все варианты.
Лента и знаменитости (celebrity problem). Обычно пост раскладывают в ленты подписчиков при публикации (fan-out on write). Для аккаунта с десятками миллионов подписчиков это миллионы записей на один пост. Гибрид: посты знаменитостей не раскладываются, а подмешиваются в ленту при чтении (fan-out on read).
Обнаружение: метрики нагрузки по шардам, сэмплирование ключей, count-min sketch для топа ключей, redis-cli --hotkeys, логи медленных запросов.
Пример
import random
N = 16
def incr_like(r, post_id):
r.incr(f"likes:{post_id}#{random.randrange(N)}") # запись размазана по 16 ключам
def likes(r, post_id):
return sum(int(v or 0) for v in r.mget([f"likes:{post_id}#{i}" for i in range(N)]))Что хотят услышать
- Почему хеширование не помогает против горячего ключа.
- Разные решения для чтения и для записи.
- Шардированные счётчики и локальный кэш как основные приёмы.
- Fan-out on write/read для знаменитостей и как находить горячие ключи.
Частые ошибки
- Предлагать «добавить шардов» — горячий ключ всё равно в одном.
- Забыть, что реплики ключа для чтения усложняют запись.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Горячий ключ решается увеличением числа шардов
- ✓Чтение — размножить ключ по кэшам; запись — разбить счётчик
- ✗Consistent hashing сам размажет нагрузку ключа
- ✗Горячий ключ невозможно обнаружить
Связанные вопросы
- Данные шардированы по хешу от идентификатора клиента. Несколько крупных клиентов дают около 80% нагрузки, и она приходится на один шард. Что здесь поможет? Senior
- Популярный ключ истекает, и сотни параллельных запросов одновременно уходят в базу за одним значением. Какие приёмы защищают от этого? Middle
- Как работает consistent hashing и зачем нужны виртуальные узлы? Middle
- Как найти самые популярные элементы в бесконечном потоке событий? Senior
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.