压缩列表

在列表、散列和有序集合的长度较短或者体积较小的时候,Redis可以选择使用一种为压缩列表(ziplist) 的紧凑存储方式来存储这些结构。压缩列表是列表、散列和有序集这3种不同类型的对象的一种非结构化( unstructured)表示。与Redis在通常情况下使双链表表示列表、使用散列表表示散列、使用散列表加上跳跃表( skiplist) 表示有序集的做法不同,压缩列表会以序列化的方式存储数据,这些序列化数据每次被读取的时候要进行解码,每次被写入的时候也要进行局部的重新编码,并且可能需要对内存里面的据进行移动。

为啥用压缩列表

数据较少时,使用传统数据结构本身带来的数据开销较大,所以采用一种紧凑的数据存储来存储那些数据量不多的数据集合关系。压缩列表的格式。压缩列表是由节点组成的序列( sequence ),每个节点都由两个长度值和一个字符串组成。第一个长度值记录的是前一个节点的长度,这个长度值将被用于对压缩列表进行从后向前的遍历,第二个长度值记录了当前节点的长度,而位于节点最后的则是被存储的字符串值。尽管压缩列表节点的长度值在实际中还有一些其他的含义。压缩列表的优点是节省数据的存储空间。缺点是压缩列表在编码解码时的性能开销。

数据类型

String

基本特性

  • Redis 的 String 可以包含任字符串,整数,浮点数
  • String 类型的值最大能存储 512MB
  • 扩容特性,小于1M时容量翻倍,大于1M时增加1M

应用场景

  • 数据存储
  • 分布式锁
  • 对象缓存
  • 访问计数

常用命令

命令 Time complexity Options 说明 Return value Example Patterns
set O(1) SET key value [EX seconds|PX milliseconds|EXAT timestamp|PXAT milliseconds-timestamp|KEEPTTL] [NX|XX] [GET]
—————————-
The SET command supports a set of options that modify its behavior:
- EX seconds — Set the specified expire time, in seconds.
- PX milliseconds — Set the specified expire time, in milliseconds.
- EXAT timestamp-seconds — Set the specified Unix time at which the key will expire, in seconds.
- PXAT timestamp-milliseconds — Set the specified Unix time at which the key will expire, in milliseconds.
- NX — Only set the key if it does not already exist.
- XX — Only set the key if it already exist.
- KEEPTTL — Retain the time to live associated with the key.
- GET — Return the old string stored at key, or nil if key did not exist. An error is returned and SET aborted if the value stored at key is not a string.

Note: Since the SET command options can replace SETNX, SETEX, PSETEX, GETSET, it is possible that in future versions of Redis these commands will be deprecated and finally removed. | 设置key为持有的字符串value。如果key已经拥有一个值,则无论其类型如何,它都会被覆盖。成功的SET操作将丢弃与密钥关联的任何先前的生存时间。 | Simple string reply: OK if SET was executed correctly.
Null reply: (nil) if the SET operation was not performed because the user specified the NX or XX option but the condition was not met.
If the command is issued with the GET option, the above does not apply. It will instead reply as follows, regardless if the SET was actually performed:
Bulk string reply: the old string value stored at key.
Null reply: (nil) if the key did not exist. | redis> SET mykey “Hello”
“OK”
redis> GET mykey
“Hello”
redis> SET anotherkey “will expire in a minute” EX 60
“OK”
redis> | 注意:不鼓励使用以下模式,以支持Redlock 算法该算法实现起来稍微复杂一点,但提供更好的保证并且具有容错性。
该命令SET resource-name anystring NX EX max-lock-time是一种使用 Redis 实现锁定系统的简单方法。
如果上述命令返回,客户端可以获取锁OK(如果命令返回 Nil,则在一段时间后重试),并仅使用DEL删除锁。
达到到期时间后,锁将自动释放。
修改解锁模式可以使这个系统更加健壮,如下所示:
- 不是设置固定字符串,而是设置一个不可猜测的大随机字符串,称为令牌。
- 不要使用DEL释放锁,而是发送一个脚本,该脚本仅在值匹配时删除密钥。
这避免了客户端会在过期时间后尝试释放锁,删除稍后获取锁的另一个客户端创建的密钥。
解锁脚本的示例类似于以下内容:

if redis.call(“get”,KEYS[1]) == ARGV[1]
then
return redis.call(“del”,KEYS[1])
else
return 0
end | | mset | O(N) where N is the number of keys to set. | MSET key value [key value …] | 将给定的键设置为其各自的值。 MSET用新值替换现有值,就像常规SET 一样。如果您不想覆盖现有值,请参阅MSETNX
MSET原子的,所以所有给定的键都是一次设置的。客户端不可能看到某些Key已更新而其他Key未更改。 | Simple string reply: always OK since MSET can’t fail. | redis> MSET key1 “Hello” key2 “World”
“OK”
redis> GET key1
“Hello”
redis> GET key2
“World”
redis> |
| | get | O(1) | GET key | 获取key的值。如果键不存在,则返回特殊值nil。如果存储的值key不是字符串,则会返回错误,因为 GET 仅处理字符串值。 | Bulk string reply: the value of key, or nil when key does not exist. | redis> GET nonexisting
(nil)
redis> SET mykey “Hello”
“OK”
redis> GET mykey
“Hello”
redis> |
| | mget | O(N) where N is the number of keys to retrieve. | MGET key [key …] | 返回所有指定键的值。对于每个不包含字符串值或不存在的键,都会返回特殊值 nil。因此,操作永远不会失败。 | Array reply: list of values at the specified keys. | redis> SET key1 “Hello”
“OK”
redis> SET key2 “World”
“OK”
redis> MGET key1 key2 nonexisting
1) “Hello” 2) “World” 3) (nil)
redis> |
| | setnx | O(1) | SETNX key value | 如果键不存在,则设置键以保存字符串值。在这种情况下,它等于SET。当 key 已经持有一个值时,不执行任何操作。。 SETNX 是“SET if Not eXists”的缩写。 | Integer reply, specifically:
- 1 if the key was set
- 0 if the key was not set
| redis> SETNX mykey “Hello”
(integer) 1
redis> SETNX mykey “World”
(integer) 0
redis> GET mykey
“Hello”
redis> | Locking with SETNX
Please note that:
1. 不鼓励使用以下模式,而是支持 Redlock 算法,该算法实现起来稍微复杂一些,但提供了更好的保证并且具有容错性。
1. 我们仍然记录旧模式,因为某些现有实现链接到此页面作为参考。此外,这是一个有趣的示例,说明如何使用 Redis 命令来挂载编程原语。
1. 无论如何,即使假设是单实例锁定原语,从 2.6.12 开始,也可以创建一个更简单的锁定原语,相当于这里讨论的那个,使用 SET 命令获取锁,和一个简单的 Lua 脚本来释放锁。该模式记录在 SET 命令页面中。
也就是说,SETNX 可以用作锁定原语,并且在历史上曾被用作锁定原语。例如,要获取密钥 foo 的锁,客户端可以尝试以下操作:
SETNX lock.foo

如果 SETNX 返回 1,则客户端获得了锁,将 lock.foo 键设置为 Unix 时间,此时该锁不再被视为有效。客户端稍后将使用 DEL lock.foo 来释放锁。
如果 SETNX 返回 0,则密钥已被其他客户端锁定。如果它是一个非阻塞锁,我们可以返回给调用者,或者进入一个循环重试保持锁直到我们成功或某种超时到期。

处理死锁

在上述锁定算法中存在一个问题:如果客户端失败、崩溃或无法释放锁定,会发生什么情况?由于锁定key包含 UNIX 时间戳,因此可以检测到这种情况。如果这样的时间戳等于当前的 Unix 时间,则锁不再有效。
发生这种情况时,我们不能只针对key调用DEL来移除锁,然后尝试发出SETNX,因为这里存在竞争条件,当多个客户端检测到过期锁并试图释放它时。
- C1 和 C2 读取lock.foo以检查时间戳,因为它们都0在执行SETNX后收到 ,因为锁仍然由 C3 持有,C3 在持有锁后崩溃。
- C1发送 DEL lock.foo
- C1发送SETNX lock.foo并成功
- C2发送 DEL lock.foo
- C2发送SETNX lock.foo并成功
- 错误:由于竞争条件,C1 和 C2 都获得了锁。


幸运的是,使用以下算法可以避免这个问题。让我们看看 C4,我们理智的客户,如何使用好的算法:
- C4发送SETNX lock.foo以获取锁
- 崩溃的客户端 C3 仍然持有它,因此 Redis 会回复 0 给 C4。
- C4 发送GET lock.foo检查锁是否过期。如果不是,它会休眠一段时间并从头开始重试。
- 相反,如果由于 lock.foo 中的 Unix 时间比当前 Unix 时间早而导致锁过期,C4 会尝试执行:
GETSET lock.foo
- 由于GETSET语义,C4 可以检查存储在的旧值 key是否仍然是过期的时间戳。如果是,则获得了锁。
- 如果另一个客户端(例如 C5)比 C4 快,并使用GETSET操作获取锁,则 C4 GETSET操作将返回一个未过期的时间戳。C4 将简单地从第一步重新开始。请注意,即使 C4 在未来将key设置几秒钟,这也不是问题。
为了使这种锁定算法更加健壮,持有锁的客户端在使用DEL解锁密钥之前应该始终检查超时没有到期,因为客户端故障可能很复杂,不仅是崩溃,而且还会阻塞一些操作的大量时间并在很长时间后尝试发出DEL(当 LOCK 已被另一个客户端持有时)。 | | msetnx | O(N) where N is the number of keys to set. | MSETNX key value [key value …] | 将给定的key设置为其各自的值。 即使只有一个key已经存在,MSETNX也不会执行任何操作。
由于此语义,MSETNX可用于以确保设置所有字段或根本不设置字段的方式设置代表唯一逻辑对象的不同字段的不同键。
MSETNX是原子的,所以所有给定的键都是一次设置的。客户端不可能看到某些key已更新而其他key未更改。 | Integer reply, specifically:
- 1 if the all the keys were set.
- 0 if no key was set (at least one key already existed).
| redis> MSETNX key1 “Hello” key2 “there”
(integer) 1
redis> MSETNX key2 “new” key3 “world”
(integer) 0
redis> MGET key1 key2 key3
1) “Hello” 2) “there” 3) (nil)
redis>

|
| | setex | O(1) | SETEX key seconds value | 设置 key 以保存字符串值,并将 key 设置为在给定秒数后超时。该命令相当于执行以下命令:

SET mykey value
EXPIRE mykey seconds

SETEX是原子的,可以通过在 MULTI / EXEC 块中使用前两个命令来复制

它是作为给定操作序列的更快替代方案提供的,因为当 Redis 用作缓存时,此操作非常常见。 秒无效时返回错误。 | Simple string reply | redis> SETEX mykey 10 “Hello”
“OK”
redis> TTL mykey
(integer) 10
redis> GET mykey
“Hello”
redis> |
| | getset | O(1) | GETSET key value | 原子地将key设置为值并返回存储在键中的旧值。当key存在但不包含字符串值时返回错误。成功的 SET 操作将丢弃与key关联的任何先前的生存时间。

根据 Redis 6.2,GETSET 被视为已弃用。请在新代码中更喜欢带有GET参数的SET。 | Bulk string reply: the old value stored at key, or nil when key did not exist. | redis> SET mykey “Hello”
“OK”
redis> GETSET mykey “World”
“Hello”
redis> GET mykey
“World”
redis> | GETSET可与INCR一起使用以进行原子复位计数。例如:进程可能会在每次发生某些事件时针对键mycounter调用INCR ,但有时我们需要获取计数器的值并将其自动重置为零。这可以使用 GETSET mycounter “0” 来完成::

redis> INCR mycounter
(integer) 1
redis> GETSET mycounter “0”
“1”
redis> GET mycounter
“0”
redis> | | incr | O(1) | INCR key | 将存储的数字key加1。如果key不存在,则在执行操作前设置为0。如果键包含错误类型的值或包含不能表示为整数的字符串,则返回错误。此操作仅限于 64 位有符号整数。

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

Redis 以整数表示形式存储整数,因此对于实际保存整数的字符串值,存储整数的字符串表示没有开销。 | Integer reply: the value of key after the increment | redis> SET mykey “10”
“OK”
redis> INCR mykey
(integer) 11
redis> GET mykey
“11”
redis> |

模式:计数器

计数器模式是你可以用 Redis 原子增量操作做的最明显的事情。这个想法只是在每次发生操作时向 Redis发送一个INCR命令。例如,在一个 Web 应用程序中,我们可能想知道该用户一年中每天的页面浏览量。
为此,Web 应用程序可以在每次用户执行页面查看时简单地增加一个键,创建键名,将用户 ID 和一个表示当前日期的字符串连接起来。
这个简单的模式可以通过多种方式扩展:
- 可以在每次页面查看时一起使用INCREXPIRE以让计数器仅计算间隔小于指定秒数的最新 N 个页面查看。
- 客户端可以使用 GETSET 来自动获取当前计数器值并将其重置为零。
- 使用其他原子递增/递减命令(如DECRINCRBY),可以根据用户执行的操作处理可能变大或变小的值。例如,想象一下在线游戏中不同用户的得分。

模式:速率限制器

速率限制器模式是一个特殊的计数器,用于限制可以执行操作的速率。这种模式的经典实现涉及限制可以针对公共 API 执行的请求数量。
我们使用INCR提供了这种模式的两种实现,我们假设要解决的问题是将 API 调用的数量限制为每个 IP 地址每秒最多 10 个请求。
模式:速率限制器 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 自动删除。
请注意MULTIEXEC的使用,以确保我们将在每次 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 地址。
这可以很容易地修复,将带有可选EXPIREINCR转换为使用EVAL命令发送的 Lua 脚本(仅自 Redis 2.6 版起可用)。

local current
current = redis.call(“incr”,KEYS[1])
if 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命令只会推送元素。
请注意,我们在这里有一个竞争,但这不是问题:EXISTS可能返回 false,但在我们在MULTI / EXEC块内创建密钥之前,密钥可能由另一个客户端创建。然而,这种竞争在极少数情况下只会错过 API 调用,因此速率限制仍将正常工作。 | | incrby | O(1) | INCRBY key increment | 按增量递增存储在键中的数字。如果该键不存在,则在执行操作前将其设置为 0。如果键包含错误类型的值或包含不能表示为整数的字符串,则返回错误。此操作仅限于 64 位有符号整数。
有关递增/递减操作的额外信息,请参阅INCR。 | Integer reply: the value of key after the increment | redis> SET mykey “10”
“OK”
redis> INCRBY mykey 5
(integer) 15
redis>

|
| | decr | O(1) | DECR key | 将存储在key中的数字减1。如果key不存在,则在执行操作前设置为0。如果键包含错误类型的值或包含不能表示为整数的字符串,则返回错误。此操作仅限于64 位有符号整数。
有关递增/递减操作的额外信息,请参阅INCR。 | Integer reply: the value of key after the decrement |
|
| | decrby | O(1) | DECRBY key decrement | 递减存储在key中的数通过decrement。如果key不存在,则0在执行操作前设置为。如果键包含错误类型的值或包含不能表示为整数的字符串,则返回错误。此操作仅限于 64 位有符号整数。
有关递增/递减操作的额外信息,请参阅INCR。 | Integer reply: the value of key after the decrement | redis> SET mykey “10”
“OK”
redis> DECRBY mykey 3
(integer) 7
redis>

|
| | append | O(1)。假设附加值很小并且已经存在的值是任意大小,摊销时间复杂度为 O(1),因为 Redis 使用的动态字符串库将使每次重新分配时可用的可用空间翻倍。 | APPEND key value | 如果key已经存在并且是一个字符串,则此命令将 附加value到字符串的末尾。如果key不存在,则创建并设置为空字符串,因此在这种特殊情况下APPEND 将类似于SET。 | Integer reply: the length of the string after the append operation. | redis> EXISTS mykey
(integer) 0
redis> APPEND mykey “Hello”
(integer) 5
redis> APPEND mykey “ World”
(integer) 11
redis> GET mykey
“Hello World”
redis>

|

模式:时间序列

APPEND命令可以用来创建固定大小的示例的列表的一个非常紧凑的表示中,通常被称为时间序列。每次有新样本到达时,我们都可以使用以下命令存储它
APPEND timeseries “fixed-size sample”
访问时间序列中的单个元素并不难:
- 可以使用STRLEN来获取样本数量。
- GETRANGE允许随机访问元素。如果我们的时间序列有相关的时间信息,我们可以很容易地实现二进制搜索来获取范围,结合GETRANGE和 Redis 2.6 中可用的 Lua 脚本引擎。
- SETRANGE可用于覆盖现有的时间序列。
这种模式的局限性在于我们被迫进入仅追加操作模式,无法轻松地将时间序列剪切到给定大小,因为 Redis 目前缺乏能够修剪字符串对象的命令。然而,以这种方式存储的时间序列的空间效率是显着的。
提示:可以根据当前的 Unix 时间切换到不同的键,这样每个键的样本量可能相对较少,避免处理非常大的键,并使这种模式更加友好地分布在许多 Redis 实例中。
使用固定大小的字符串(在实际实现中使用二进制格式更好)对传感器的温度进行采样的示例。

redis> APPEND ts “0043”
(integer) 4
redis> APPEND ts “0035”
(integer) 8
redis> GETRANGE ts 0 3
“0043”
redis> GETRANGE ts 4 7
“0035”
redis>

| | getrange | O(N) where N is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered O(1) for small strings. | GETRANGE key start end | 警告:此命令已重命名为GETRANGE,它SUBSTR在 Redis 版本中被调用<= 2.0。
返回存储在key的字符串值的子字符串,由偏移量start和end(两者都包含)确定。可以使用负偏移量来提供从字符串末尾开始的偏移量。所以 -1 表示最后一个字符,-2 表示倒数第二个,依此类推。
该函数通过将结果范围限制为字符串的实际长度来处理超出范围的请求。 | Bulk string reply | redis> SET mykey “This is a string”
“OK”
redis> GETRANGE mykey 0 3
“This”
redis> GETRANGE mykey -3 -1
“ing”
redis> GETRANGE mykey 0 -1
“This is a string”
redis> GETRANGE mykey 10 100
“string”
redis> |
| | setrange | O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument. | SETRANGE key offset value | 覆盖存储在key 的部分字符串,从指定的偏移量开始,覆盖value的整个长度。如果偏移量大于key 处字符串的当前长度,则用零字节填充该字符串以使偏移量适合。不存在的键被视为空字符串,因此此命令将确保它包含一个足够大的字符串,以便能够在offset处设置值。
请注意,您可以设置的最大偏移量为 2 29 -1 (536870911),因为 Redis 字符串限制为 512 兆字节。如果您需要增长超过此大小,您可以使用多个密钥。
警告:当设置最后一个可能的字节并且存储在 key中的字符串值还没有保存字符串值,或者保存一个很小的字符串值时,Redis需要分配所有可能阻塞服务器一段时间的中间内存。在 2010 款 MacBook Pro 上,设置字节数 536870911(512MB 分配)需要约 300 毫秒,设置字节数 134217728(128MB 分配)需要约 80 毫秒,设置位号 33554432(32MB 分配)需要约 30 毫秒和设置位号 838860 分配需要~8ms。请注意,一旦第一次分配完成,对相同键的后续调用SETRANGE 不会有分配开销。 | Integer reply: the length of the string after it was modified by the command | Basic usage:
redis> SET key1 “Hello World”
“OK”
redis> SETRANGE key1 6 “Redis”
(integer) 11
redis> GET key1
“Hello Redis”
redis>

Example of zero padding:
redis> SETRANGE key2 6 “Redis”
(integer) 11
redis> GET key2
“\u0000\u0000\u0000\u0000\u0000\u0000Redis”
redis>

| Thanks to SETRANGE and the analogous GETRANGE commands, you can use Redis strings as a linear array with O(1) random access. This is a very fast and efficient storage in many real world use cases. |

List

基本特性

每个 List 理论可以存储 232 -1 键值对(40多亿), 值在键在,值空键亡

数据结构

数据较少:ziplist

  • list-max-ziplist-entries [512~1024]

entries选项说明列表、散列和有序集合在被编码为压缩列表的情况下,允许包含的最大元素数量

  • list-max-ziplist-value 64

value选项则说明了压缩列表每个节点的最大体积是多少个字节

当这些选项设置的限制条件中的任意一个被突破的时候,Redis就会将相应的列表、散列或是有序集合从压缩列表编码转换为其他结构.而内存占用也会因此而增加

数据较多:linkedlist

应用场景

  • 消息排队

常用命令

命令 复杂度 说明 返回值 Examples 模式
lpush O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments. Insert all the specified values at the head of the list stored at key. If key does not exist, it is created as empty list before performing the push operations. When key holds a value that is not a list, an error is returned.
It is possible to push multiple elements using a single command call just specifying multiple arguments at the end of the command. Elements are inserted one after the other to the head of the list, from the leftmost element to the rightmost element. So for instance the command LPUSH mylist a b c will result into a list containing c as first element, b as second element and a as third element.
nteger reply: the length of the list after the push operations. redis> LPUSH mylist “world”
(integer) 1
redis> LPUSH mylist “hello”
(integer) 2
redis> LRANGE mylist 0 -1
1) “hello” 2) “world”
redis>

rpush O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments. Insert all the specified values at the tail of the list stored at key. If key does not exist, it is created as empty list before performing the push operation. When key holds a value that is not a list, an error is returned.
It is possible to push multiple elements using a single command call just specifying multiple arguments at the end of the command. Elements are inserted one after the other to the tail of the list, from the leftmost element to the rightmost element. So for instance the command RPUSH mylist a b c will result into a list containing a as first element, b as second element and c as third element.
Integer reply: the length of the list after the push operation redis> RPUSH mylist “hello”
(integer) 1
redis> RPUSH mylist “world”
(integer) 2
redis> LRANGE mylist 0 -1
1) “hello” 2) “world”
redis>

|
| | lpop | O(N) where N is the number of elements returned | Removes and returns the first elements of the list stored at key.
By default, the command pops a single element from the beginning of the list. When provided with the optional count argument, the reply will consist of up to count elements, depending on the list’s length. | When called without the count argument:
Bulk string reply: the value of the first element, or nil when key does not exist.
When called with the count argument:
Array reply: list of popped elements, or nil when key does not exist. | redis> RPUSH mylist “one” “two” “three” “four” “five”
(integer) 5
redis> LPOP mylist
“one”
redis> LPOP mylist 2
1) “two” 2) “three”
redis> LRANGE mylist 0 -1
1) “four” 2) “five”
redis>

|
| | rpop | O(N) where N is the number of elements returned | Removes and returns the last elements of the list stored at key.
By default, the command pops a single element from the end of the list. When provided with the optional count argument, the reply will consist of up to count elements, depending on the list’s length. | When called without the count argument:
Bulk string reply: the value of the last element, or nil when key does not exist.
When called with the count argument:
Array reply: list of popped elements, or nil when key does not exist. | redis> RPUSH mylist “one” “two” “three” “four” “five”
(integer) 5
redis> RPOP mylist
“five”
redis> RPOP mylist 2
1) “four” 2) “three”
redis> LRANGE mylist 0 -1
1) “one” 2) “two”
redis>

|
| | rpoplpush | O(1) | Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element at the first element (head) of the list stored at destination.
For example: consider source holding the list a,b,c, and destination holding the list x,y,z. Executing RPOPLPUSH results in source holding a,b and destination holding c,x,y,z.
If source does not exist, the value nil is returned and no operation is performed. If source and destination are the same, the operation is equivalent to removing the last element from the list and pushing it as first element of the list, so it can be considered as a list rotation command.
As per Redis 6.2.0, RPOPLPUSH is considered deprecated. Please prefer LMOVE in new code. | Bulk string reply: the element being popped and pushed | redis> RPUSH mylist “one”
(integer) 1
redis> RPUSH mylist “two”
(integer) 2
redis> RPUSH mylist “three”
(integer) 3
redis> RPOPLPUSH mylist myotherlist
“three”
redis> LRANGE mylist 0 -1
1) “one” 2) “two”
redis> LRANGE myotherlist 0 -1
1) “three”
redis>

|
- Pattern: Reliable queue
Redis is often used as a messaging server to implement processing of background jobs or other kinds of messaging tasks. A simple form of queue is often obtained pushing values into a list in the producer side, and waiting for this values in the consumer side using RPOP (using polling), or BRPOP if the client is better served by a blocking operation.
However in this context the obtained queue is not reliable as messages can be lost, for example in the case there is a network problem or if the consumer crashes just after the message is received but before it can be processed.
RPOPLPUSH (or BRPOPLPUSH for the blocking variant) offers a way to avoid this problem: the consumer fetches the message and at the same time pushes it into a processing list. It will use the LREM command in order to remove the message from the processing list once the message has been processed.
An additional client may monitor the processing list for items that remain there for too much time, pushing timed out items into the queue again if needed.

- Pattern: Circular list
Using RPOPLPUSH with the same source and destination key, a client can visit all the elements of an N-elements list, one after the other, in O(N) without transferring the full list from the server to the client using a single LRANGE operation.
The above pattern works even if one or both of the following conditions occur:
- There are multiple clients rotating the list: they’ll fetch different elements, until all the elements of the list are visited, and the process restarts.
- Other clients are actively pushing new items at the end of the list.
The above makes it very simple to implement a system where a set of items must be processed by N workers continuously as fast as possible. An example is a monitoring system that must check that a set of web sites are reachable, with the smallest delay possible, using a number of parallel workers.
Note that this implementation of workers is trivially scalable and reliable, because even if a message is lost the item is still in the queue and will be processed at the next iteration. | | lrange | O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range. | Returns the specified elements of the list stored at key. The offsets start and stop are zero-based indexes, with 0 being the first element of the list (the head of the list), 1 being the next element and so on.
These offsets can also be negative numbers indicating offsets starting at the end of the list. For example, -1 is the last element of the list, -2 the penultimate, and so on.
Consistency with range functions in various programming languages
Note that if you have a list of numbers from 0 to 100, LRANGE list 0 10 will return 11 elements, that is, the rightmost item is included. This may or may not be consistent with behavior of range-related functions in your programming language of choice (think Ruby’s Range.new, Array#slice or Python’s range() function).
Out-of-range indexes
Out of range indexes will not produce an error. If start is larger than the end of the list, an empty list is returned. If stop is larger than the actual end of the list, Redis will treat it like the last element of the list | Array reply: list of elements in the specified range. | redis> RPUSH mylist “one”
(integer) 1
redis> RPUSH mylist “two”
(integer) 2
redis> RPUSH mylist “three”
(integer) 3
redis> LRANGE mylist 0 0
1) “one”
redis> LRANGE mylist -3 2
1) “one” 2) “two” 3) “three”
redis> LRANGE mylist -100 100
1) “one” 2) “two” 3) “three”
redis> LRANGE mylist 5 10
(empty list or set)
redis>

|
| | llen | O(1) | Returns the length of the list stored at key. If key does not exist, it is interpreted as an empty list and 0 is returned. An error is returned when the value stored at key is not a list. | Integer reply: the length of the list at key. | redis> LPUSH mylist “World”
(integer) 1
redis> LPUSH mylist “Hello”
(integer) 2
redis> LLEN mylist
(integer) 2
redis>

|
| | lindex | Time complexity: O(N) where N is the number of elements to traverse to get to the element at index. This makes asking for the first or the last element of the list O(1). | Returns the element at index index in the list stored at key. The index is zero-based, so 0 means the first element, 1 the second element and so on. Negative indices can be used to designate elements starting at the tail of the list. Here, -1 means the last element, -2 means the penultimate and so forth.
When the value at key is not a list, an error is returned. | Bulk string reply: the requested element, or nil when index is out of range. | redis> LPUSH mylist “World”
(integer) 1
redis> LPUSH mylist “Hello”
(integer) 2
redis> LINDEX mylist 0
“Hello”
redis> LINDEX mylist -1
“World”
redis> LINDEX mylist 3
(nil)
redis>

|
| | lset | O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1). | Sets the list element at index to element. For more information on the index argument, see LINDEX.
An error is returned for out of range indexes. | Simple string reply | redis> RPUSH mylist “one”
(integer) 1
redis> RPUSH mylist “two”
(integer) 2
redis> RPUSH mylist “three”
(integer) 3
redis> LSET mylist 0 “four”
“OK”
redis> LSET mylist -2 “five”
“OK”
redis> LRANGE mylist 0 -1
1) “four” 2) “five” 3) “three”
redis>

|
| | lrem | O(N+M) where N is the length of the list and M is the number of elements removed. | Removes the first count occurrences of elements equal to element from the list stored at key. The count argument influences the operation in the following ways:
- count > 0: Remove elements equal to element moving from head to tail.
- count < 0: Remove elements equal to element moving from tail to head.
- count = 0: Remove all elements equal to element.
For example, LREM list -2 “hello” will remove the last two occurrences of “hello” in the list stored at list.
Note that non-existing keys are treated like empty lists, so when key does not exist, the command will always return 0. | Integer reply: the number of removed elements. | redis> RPUSH mylist “hello”
(integer) 1
redis> RPUSH mylist “hello”
(integer) 2
redis> RPUSH mylist “foo”
(integer) 3
redis> RPUSH mylist “hello”
(integer) 4
redis> LREM mylist -2 “hello”
(integer) 2
redis> LRANGE mylist 0 -1
1) “hello” 2) “foo”
redis>

|
| | ltrim | O(N) where N is the number of elements to be removed by the operation. | Trim an existing list so that it will contain only the specified range of elements specified. Both start and stop are zero-based indexes, where 0 is the first element of the list (the head), 1 the next element and so on.
For example: LTRIM foobar 0 2 will modify the list stored at foobar so that only the first three elements of the list will remain.
start and end can also be negative numbers indicating offsets from the end of the list, where -1 is the last element of the list, -2 the penultimate element and so on.
Out of range indexes will not produce an error: if start is larger than the end of the list, or start > end, the result will be an empty list (which causes key to be removed). If end is larger than the end of the list, Redis will treat it like the last element of the list.

A common use of LTRIM is together with LPUSH / RPUSH. For example:
LPUSH mylist someelement
LTRIM mylist 0 99

This pair of commands will push a new element on the list, while making sure that the list will not grow larger than 100 elements. This is very useful when using Redis to store logs for example. It is important to note that when used in this way LTRIM is an O(1) operation because in the average case just one element is removed from the tail of the list. | Simple string reply | redis> RPUSH mylist “one”
(integer) 1
redis> RPUSH mylist “two”
(integer) 2
redis> RPUSH mylist “three”
(integer) 3
redis> LTRIM mylist 1 -1
“OK”
redis> LRANGE mylist 0 -1
1) “two” 2) “three”
redis>

|
|

Hash

基本特性

  • Redis Hash 是一个键值(key=>value)对集合
  • 每个 Hash 理论可以存储 232 -1 键值对(40多亿)

数据结构

数据较少:ziplist

  • hash-max-ziplist-entries 512~1024

entries选项说明列表、散列和有序集合在被编码为压缩列表的情况下,允许包含的最大元素数量

  • hash-max-ziplist-value 64

value选项则说明了压缩列表每个节点的最大体积是多少个字节

当这些选项设置的限制条件中的任意一个被突破的时候,Redis就会将相应的列表、散列或是有序集合从压缩列表编码转换为其他结构.而内存占用也会因此而增加

数据较多:散列表

应用场景

  • 表示复杂的对象

常用命令

命令 复杂度 说明 返回值 Examples 模式
hset O(1) for each field/value pair added, so O(N) to add N field/value pairs when the command is called with multiple field/value pairs. HSET key field value [field value …]

Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created. If field already exists in the hash, it is overwritten.
As of Redis 4.0.0, HSET is variadic and allows for multiple field/value pairs.
Integer reply: The number of fields that were added. redis> HSET myhash field1 “Hello”
(integer) 1
redis> HGET myhash field1
“Hello”
redis>

hsetnx O(1) HSETNX key field value

Sets field in the hash stored at key to value, only if field does not yet exist. If key does not exist, a new key holding a hash is created. If field already exists, this operation has no effect.
Integer reply, specifically:
- 1 if field is a new field in the hash and value was set.
- 0 if field already exists in the hash and no operation was performed.
redis> HSETNX myhash field “Hello”
(integer) 1
redis> HSETNX myhash field “World”
(integer) 0
redis> HGET myhash field
“Hello”
redis>

hmset O(N) where N is the number of fields being set. HMSET key field value [field value …]

Sets the specified fields to their respective values in the hash stored at key. This command overwrites any specified fields already existing in the hash. If key does not exist, a new key holding a hash is created.
As per Redis 4.0.0, HMSET is considered deprecated. Please prefer HSET in new code.
Simple string reply redis> HMSET myhash field1 “Hello” field2 “World”
“OK”
redis> HGET myhash field1
“Hello”
redis> HGET myhash field2
“World”
redis>

hget O(1) HGET key field

Returns the value associated with field in the hash stored at key.
Bulk string reply: the value associated with field, or nil when field is not present in the hash or key does not exist. redis> HSET myhash field1 “foo”
(integer) 1
redis> HGET myhash field1
“foo”
redis> HGET myhash field2
(nil)
redis>

hgetall O(N) where N is the size of the hash. HGETALL key

Returns all fields and values of the hash stored at key. In the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash.
Array reply: list of fields and their values stored in the hash, or an empty list when key does not exist. redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HGETALL myhash
1) “field1” 2) “Hello” 3) “field2” 4) “World”
redis>

hmget O(N) where N is the number of fields being requested. HMGET key field [field …]

Returns the values associated with the specified fields in the hash stored at key.
For every field that does not exist in the hash, a nil value is returned. Because non-existing keys are treated as empty hashes, running HMGET against a non-existing key will return a list of nil values.
Array reply: list of values associated with the given fields, in the same order as they are requested. redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HMGET myhash field1 field2 nofield
1) “Hello” 2) “World” 3) (nil)
redis>

hexists O(1) HEXISTS key field

Returns if field is an existing field in the hash stored at key.
Integer reply, specifically:
- 1 if the hash contains field.
- 0 if the hash does not contain field, or key does not exist.
redis> HSET myhash field1 “foo”
(integer) 1
redis> HEXISTS myhash field1
(integer) 1
redis> HEXISTS myhash field2
(integer) 0
redis>

hkeys O(N) where N is the size of the hash. HKEYS key

Returns all field names in the hash stored at key.
Array reply: list of fields in the hash, or an empty list when key does not exist. redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HKEYS myhash
1) “field1” 2) “field2”
redis>

hvals O(N) where N is the size of the hash. Returns all values in the hash stored at key. Array reply: list of values in the hash, or an empty list when key does not exist. redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HVALS myhash
1) “Hello” 2) “World”
redis>

hdel O(N) where N is the number of fields to be removed. HDEL key field [field …]

Removes the specified fields from the hash stored at key. Specified fields that do not exist within this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.
Integer reply: the number of fields that were removed from the hash, not including specified but non existing fields. redis> HSET myhash field1 “foo”
(integer) 1
redis> HDEL myhash field1
(integer) 1
redis> HDEL myhash field2
(integer) 0
redis>

hlen O(1) HLEN key

Returns the number of fields contained in the hash stored at key.
Integer reply: number of fields in the hash, or 0 when key does not exist redis> HSET myhash field1 “Hello”
(integer) 1
redis> HSET myhash field2 “World”
(integer) 1
redis> HLEN myhash
(integer) 2
redis>

hincrby O(1) HINCRBY key field increment

Increments the number stored at field in the hash stored at key by increment. If key does not exist, a new key holding a hash is created. If field does not exist the value is set to 0 before the operation is performed.
The range of values supported by HINCRBY is limited to 64 bit signed integers.
Integer reply: the value at field after the increment operation. Since the increment argument is signed, both increment and decrement operations can be performed:

redis> HSET myhash field 5
(integer) 1
redis> HINCRBY myhash field 1redis> HINCRBY myhash field -1redis> HINCRBY myhash field -10
(integer) 6
(integer) 5
(integer) -5
redis>

hstrlen O(1) HSTRLEN key field

Returns the string length of the value associated with field in the hash stored at key. If the key or the field do not exist, 0 is returned.
Integer reply: the string length of the value associated with field, or zero when field is not present in the hash or key does not exist at all.

ZSet

基本特性

  • Redis 的 ZSet 是 String 类型的有序集合
  • Redis 的 ZSet中的成员不能重复是唯一的
  • ZSet中的成员会关联一个double类型分数
  • Redis的ZSet中的成员唯一但分数可以重复
  • 每个 ZSet 理论可以存储 232 -1 键值对(40多亿)

数据结构

数据较少:ziplist

  • zset-max-ziplist-entries 512~1024

entries选项说明列表、散列和有序集合在被编码为压缩列表的情况下,允许包含的最大元素数量

  • zset-max-ziplist-value 64

value选项则说明了压缩列表每个节点的最大体积是多少个字节

当这些选项设置的限制条件中的任意一个被突破的时候,Redis就会将相应的列表、散列或是有序集合从压缩列表编码转换为其他结构.而内存占用也会因此而增加

数据较多:散列表+skiplist

应用场景

  • 存储可排序的数据,如排行榜单
  • 从排序集合中获取到排名最靠前的 10个用户
  • 延时队列。拿时间戳作为score,消费者用zrangbyscore指令获取N秒之前的数据轮询进行处理

    常用命令

命令 复杂度 说明 options 返回值 Examples 模式
zadd O(log(N)) for each item added, where N is the number of elements in the sorted set. ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member …]


Adds all the specified members with the specified scores to the sorted set stored at key. It is possible to specify multiple score / member pairs. If a specified member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering.
If key does not exist, a new sorted set with the specified members as sole members is created, like if the sorted set was empty. If the key exists but does not hold a sorted set, an error is returned.
The score values should be the string representation of a double precision floating point number. +inf and -inf values are valid values as well.
ZADD supports a list of options, specified after the name of the key and before the first score argument. Options are:
- XX: Only update elements that already exist. Don’t add new elements.
- NX: Only add new elements. Don’t update already existing elements.
- LT: Only update existing elements if the new score is less than the current score. This flag doesn’t prevent adding new elements.
- GT: Only update existing elements if the new score is greater than the current score. This flag doesn’t prevent adding new elements.
- CH: Modify the return value from the number of new elements added, to the total number of elements changed (CH is an abbreviation of changed). Changed elements are new elements added and elements already existing for which the score was updated. So elements specified in the command line having the same score as they had in the past are not counted. Note: normally the return value of ZADD only counts the number of new elements added.
- INCR: When this option is specified ZADD acts like ZINCRBY. Only one score-element pair can be specified in this mode.

Note: The GT, LT and NX options are mutually exclusive. | Integer reply, specifically:
- When used without optional arguments, the number of elements added to the sorted set (excluding score updates).
- If the CH option is specified, the number of elements that were changed (added or updated).
If the INCR option is specified, the return value will be Bulk string reply:
- The new score of member (a double precision floating point number) represented as string, or nil if the operation was aborted (when called with either the XX or the NX option).
| redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 1 “uno”
(integer) 1
redis> ZADD myzset 2 “two” 3 “three”
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) “one”
2) “1”
3) “uno”
4) “1”
5) “two”
6) “2”
7) “three”
8) “3”
redis> |
| | zrange | O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned. | ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]

Returns the specified range of elements in the sorted set stored at .
ZRANGE can perform different types of range queries: by index (rank), by the score, or by lexicographical order.
Starting with Redis 6.2.0, this command can replace the following commands: ZREVRANGE, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZRANGEBYLEX and ZREVRANGEBYLEX. |
| Array reply: list of elements in the specified range (optionally with their scores, in case the WITHSCORES option is given). | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZRANGE myzset 0 -1
1) “one” 2) “two” 3) “three”
redis> ZRANGE myzset 2 3
1) “three”
redis> ZRANGE myzset -2 -1
1) “two” 2) “three”
redis>

The following example using WITHSCORES shows how the command returns always an array, but this time, populated with element_1, score_1, element_2, score_2, …, element_N, score_N.
redis> ZRANGE myzset 0 1 WITHSCORES
1) “one” 2) “1” 3) “two” 4) “2”
redis>
This example shows how to query the sorted set by score, excluding the value 1 and up to infinity, returning only the second element of the result:
redis> ZRANGE myzset (1 +inf BYSCORE LIMIT 1 1
1) “three”
redis>

|
| | zrangebyscore | O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)). | ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

Returns all the elements in the sorted set at key with a score between min and max (including elements with score equal to min or max). The elements are considered to be ordered from low to high scores.
The elements having the same score are returned in lexicographical order (this follows from a property of the sorted set implementation in Redis and does not involve further computation).
As per Redis 6.2.0, this command is considered deprecated. Please prefer using the ZRANGE command with the BYSCORE argument in new code.
The optional LIMIT argument can be used to only get a range of the matching elements (similar to SELECT LIMIT offset, count in SQL). A negative count returns all elements from the offset. Keep in mind that if offset is large, the sorted set needs to be traversed for offset elements before getting to the elements to return, which can add up to O(N) time complexity.
The optional WITHSCORES argument makes the command return both the element and its score, instead of the element alone. This option is available since Redis 2.0. | Exclusive intervals and infinity
min and max can be -inf and +inf, so that you are not required to know the highest or lowest score in the sorted set to get all elements from or up to a certain score.
By default, the interval specified by min and max is closed (inclusive). It is possible to specify an open interval (exclusive) by prefixing the score with the character (. For example:

ZRANGEBYSCORE zset (1 5

Will return all elements with 1 < score <= 5 while:

ZRANGEBYSCORE zset (5 (10

Will return all the elements with 5 < score < 10 (5 and 10 excluded). | Array reply: list of elements in the specified range (optionally with their scores, in case the WITHSCORES option is given). | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZRANGEBYSCORE myzset -inf +inf
1) “one” 2) “two” 3) “three”
redis> ZRANGEBYSCORE myzset 1 2
1) “one” 2) “two”
redis> ZRANGEBYSCORE myzset (1 2
1) “two”
redis> ZRANGEBYSCORE myzset (1 (2
(empty list or set)
redis>

|
- Pattern: weighted random selection of an element


Normally ZRANGEBYSCORE is simply used in order to get range of items where the score is the indexed integer key, however it is possible to do less obvious things with the command.
For example a common problem when implementing Markov chains and other algorithms is to select an element at random from a set, but different elements may have different weights that change how likely it is they are picked.
This is how we use this command in order to mount such an algorithm:
Imagine you have elements A, B and C with weights 1, 2 and 3. You compute the sum of the weights, which is 1+2+3 = 6 | | zrevrangebyscore | O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)). | ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

Returns all the elements in the sorted set at key with a score between max and min (including elements with score equal to max or min). In contrary to the default ordering of sorted sets, for this command the elements are considered to be ordered from high to low scores.
The elements having the same score are returned in reverse lexicographical order.
Apart from the reversed ordering, ZREVRANGEBYSCORE is similar to ZRANGEBYSCORE.
As per Redis 6.2.0, this command is considered deprecated. Please prefer using the ZRANGE command with the BYSCORE and REV arguments in new code. |
| Array reply: list of elements in the specified score range (optionally with their scores). | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZREVRANGEBYSCORE myzset +inf -inf
1) “three” 2) “two” 3) “one”
redis> ZREVRANGEBYSCORE myzset 2 1
1) “two” 2) “one”
redis> ZREVRANGEBYSCORE myzset 2 (1
1) “two”
redis> ZREVRANGEBYSCORE myzset (2 (1
(empty list or set)
redis>

|
| | zremrangebyscore | O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation. | ZREMRANGEBYSCORE key min max

Removes all elements in the sorted set stored at key with a score between min and max (inclusive).
Since version 2.1.6, min and max can be exclusive, following the syntax of ZRANGEBYSCORE. |
| Integer reply: the number of elements removed. | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZREMRANGEBYSCORE myzset -inf (2
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) “two” 2) “2” 3) “three” 4) “3”
redis>

|
| | zrem | O(Mlog(N)) with N being the number of elements in the sorted set and M the number of elements to be removed. | ZREM key member [member …]

Removes the specified members from the sorted set stored at key. Non existing members are ignored.
An error is returned when key exists and does not hold a sorted set. |
| Integer reply, specifically:
- The number of members removed from the sorted set, not including non existing members
| redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZREM myzset “two”
(integer) 1
redis> *ZRANGE myzset 0 -1 WITHSCORES

1) “one” 2) “1” 3) “three” 4) “3”
redis>

|
| | zcard | O(1) | ZCARD key

Returns the sorted set cardinality (number of elements) of the sorted set stored at key. |
| Integer reply: the cardinality (number of elements) of the sorted set, or 0 if key does not exist. | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZCARD myzset
(integer) 2
redis>

|
| | zcount | O(log(N)) with N being the number of elements in the sorted set. | Returns the number of elements in the sorted set at key with a score between min and max.
The min and max arguments have the same semantic as described for ZRANGEBYSCORE.
Note: the command has a complexity of just O(log(N)) because it uses elements ranks (see ZRANK) to get an idea of the range. Because of this there is no need to do a work proportional to the size of the range. |
| Integer reply: the number of elements in the specified score range. | redis> ZADD myzset 1 “one”
(integer) 1
redis> ZADD myzset 2 “two”
(integer) 1
redis> ZADD myzset 3 “three”
(integer) 1
redis> ZCOUNT myzset -inf +inf
(integer) 3
redis> ZCOUNT myzset (1 3
(integer) 2
redis>

|
|

Set

基本特性

  • Redis 的 Set 是 String 类型的无序集合
  • Redis 的 Set 中的成员不能重复是唯一的
  • Redis 的 Set可以计算并集,交集,差集
  • 每个 Set 理论可以存储 232 -1 键值对(40多亿)
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)

数据结构

数据较少:intset

  • 阈值
    • 集合所有元素都是十进制整数
    • set -max-intset-entries 512
  • 优点
    • 节省数据的存储空间
  • 缺点
    • 整数集合在编码解码时候所带来的性能开销
    • 整数集合插入删除操作带来的数据移动开销

当这些选项设置的限制条件中的任意一个被突破的时候,Redis就会将相应的列表、散列或是有序集合从压缩列表编码转换为其他结构.而内存占用也会因此而增加

数据较多:hashtable

  • 元素不都是整数 或 元素数大于set -max-intset-entries

应用场景

  • 关注好友
  • 共同好友

常用命令

命令 格式 复杂度 说明 返回值 例子 模式
sadd SADD key member [member …] O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments. Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members.
An error is returned when the value stored at key is not a set.
Integer reply: the number of elements that were added to the set, not including all the elements already present in the set. redis> SADD myset “Hello”
(integer) 1
redis> SADD myset “World”
(integer) 1
redis> SADD myset “World”
(integer) 0
redis> SMEMBERS myset
1) “Hello” 2) “World”
redis>

|
| | scard | SCARD key | O(1) | Returns the set cardinality (number of elements) of the set stored at key. | Integer reply: the cardinality (number of elements) of the set, or 0 if key does not exist. | redis> SADD myset “Hello”
(integer) 1
redis> SADD myset “World”
(integer) 1
redis> SCARD myset
(integer) 2
redis>
|
| | smembers | SMEMBERS key | O(N) where N is the set cardinality. | Returns all the members of the set value stored at key.
This has the same effect as running SINTER with one argument key. | Array reply: all elements of the set. | redis> SADD myset “Hello”
(integer) 1
redis> SADD myset “World”
(integer) 1
redis> SMEMBERS myset
1) “Hello” 2) “World”
redis>
|
| | sismember | SISMEMBER key member | O(1) | Returns if member is a member of the set stored at key. | Integer reply, specifically:
- 1 if the element is a member of the set.
- 0 if the element is not a member of the set, or if key does not exist.
| redis> SADD myset “one”
(integer) 1
redis> SISMEMBER myset “one”
(integer) 1
redis> SISMEMBER myset “two”
(integer) 0
redis>

|
| | srem | SREM key member [member …] | O(N) where N is the number of members to be removed. | Remove the specified members from the set stored at key. Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0.
An error is returned when the value stored at key is not a set. | Integer reply: the number of members that were removed from the set, not including non existing members. | redis> SADD myset “one”
(integer) 1
redis> SADD myset “two”
(integer) 1
redis> SADD myset “three”
(integer) 1
redis> SREM myset “one”
(integer) 1
redis> SREM myset “four”
(integer) 0
redis> SMEMBERS myset
1) “three” 2) “two”
redis>

|
| | srandmember | SRANDMEMBER key [count] | Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count. | When called with just the key argument, return a random element from the set value stored at key.
If the provided count argument is positive, return an array of distinct elements. The array’s length is either count or the set’s cardinality (SCARD), whichever is lower.
If called with a negative count, the behavior changes and the command is allowed to return the same element multiple times. In this case, the number of returned elements is the absolute value of the specified count. | Bulk string reply: without the additional count argument, the command returns a Bulk Reply with the randomly selected element, or nil when key does not exist.
Array reply: when the additional count argument is passed, the command returns an array of elements, or an empty array when key does not exist. | redis> SADD myset one two three
(integer) 3
redis> SRANDMEMBER myset
“three”
redis> SRANDMEMBER myset 2
1) “three” 2) “two”
redis> SRANDMEMBER myset -5
1) “one”
2) “two”
3) “two”
4) “one”
5) “two”
redis>

| Specification of the behavior when count is passed
When the count argument is a positive value this command behaves as follows:
- No repeated elements are returned.
- If count is bigger than the set’s cardinality, the command will only return the whole set without additional elements.
- The order of elements in the reply is not truly random, so it is up to the client to shuffle them if needed.
When the count is a negative value, the behavior changes as follows:
- Repeating elements are possible.
- Exactly count elements, or an empty array if the set is empty (non-existing key), are always returned.
- The order of elements in the reply is truly random.


Distribution of returned elements
Note: this section is relevant only for Redis 5 or below, as Redis 6 implements a fairer algorithm.
The distribution of the returned elements is far from perfect when the number of elements in the set is small, this is due to the fact that we used an approximated random element function that does not really guarantees good distribution.
The algorithm used, that is implemented inside dict.c, samples the hash table buckets to find a non-empty one. Once a non empty bucket is found, since we use chaining in our hash table implementation, the number of elements inside the bucket is checked and a random element is selected.
This means that if you have two non-empty buckets in the entire hash table, and one has three elements while one has just one, the element that is alone in its bucket will be returned with much higher probability. | | SUNION | SUNION key [key …] | O(N) where N is the total number of elements in all given sets. | Returns the members of the set resulting from the union of all the given sets. | Array reply: list with members of the resulting set. | redis> SADD key1 “a”
(integer) 1
redis> SADD key1 “b”
(integer) 1
redis> SADD key1 “c”
(integer) 1
redis> SADD key2 “c”
(integer) 1
redis> SADD key2 “d”
(integer) 1
redis> SADD key2 “e”
(integer) 1
redis> SUNION key1 key2
1) “a” 2) “c” 3) “e” 4) “d” 5) “b”
redis>

|
| | sunionstore | SUNIONSTORE destination key [key …] | O(N) where N is the total number of elements in all given sets. | This command is equal to SUNION, but instead of returning the resulting set, it is stored in destination.
If destination already exists, it is overwritten. | Integer reply: the number of elements in the resulting set | redis> SADD key1 “a”
(integer) 1
redis> SADD key1 “b”
(integer) 1
redis> SADD key1 “c”
(integer) 1
redis> SADD key2 “c”
(integer) 1
redis> SADD key2 “d”
(integer) 1
redis> SADD key2 “e”
(integer) 1
redis> SUNIONSTORE key key1 key2
(integer) 5
redis> SMEMBERS key
1) “a” 2) “c” 3) “e” 4) “d” 5) “b”
redis>

|
| | sdiff | SDIFF key [key …] | O(N) where N is the total number of elements in all given sets. | Returns the members of the set resulting from the difference between the first set and all the successive sets. | Array reply: list with members of the resulting set. | redis> SADD key1 “a”
(integer) 1
redis> SADD key1 “b”
(integer) 1
redis> SADD key1 “c”
(integer) 1
redis> SADD key2 “c”
(integer) 1
redis> SADD key2 “d”
(integer) 1
redis> SADD key2 “e”
(integer) 1
redis> SDIFF key1 key2
1) “b” 2) “a”
redis>

| | | sdiffstore | SDIFFSTORE destination key [key …] | O(N) where N is the total number of elements in all given sets. | This command is equal to SDIFF, but instead of returning the resulting set, it is stored in destination.
If destination already exists, it is overwritten. | Integer reply: the number of elements in the resulting set. | redis> SADD key1 “a”
(integer) 1
redis> SADD key1 “b”
(integer) 1
redis> SADD key1 “c”
(integer) 1
redis> SADD key2 “c”
(integer) 1
redis> SADD key2 “d”
(integer) 1
redis> SADD key2 “e”
(integer) 1
redis> SDIFFSTORE key key1 key2
(integer) 2
redis> SMEMBERS key
1) “b” 2) “a”
redis>

| | | sinter | SINTER key [key …] | O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets. | Returns the members of the set resulting from the intersection of all the given sets.

Keys that do not exist are considered to be empty sets. With one of the keys being an empty set, the resulting set is also empty (since set intersection with an empty set always results in an empty set). | Array reply: list with members of the resulting set. | redis> SADD key1 “a”
(integer) 1
redis> SADD key1 “b”
(integer) 1
redis> SADD key1 “c”
(integer) 1
redis> SADD key2 “c”
(integer) 1
redis> SADD key2 “d”
(integer) 1
redis> SADD key2 “e”
(integer) 1
redis> SINTER key1 key2
1) “c”
redis>

| | | smove | SMOVE source destination member | O(1) | Move member from the set at source to the set at destination. This operation is atomic. In every given moment the element will appear to be a member of source or destination for other clients.
If the source set does not exist or does not contain the specified element, no operation is performed and 0 is returned. Otherwise, the element is removed from the source set and added to the destination set. When the specified element already exists in the destination set, it is only removed from the source set.
An error is returned if source or destination does not hold a set value | Integer reply, specifically:
- 1 if the element is moved.
- 0 if the element is not a member of source and no operation was performed.
| redis> SADD myset “one”
(integer) 1
redis> SADD myset “two”
(integer) 1
redis> SADD myotherset “three”
(integer) 1
redis> SMOVE myset myotherset “two”
(integer) 1
redis> SMEMBERS myset
1) “one”
redis> SMEMBERS myotherset
1) “three” 2) “two”
redis>

| |