Redis数据结构简介
Redis可以存储键与5种不同数据结构类型之间的映射,这五种数据结构分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)、和Zset(有序集合)。
结构类型 | 结构存储的值 | 结构的读写能力 |
---|---|---|
String | 字符串、整数或者浮点数 | 对整个字符串或者字符串的一部分执行操作;对整数和浮点数执行自增或者自减操作 |
List | 一个链表,链表上的每个节点都包含一个字符串 | 从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值查找或者移除元素 |
Set | 包含字符串的无序收集器 ,并且被包含的每个字符串都是独一无二、各不相同的 | 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素 |
Hash | 包含键值对的无序散列表 | 添加、获取、移除单个键值对;获取所有键值对 |
ZSet | 字符串成员与浮点数分值之间的有序映射,元素的排列顺序由分值的大小决定 | 添加、获取、移除单个元素;根据分值范围或者成员来获取元素 |
Redis中的字符串
字符串可以存储以下3种类型的值
- 字符串
- 整数
- 浮点数
基本操作:
命令 | 用例 | 描述 |
---|---|---|
GET | get key-name | 获取字符串的值 |
Set | set key-name | 设置字符串的值 |
Del | del key-name | 删除字符串的值 |
整数和浮点数类型操作:
命令 | 用例 | 描述 |
---|---|---|
INCR | incr key-name | 将键存储的值加1 |
DECR | decr key-name | 将键存储的值减去1 |
INCRBY | incrby key-name amount | 将键存储的值加上整数amount |
DECRBY | decrby key-name amount | 将键存储的值减去整数amount |
INCRBYFLOAT | incrbyfloat key-name amount | 将键存储的值减去浮点数amount |
当用户将一个值存储到Redis字符串里面的时候,如果这个值可以被解释为十进制整数或者浮点数,那么Redis就允许用户对这个字符串执行各种incr *和decr *操作。如果用户对一个不存在的键或者一个保存了空串的键执行自增或者自减操作,那么redis在执行操作时会将这个键的值当作0来处理。
如果用户尝试对一个值无法被解释为整数或者浮点数的字符串键执行自增或者自减操作,那么Redis会向用户返回一个错误。
字符串操作:
命令 | 用例 | 描述 |
---|---|---|
APPEND | append key-name value | 将值value追加到给定键当前存储的值的末尾 |
GETRANGE | getrange key-name start end | 获取一个由偏移量start至偏移量end范围内所有字符组成的子串,包括start 和end |
SETRANGE | setrange key-name offset value | 从指定的偏移量offset开始,用给定的值覆盖原有值 |
GETBIT | getbit key-name offset | 将字节传看作是二进制位串(bit string),返回位串中偏移量为offset的二进制位的值 |
SETBIT | setbit key-name offset value | 将字节传看作是二进制位串,并将位串中偏移量为offset的二进制位的值设置为value |
BITCOUNT | bitcount key-name < start end> | 统计二进制位串里值为1的二进制位的数量,如果给定了可选的start和end。那么只对偏移量指定范围内的二进制位进行统计 |
BITTOP | bittop operation dest-key key-name [key-name...] | 对一个或者多个二进制位串执行包括 并、或、异或、非在内的任意一种按位运算操作,并将结果值保存到dest-key中 |
补充:什么是二进制位串?
假设我们有一个键 mykey,其二进制表示为 01001000 01100101 01101100 01101100 01101111(对应字符串 "Hello")。 那么 字符H的二进制位串表示为0【第0位】1【第1位】0【第2位】0【第3位】1【第4位】0【第5位】0【第6位】0【第7位】,获取偏移量为6的位值为0.即getbit mykey 6 返回结果0。
Redis中的列表
redis对链表结构的支持使得他在键值存储的世界中独树一帜。一个列表结构可以有序的存储多个字符串。列表的主要优点在于他可以包含多个字符串值,使得用户可以将数据集中在同一个地方。Redis集合也提供了与列表相似的特性,但集合只能保存不相同的元素。
列表的常用操作:
命令 | 用例 | 描述 |
---|---|---|
RPUSH | rpush key-name value[value...] | 将一个或者多个值推入列表的右端 |
LPUSH | LPUSH key-name value[value...] | 将一个或者多个值推入列表的左端 |
RPOP | RPOP key-name | 移除并返回列表最右端的元素 |
LPOP | LPOP key-name | 移除并返回列表最左端的元素 |
LINDEX | LINDEX key-name offset | 返回列表中偏移量为offset的元素 |
LRANGE | LRANGE key-name start end | 返回列表从start偏移量到end偏移量范围内的所有元素,其中start和end位置的元素也包含在内 |
LTRIM | LTRIM key-name start end | 对列表进行修剪,只保留从start偏移量到end偏移量范围内的元素,start和end位置元素也保留 |
结合LRANGE和LTRIM 可以构建出一个在功能上类似于LPOP和RPOP,但是一次能够返回并弹出多个元素的操作。
阻塞式的列表弹出命令以及在列表之间移动元素的命令:
命令 | 用例 | 描述 |
---|---|---|
BLPOP | BLPOP key [key ...] timeout | 从列表的左侧弹出元素。如果列表为空,它会阻塞连接,直到有新的元素被推入或达到超时时间 |
BRPOP | BRPOP key [key ...] timeout | 从列表的右侧弹出元素。如果列表为空,它会阻塞连接,直到有新的元素被推入或达到超时时间 |
RPOPLPUSH | RPOPLPUSH source-key dest-key | 从source-key列表中弹出位于最右端的元素,然后将这个元素推入dest-key列表的最左端,并向用户返回这个元素 |
BRPOPLPUSH | BRPOPLPUSH source-key dest-key timeout | 从source-key列表中弹出位于最右端的元素,然后将这个元素推入dest-key列表的最左端,并向用户返回这个元素;如果source-key 为空,那么timeout秒之内阻塞并弹出元素 |
对于阻塞弹出命令和弹出并推入命令,最常见的用例就是消息传度和任务队列。
Redis中的集合
redis的集合和列表都可以存储多个字符串,他们之间的不同在于,列表可以存储多个相同的字符串,而集合则通过使用散列表来保证自己存储的每个字符串各不相同。
redis的集合使用无序方式存储多个各不相同的元素,用户可以快速的对集合执行添加元素、删除元素以及检查一个元素是否在集合里等操作。
集合的常用操作:
命令 | 用例 | 描述 |
---|---|---|
SADD | SADD key-name item[item...] | 将一个或者多个值添加到集合里面 |
SREM | SREM key-name value[value...] | 从集合里面移除一个或者多个元素 |
SISMEMBER | SISMEMBER key-name item | 检查元素item是否存在于集合key-name中 |
SCARD | SCARD key-name | 返回集合包含的元素数量 |
SMEMBERS | SMEMBERS key-name | 返回集合包含的元素 |
SRANDMEMBER | SRANDMEMBER key-name [count] | 从集合里面随机的返回一个或者多个元素 |
SPOP | SPOP key-name | 随机的移除集合中的一个元素,并返回被移除的元素 |
SMOVE | SMOVE source-key dest-key item | 如果集合source-key包含元素item,那么从集合source-key里面移除元素item,并将元素item添加到集合dest-key中 |
组合和处理多个集合的命令:
命令 | 用例 | 描述 |
---|---|---|
SDIFF | SDIFF key-name [key-name ...] | 返回那些存在于第一个集合、但不存在于其他集合中的元素(差集运算) |
SDIFFSTORE | SDIFFSTORE dest-key key-name [key-name ...] | 将那些存在于第一个集合但不存在于其他集合的元素存储到dest-key中 |
SINTER | SINTER key-name [key-name ...] | 返回那些同时存在于所有集合中的元素(交集运算) |
SINTERSTORE | SINTERSTORE dest-key key-name [key-name ...] | 将那些同时存在于所有集合的元素存储到dest-key中 |
SUNION | SUNION key-name [key-name ...] | 返回至少存在于一个集合中的元素(并集运算) |
SUNIONSTORE | SUNIONSTORE dest-key key-name [key-name ...] | 将那些至少存在于一个集合中的元素存储到dest-key中 |
Redis中的散列
redis的散列可以存储多个键值对之间的映射。和字符串一样,散列存储的值既可以是字符串又可以是数字值,并且用户可以对散列存储的数字值进行自增和自减操作。
散列的常用操作:
命令 | 用例 | 描述 |
---|---|---|
HSET | HSET hash-key sub-key value | 在散列里面关联起给定的键值对 |
HGET | HGET hash-key sub-key | 获取指定散列键的值 |
HGETALL | HGETALL hash-key | 获取散列包含的所有键值对 |
HDEL | HDEL hash-key sub-key | 如果给定键存在于散列里面,移除这个键 |
散列的其他常用操作:
命令 | 用例 | 描述 |
---|---|---|
HMGET | HMGET key-name key[key...] | 从散列里面获取一个或者多个键的值 |
HMSET | HMSET key-name key value [key value...] | 为散列里面的一个或者多个键设置值 |
HLEN | HLEN key-name | 返回散列包含的键值对数量 |
使用示例
bash
HMSET user:1000 name "John Doe" age "30" email "john.doe@example.com"
HMGET user:1000 name email
返回:
1) "John Doe"
2) "john.doe@example.com"
散列的更高级特性:
命令 | 用例 | 描述 |
---|---|---|
HEXISTS | HEXISTS key-name key | 检查给定键是否存在于散列中 |
HKEYS | HKEYS key-name | 获取散列包含的所有键 |
HVALS | HVALS key-name | 获取散列包含的所有值 |
HGETALL | HGETALL key-name | 获取散列包含的所有键值对 |
HINCRBY | HINCRBY key-name key increment | 将键key存储的值加上整数increment |
HINCRBYFLOAT | HINCRBYFLOAT key-name key increment | 将键key存储的值加上浮点数increment |
尽管有HGETALL存在,但是HKEYS和HVALUES也是非常有用的,如果散列包含的值非常大,那么用户可以先使用HKEYS取出散列包含的所有键,然后使用HGET一个一个的获取键的值,从而避免因为一次获取大体积的值导致服务器阻塞。
Redis中的有序集合
有序集合和散列一样,都用于存储键值对,有序集合的键被称为成员,每个成员都是各不相同的。而有序集合的值被称为分值(score),分值必须为浮点数。有序集合是Redis里面唯一一个既可以根据成员访问元素(这一点和散列一样),又可以根据分值以及分值的排列顺序来访问元素的结构。
有序集合常用操作:
命令 | 用例 | 描述 |
---|---|---|
ZADD | zadd zset-key score sub-key | 将一个带有给定分值的成员添加到有序集合里面 |
ZRANGE | ZRANGE key start stop [WITHSCORES] | 用于获取有序集合中指定区间内的成员。成员是按分数(score)从低到高排序的。WITHSCORES可选参数,如果提供此参数则同时返回分数 |
ZREM | ZREM zset-key sub-key | 如果给定成员存在于有序集合,则移除这个成员 |
ZCARD | ZCARD key-name | 返回有序集合包含的成员数量 |
ZINCRBY | ZINCRBY key-name increment member | 将member成员的分值加上increment |
ZCOUNT | ZCOUNT key-name min max | 返回分值介于min和max之间的成员数量 |
ZRANK | ZRANK key-name member | 返回成员member在有序集合中的排名 |
ZSCORE | ZSCORE key-name member | 返回成员member的分值 |
ZRANGE | ZRANGE key-name start stop [withscores] | 返回有序集合中排名介于start 和stop之间的成员,如果给定了withscores选项,那么命令会将成员分值一并返回 |
有序集合范围型数据获取命令和范围型数据删除命令以及并集交集命令:
命令 | 用例 | 描述 |
---|---|---|
zrevrank | zrevrank key-name member | 返回有序集合里成员member的排名,成员按照分值从小到大排列 |
zrevrange | zrevrange key-name start stop[withscores] | 返回有序集合里给定排名范围内的成员,成员分值从小到大排列 |
ZRANGEBYSCORE | ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | 用于获取有序集合中指定分数范围内的成员。成员按分数从低到高排序。limit offset count等可选参数用于限制返回的偏移量以及数量 |
ZREVRANGEBYSCORE | ZREVRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | 获取有序集合中分值介于min和max之间的成员,并按照分值从大到小顺序排列。 |
zremrangebyrank | zremrangebyrank key-name start stop | 移除有序集合中排名介于start和stop之间的所有成员 |
zremrangebyscore | zremrangebyscore key-name min max | 移除有序集合中分值介于min和max之间的所有成员 |
zinterstore | ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] | 计算给定的一个或多个有序集合的交集,并将结果存储在新的有序集合中。结果集中每个成员的分数是所有输入有序集合中该成员分数的和(默认情况),或者根据用户提供的聚合方式进行计算。 |
zunionstore | zunionstore dest-key key-count key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] | 同上,对给定的有序集合执行类似于集合的并集运算 |
zinterstore示例
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
bash
ZADD zset1 1 "one" 2 "two" 3 "three"
ZADD zset2 2 "one" 3 "two" 4 "four"
计算zset1和zset2的交集,并将结果存储到out中
ZINTERSTORE out 2 zset1 zset2
查看out中的结果
ZRANGE out 0 -1 WITHSCORES
输出
1) "one"
2) "3"
3) "two"
4) "5"
如果使用权重计算交集,例如,将 zset1 的权重设为 2,将 zset2 的权重设为 3:
ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
返回结果
1) "one"
2) "8" // 1*2 + 2*3 = 2 + 6 = 8
3) "two"
4) "13" // 2*2 + 3*3 = 4 + 9 = 13
如果使用 MIN 作为聚合方式:
ZINTERSTORE out 2 zset1 zset2 AGGREGATE MIN
返回结果
1) "one"
2) "1" // MIN(1, 2) = 1
3) "two"
4) "2" // MIN(2, 3) = 2
发布与订阅
redis提供的发布与订阅命令:
命令 | 用例 | 描述 |
---|---|---|
subscribe | subscribe channel [channel...] | 订阅给定的一个或者多个频道 |
unsubscribe | unsubscribe channel [channel...] | 退订给定的一个或者多个频道,如果执行时没有给定任何频道,那么退订所有频道 |
publish | publish channel message | 向给定频道发送消息 |
psubscribe | psubscribe pattern [pattern...] | 订阅与给定模式相匹配的所有频道 |
punsubscribe | punsubscribe pattern [pattern...] | 退订给定的模式,如果执行时没有给定任何模式,那么退订所有模式 |
Redis发布与订阅模式的问题
- Redis系统稳定性:对于旧版的Redis来说,如果一个客户端订阅了某个频道,但他读取消息的速度不够快的话,那么不断积压的消息会使得Redis输出缓冲区的体积变得越来越大。这可能会导致Redis速度变慢,甚至直接崩溃。也可能会导致Redis被操作系统强制杀死,甚至导致操作系统本身不可用。
- 数据传输的可靠性:任何网络系统在执行操作时都可能会遇上断线情况,而断线产生的连接错误通常会使得网络连接两端中的其中一端进行重新连接。但是,如果客户端在执行订阅操作过程中断线,那么客户端将丢失在断线期间发送的所有消息。