Sobes.tech
Back to questions
Middle
13

Как реализовать счетчик с временем жизни ключа в Redis для задачи автоотклонения звонков?

Companies where asked
AvitoAvito

Answer from AI

sobes.tech AI

Что хотят услышать интервьюеры:

Нужно показать, что счетчик в Redis можно сделать через атомарное увеличение значения и отдельное ограничение по времени жизни ключа. Важно понимать, как избежать гонок и как сбрасывать счетчик после истечения окна. Для задачи автоотклонения звонков обычно используют INCR и EXPIRE в одном атомарном сценарии.

Определение:

Счетчик с временем жизни в Redis — это ключ, значение которого увеличивается при каждом событии, а сам ключ автоматически удаляется через заданный TTL. Это удобно для подсчета действий в фиксированном временном окне: например, сколько раз пользователь попытался позвонить за минуту. Когда TTL истекает, счетчик обнуляется естественным образом.

Пример использования:

Например, нужно автоотклонять звонки, если один абонент делает слишком много попыток за 60 секунд. При каждом новом вызове увеличивается счетчик по ключу, завязанному на номер телефона. Если значение превышает порог, система отклоняет звонок.

import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)

def should_reject_call(phone: str) -> bool:
    key = f"calls:{phone}"
    count = r.incr(key)

    if count == 1:
        r.expire(key, 60)  # TTL в 60 секунд выставляем только при первом попадании

    return count > 5

Пояснение кода:

  1. Формируется ключ, привязанный к номеру телефона.
  2. Команда INCR атомарно увеличивает значение счетчика.
  3. Если значение стало 1, значит ключ создан только что, и для него задается TTL через EXPIRE.
  4. Если за 60 секунд счетчик превысил лимит, вызов можно отклонить.
  5. После истечения TTL ключ исчезнет, и счетчик начнет считаться заново.

Ключевые моменты:

  • INCR в Redis атомарный, поэтому подходит для конкурентных запросов.
  • TTL нужен, чтобы счетчик работал в пределах временного окна, а не рос бесконечно.
  • EXPIRE лучше ставить только при первом создании ключа, чтобы не сдвигать окно на каждый новый звонок.
  • Для более надежной атомарности INCR и EXPIRE можно объединять через Lua-скрипт.
  • Ключ обычно строят по бизнес-идентификатору: номеру телефона, user ID, IP-адресу или комбинации этих полей.
  • Такой подход подходит для rate limiting, антифрода и автоотклонения повторяющихся звонков.