Выбор ответа Middle Разборы систем обновлено
Гонка в rate limiter
Вопрос
Rate limiter реализован так. Что в нём не так?
const key = `rl:${userId}:${currentMinute}`;
const count = Number(await redis.get(key)) || 0;
if (count >= 100) return reply.code(429).send();
await redis.set(key, count + 1, 'EX', 60);
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Правильный ответ: Между GET и SET проходят параллельные запросы, нужен INCR. Redis выполняет каждую команду атомарно, но GET и SET это две команды, между ними успевают выполниться команды других клиентов.
Варианты ответа
- Ничего: Redis однопоточный, значит этот код атомарен
- Нужно убрать TTL, он сбрасывает счётчик посреди минуты
- Между GET и SET проходят параллельные запросы, нужен INCRправильный ответ
- Ключ не должен содержать минуту, иначе окно не скользит
Разбор
Redis выполняет каждую команду атомарно, но GET и SET это две команды, между ними успевают выполниться команды других клиентов. Десять параллельных запросов прочитают count = 99 и все пройдут. INCR атомарно увеличивает и возвращает новое значение; EXPIRE ставят при первом увеличении, а надёжнее всё сделать в одном Lua-скрипте. Минута в ключе как раз и задаёт фиксированное окно, а TTL нужен, чтобы старые ключи не копились.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.