ディレクトリ 検索
Cluster cluster addslots(集群 槽位) cluster count failure reports(集群计数失败报告) cluster countkeysinslot cluster delslots cluster failover cluster forget cluster getkeysinslot cluster info cluster keyslot(集群键槽) cluster meet cluster nodes(集群节点) cluster replicate(集群复制) cluster reset(集群重置) cluster saveconfig cluster set config epoch cluster setslot cluster slaves cluster slots readonly readwrite Connection auth echo ping quit select swapdb Geo geoadd geodist geohash geopos georadius georadiusbymember Hashes hdel hexists hget hgetall hincrby hincrbyfloat hkeys hlen hmget hmset hscan hset hsetnx hstrlen hvals HyperLogLog pfadd pfcount pfmerge Keys del dump exists expire expireat keys migrate move object persist pexpire pexpireat pttl randomkey rename renamenx restore scan sort touch ttl type unlink wait Lists blpop brpop brpoplpush lindex linsert llen lpop lpush lpushx lrange lrem lset ltrim rpop rpoplpush rpush rpushx Pub/Sub psubscribe publish pubsub punsubscribe subscribe unsubscribe Scripting eval evalsha script debug script exists script flush script kill script load Server bgrewriteaof bgsave client getname client kill client list client pause client reply client setname command command count command getkeys command info config get config resetstat config rewrite config set dbsize debug object debug segfault flushall flushdb info lastsave monitor role save shutdown slaveof slowlog time Sets sadd scard sdiff sdiffstore sinter sinterstore sismember smembers smove spop srandmember srem sscan sunion sunionstore Sorted Sets zadd zcard zcount zincrby zinterstore zlexcount zrange zrangebylex zrangebyscore zrank zrem zremrangebylex zremrangebyrank zremrangebyscore zrevrange zrevrangebylex zrevrangebyscore zrevrank zscan zscore zunionstore Strings append bitcount bitfield bitop bitpos decr decrby get getbit getrange getset incr incrby incrbyfloat mget mset msetnx psetex set setbit setex setnx setrange strlen Transactions discard exec multi unwatch watch
テキスト

INCR key

自1.0.0起可用。

时间复杂度: O(1)

将存储的数字key加1。如果密钥不存在,则0在执行操作之前将其设置为。如果密钥包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。该操作仅限于64位有符号整数。

注意:这是一个字符串操作,因为Redis没有专用的整数类型。存储在密钥中的字符串被解释为一个以10为底的64位有符号整数来执行操作。

Redis 以整数表示形式存储整数,因此对于实际上包含整数的字符串值,不存在用于存储整数的字符串表示形式的开销。

返回值

整数回复:key增量后的值

例子

redis>  SET mykey "10" "OK" redis>  INCR mykey (integer) 11 redis>  GET mykey "11"

模式:计数器

计数器模式是使用 Redis 原子增量操作可以做的最明显的事情。这个想法只是在每次操作发生时发送 INCR 命令给 Redis。例如,在一个 Web 应用程序中,我们可能想知道这个用户一年中每天都做了多少页面浏览。

为此,Web 应用程序可以在每次用户执行页面视图时简单地增加一个键,创建连接用户 ID 的键名和代表当前日期的字符串。

这种简单模式可以通过多种方式进行扩展:

  • 可以在每个页面视图中一起使用 INCR 和 EXPIRE,使计数器只计算最近 N 个分页少于指定秒数的页面视图。

  • 客户端可以使用 GETSET 来自动获取当前计数器值并将其重置为零。

  • 使用其他原子增量/减量命令(如 DECR 或 INCRBY),可以根据用户执行的操作来处理可能变大或变小的值。想象一下在线游戏中不同用户的分数。

模式:限速器

速率限制器模式是一个特殊的计数器,用于限制执行操作的速率。这种模式的经典实现涉及限制可以针对公共 API 执行的请求的数量。

我们使用 INCR 提供了这种模式的两种实现,我们假设要解决的问题是将 API 调用的数量限制为每IP地址每秒最多10个请求

模式:限速器1

这种模式的更简单直接的实现如下:

FUNCTION LIMIT_API_CALL(ip)ts = CURRENT_UNIX_TIME()keyname = ip+":"+ts
current = GET(keyname)IF current != NULL AND current > 10 THEN
    ERROR "too many requests per second"ELSE
    MULTI        INCR(keyname,1)        EXPIRE(keyname,10)
    EXEC    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地址。

这可以很容易地解决,将带有可选 EXPIRE 的 INCR 转换为使用EVAL 命令发送的 Lua 脚本(仅在 Redis 版本2.6以后可用)。

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

有一种不使用脚本解决此问题的方法,但使用 Redis 列表而不是计数器。实现更复杂,使用更多高级功能,但具有记住当前正在执行API调用的客户端的IP地址的优点,根据应用程序的不同,该地址可能有用或无用。

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 命令只会推送元素。

请注意,我们在这里有一场竞赛,但这不是问题:在我们在MULTI / EXEC 块中创建它之前,EXISTS 可能会返回 false,但可能会由另一个客户端创建密钥。然而,这种竞争只会在极少数情况下错过API调用,所以速率限制仍然可以正常工作。

前の記事: 次の記事: