Spec-Zone.ru › Redis

INCR

INCR
Синтаксис
INCR key
Доступно с версии:
1.0.0
Сложность вычислений:
O(1)
Категории ACL:
@write, @string, @fast,

Увеличивает значение, хранящееся по ключу key на единицу. Если ключ не существует, его значение устанавливается в 0 перед выполнением операции. Возвращается ошибка, если значение ключа имеет неправильный тип или содержит строку, которая не может быть представлена как целое число. Данная операция ограничена 64-битными знаковыми целыми числами.

Примечание: эта операция работает со строками, так как в Redis нет отдельного типа данных «целое число». Хранимое по ключу значение интерпретируется как 64-битное знаковое целое число в системе счисления по основанию 10 для выполнения операции.

Redis хранит целые числа в их целочисленном представлении, поэтому для строковых значений, которые фактически содержат целое число, нет накладных расходов на хранение строкового представления целого числа.

Возврат

Целочисленный ответ: значение key после инкремента

Примеры

SET mykey "10"
INCR mykey
GET mykey

Шаблон: Счётчик

Шаблон счётчика — это наиболее очевидное применение атомарных операций инкремента в Redis. Суть заключается в отправке команды INCR в Redis каждый раз, когда происходит операция. Например, в веб-приложении мы можем захотеть узнать, сколько страниц просмотрел каждый пользователь каждый день в году.

Для этого веб-приложение может просто инкрементировать ключ каждый раз, когда пользователь просматривает страницу, создавая имя ключа, соединяя идентификатор пользователя и строку, представляющую текущую дату.

Этот простой шаблон можно расширить различными способами:

  • Можно использовать INCR и EXPIRE вместе при каждом просмотре страницы, чтобы счётчик учитывал только последние N просмотров страниц, разделённых менее чем заданным количеством секунд.
  • Клиент может использовать GETSET для атомарного получения текущего значения счётчика и сброса его до нуля.
  • Используя другие атомарные команды инкремента/декремента, такие как DECR или INCRBY, можно обрабатывать значения, которые могут увеличиваться или уменьшаться в зависимости от операций, выполняемых пользователем. Например, это может быть рейтинг пользователей в онлайн-игре.

Шаблон: Лимит скорости

Шаблон лимита скорости — это специальный счётчик, используемый для ограничения скорости выполнения операции. Классическое применение этого шаблона заключается в ограничении числа запросов, которые могут выполняться к публичному API.

Мы предоставляем две реализации этого шаблона, используя INCR, где мы предполагаем, что задача заключается в ограничении числа вызовов API до максимум десяти запросов в секунду на IP-адрес.

Шаблон: Лимит скорости 1

Более простая и прямая реализация этого шаблона выглядит следующим образом:

FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
MULTI
    INCR(keyname)
    EXPIRE(keyname,10)
EXEC
current = RESPONSE_OF_INCR_WITHIN_MULTI
IF current > 10 THEN
    ERROR "too many requests per second"
ELSE
    PERFORM_API_CALL()
END

В основном, у нас есть счётчик для каждого IP-адреса для каждой секунды. Но эти счётчики всегда увеличиваются, устанавливая срок действия 10 секунд, чтобы они автоматически удалялись Redis, когда текущая секунда отличается.

Обратите внимание на использование MULTI и EXEC для обеспечения того, что мы будем увеличивать счётчик и устанавливать срок действия при каждом обращении к API.

Шаблон: Лимит скорости 2

Альтернативная реализация использует один счётчик, но немного сложнее правильно реализовать его без гонок. Мы рассмотрим различные варианты.

FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
    ERROR "too many requests per second"
ELSE
    value = INCR(ip)
    IF value == 1 THEN
        EXPIRE(ip,1)
    END
    PERFORM_API_CALL()
END

Счётчик создаётся так, что он выживает только одну секунду, начиная с первого запроса в текущей секунде. Если в одной секунде поступает более 10 запросов, счётчик достигнет значения больше 10, в противном случае он истечёт и начнётся снова с 0.

В приведенном коде есть гонка. Если по какой-то причине клиент выполняет команду INCR , но не выполняет EXPIRE , ключ будет утечкой до тех пор, пока мы не увидим тот же IP-адрес снова.

Это можно легко исправить, преобразовав INCR с необязательным EXPIRE в скрипт Lua, который отправляется с помощью команды EVAL (доступен только начиная с версии Redis 2.6).

local current
current = redis.call("incr",KEYS[1])
if current == 1 then
    redis.call("expire",KEYS[1],1)
end

Существует другой способ исправить эту проблему без использования скриптов — использование списков Redis вместо счётчиков. Реализация более сложная и использует более продвинутые функции, но имеет преимущество в запоминании IP-адресов клиентов, которые в данный момент выполняют обращение к API, что может быть полезно или нет в зависимости от приложения.

FUNCTION LIMIT_API_CALL(ip)
current = LLEN(ip)
IF current > 10 THEN
    ERROR "too many requests per second"
ELSE
    IF EXISTS(ip) == FALSE
        MULTI
            RPUSH(ip,ip)
            EXPIRE(ip,1)
        EXEC
    ELSE
        RPUSHX(ip,ip)
    END
    PERFORM_API_CALL()
END

Команда RPUSHX добавляет элемент только в том случае, если ключ уже существует.

Обратите внимание, что здесь тоже есть гонка, но это не проблема: EXISTS может вернуть false, но ключ может быть создан другим клиентом до того, как мы создадим его внутри блока MULTI / EXEC. Однако эта гонка будет просто пропускать вызов API в редких случаях, поэтому лимит скорости по-прежнему будет работать правильно.

© 2006–2022 Salvatore Sanfilippo
Licensed under the Creative Commons Attribution-ShareAlike License 4.0.
https://redis.io/commands/incr/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API