公用命令
可以删除任意数据结构的key
del key
查看所有key
keys *
根据给定的选项,对输入列表、集合或者有序集合进行排序,然后返回或者存储排序的结果。
sort source-key [by pattern] [limit offset count] [get pattern [get pattern ...]] [asc|desc] [alpha] [store dest-key]
查看数据库有多少个key
dbsize
清除所有库的数据
flushall
清除当前库的所有数据
flushdb
查看reids内存信息等
info
监控所有客户发送的命令(redis编译执行成功的命令)
monitor
处理时间
移除键的过期时间
persist key
查看给定键距离过期还有多少秒
ttl key
给定键在指定的秒数后过期
expire key seconds
将给定键的过期时间设置为给定的unix时间戳
expireat key timestamp
查看给定键距离过期时间还有多少毫秒,这个命令在reids2.6以上版本可用。
pttl key
让给定键在指定的毫秒数之后过期,这个命令在redis2.6以上版本可用。
pexpire key milliseconds
将一个毫秒级精度的unix 时间戳设置为给定键的过期时间,这个命令在redis2.6以上版本可用。
pexpireat key timestamp-milliseconds
自增和自减
将键存储的值+1
incr key
将键存储的值-1
decr key
将键存储的值加上整数amount
incrby key amount
将键存储的值减去整数amount
decrby key amount
将键存储的值加上浮点数amount,这个命令在Redis2.6以上版本可用
incrbyfloat key amount
字符串 String 可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB
创建一个键值对 set key value
127.0.0.1:6379> set a 1234567890
OK
获取key存储的值 get key
127.0.0.1:6379> get a
"1234567890"
将值value追加到给定 key 当前存储的值的末尾,追加成功的发返回值为这个字符串的长度(length) append key value
127.0.0.1:6379> append a a
(integer) 11
127.0.0.1:6379> get a
"1234567890a"
获取一个由偏移量start至end范围内的所有字符组成的字串,包括start和end在内。getrange key start end
127.0.0.1:6379> getrange a 0 3
"1234"
将从start偏移量开始的字串设置为给定值 setrange key offset value
127.0.0.1:6379> setrange a 3 bcde
(integer) 11
127.0.0.1:6379> get a
"123bcde890a"
列表 list 用来存储多个有序的字符串,列表中的每个字符串称为元素(element),一个列表最多可以存储2^32 -1个元素
将一个或多个值推入列表的右端 rpush key value[...]
127.0.0.1:6379> LRANGE b 0 -1
1) "5"
2) "6"
127.0.0.1:6379> RPUSH b 7 8
(integer) 4
127.0.0.1:6379> LRANGE b 0 -1
1) "5"
2) "6"
3) "7"
4) "8"
获取 list 元素数量 llen
127.0.0.1:6379[1]> llen 32021420001:90000300009999:10002:1601198414621
(integer) 2
lpush key value[...] -> 将一个或多个值推入列表的左端
127.0.0.1:6379> LPUSH b 1 2
(integer) 6
127.0.0.1:6379> LRANGE b 0 -1
1) "2"
2) "1"
3) "5"
4) "6"
5) "7"
6) "8"
rpop key -> 移除并返回列表最右端的元素
127.0.0.1:6379> rpop b
"8"
127.0.0.1:6379> LRANGE b 0 -1
1) "2"
2) "1"
3) "5"
4) "6"
5) "7"
lpop key -> 移除并返回列表最左端的元素
127.0.0.1:6379> lpop b
"2"
127.0.0.1:6379> LRANGE b 0 -1
1) "1"
2) "5"
3) "6"
4) "7"
lindex key offset -> 返回列表中偏移量为offset的元素(下标从0开始)
127.0.0.1:6379> lindex b 3
"7"
lrange key start end -> 返回列表从start偏移量到end偏移量范围的所有元素。包含start 和 end 本身。lrange key 0 -1 为查询所有
127.0.0.1:6379> LRANGE b 0 2
1) "1"
2) "5"
3) "6"
ltrim key start end -> 对列表进行修键,只保留从start至end偏移量的元素,包含start 和 end。
127.0.0.1:6379> LTRIM b 1 2
OK
127.0.0.1:6379> LRANGE b 0 -1
1) "5"
2) "6"
blpop key[...] timeout -> 从第一个非空列表中弹出位于最左端的元素,或者在timeout秒之内阻塞并等待可弹出的元素出现(一下测试没有元素所以nil)
127.0.0.1:6379> BLPOP c 10
(nil)
(10.03s)
brpop key[...] timeout -> 从第一个非空列表中弹出位于最右端的元素,或者在timeout秒之内阻塞并等待可弹出的元素出现(一下测试没有元素所以nil)
127.0.0.1:6379> brpop c 10
(nil)
(10.07s)
rpoplpush source-key dest-key -> 从source-key 列表中弹出位于最右端的元素,然后将这个元素推入dest-key 列表的最左端,并向用户返回这个元素
brpoplpush source-key dest-key timeout -> 从source-key 列表中弹出位于最右端的元素,然后将这个元素推入dest-key 列表的最左端,并向用户返回这个元素;如果source-key为空,那么在timeout秒之内阻塞并等待可弹出的元素出现。
集合 set 用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素
sadd key item[...] -> 将一个或多个元素添加到集合里面,并返回被添加元素当中原本并不存在于集合里面的元素数量。
srem key item[...] -> 从集合里面删除一个或多个元素,并返回被移除元素的数量。
sismember key item -> 检查元素item是否存在于集合key里面。
scard key -> 返回集合包含的元素数量。
smembers key -> 返回集合包含的所有元素。
srandmember key [count] -> 从集合里随机的返回一个或多个元素,当count 为正整数时,命令返回的随机元素不会重复;当count为负数时,命令返回的随机元素可能会出现重复。
spop key -> 随机的移除集合中的一个元素,并返回被移除的元素。
smove source-key dest-key item -> 如果集合source-key包含元素item,那么从集合source-key 里面移除y元素item,并将元素item添加到集合dest-key中;如果item成功移除,那么命令返回1,否则返回0;
sdiff key[...] -> 返回那些存在于第一个集合、但不存在于其他集合中的元素(数学上的差集运算)
sdiffstore dest-key key[...] -> 将那些存在于第一个集合但不存在于其他集合的元素(数学上的差集运算)存储到dest-key 键里面
sinter key[...] -> 返回那些同时存在于所有集合中的元素(数学上的交集运算)
sinter dest-key key[...] -> 那些同时存在于所有集合中的元素(数学上的交集运算)存储到dest-key键里面。
sunion key[...] -> 返回那些至少存在于一个集合中的元素(数学上讲的并集运算)
sunionstore dest-key key[...] -> 那些至少存在于一个集合中的元素(数学上讲的并集运算)存储到dest-key键里面。
散列 hash 哈希类型是指键值本身又是一个键值对结构,value={{field1,value1},…{fieldN,valueN}}
hset key-name key value -> 创建一个散列并赋值
hget key-name key -> 返回指定散列键的值
hgetall key-name -> 获取散列包含的所有键值对
hmset key-name key value[key value ...] -> 为散列里面的一个或多个键设置值
hmget key-name key[...] -> 从散列里面获取一个或多个键的值
hlen key-name -> 返回散列包含的键值对数量
hdel key-name key[...] -> 删除散列里面的一个或多个键值对,返回成功找到并删除的键值对数量。
hexists key-name key -> 检查给定的键是否存在于散列中
hkeys key-name -> 获取散列包含的所有键
hvals key-name -> 获取散列包含的所有值
hincrby key-name key increment -> 将键key存储的值加上整数increment
hincrbyfloat key-name key increment -> 将键key存储的值加上浮点数increment
有序集合 zset 不能有重复的元素,而且还可以排序,它和列表使用索引下标作为排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依据(默认升序)
zadd key score member [score member ...] -> 将带有给定分值的成员添加到有序集合里面
zrem key member[...] -> 从有序集合里面移除给定的成员,并返回被移除成员的数量
zcard key -> 返回有序集合包含的成员数量
zincrby key increment member -> 将member成员的分值加上increment
zcount key min max -> 返回分值介于min 和max 之间的成员数量
zrank key member -> 返回成员member在有序集合中的排名
zscore key member -> 返回成员member的分值
zrange key start stop [withscores] -> 返回有序集合中排名介于start 和 stop 之间的成员,如果给定了可选的 withscores 选项,那么会将成员的分值一并返回。zrange key 0 -1 查询所有成员
zrevrank key member -> 返回有序集合里成员member的排名,成员按照分值从大到小排列
zrevrange key start stop [withscores] -> 返回有序集合给定排名范围内的成员,按照分值从大到小排列
zrangebyscore key min max [withscores] [left offset count] -> 返回有序集合中,分值介于min和max之间的所有成员
zrevrangebyscore key max min [withscores] [left offset count] -> 获取有序集合中分值介于min和max之间的所有成员,并按照分值从大到小的顺序来返回他们。
zremrangebyrank key start top -> 移除有序集合中排名介于start 和 stop 之间的成员。
zremrangebyscore key min max -> 移除有序集合中分值介于min和max 之间的成员。
zinterstore dest-key key-count key[...] [weights weight[...] ] [aggregate sum|min|max] -> 对给定的有序集合执行类似于集合的交集运算
zunionstore dest-key key-count key[...] [weights weight[...] ] [aggregate sum|min|max] -> 对指定的有序集合执行类似于集合的并集运算
订阅/发布
subscribe channel[...] -> 订阅给定的一个或多个频道
unsubscribe channel[...] -> 退订给定的一个或多个频道,如果执行时没有给定任何频道,那么退订所有频道
publish channel message -> 向给定的频道发送消息
psubscribe pattern[...] -> 订阅与给定模式相匹配的所有频道
punsubscribe pattern[...] -> 退订给定的模式,如果执行时没有给定任何模式,那么退订所有模式。
Redis5 之 Streams 数据类型
Redis 5.0 全新的数据类型:streams,官方把它定义为:以更抽象的方式建模日志的数据结构。Redis的streams主要是一个append only的数据结构,至少在概念上它是一种在内存中表示的抽象数据类型,只不过它们实现了更强大的操作,以克服日志文件本身的限制。
如果你了解MQ,那么可以把streams当做MQ。如果你还了解kafka,那么甚至可以把streams当做kafka。
另外,这个功能有点类似于redis以前的Pub/Sub,但是也有基本的不同:
streams支持多个客户端(消费者)等待数据(Linux环境开多个窗口执行XREAD即可模拟),并且每个客户端得到的是完全相同的数据。
Pub/Sub是发送忘记的方式,并且不存储任何数据;而streams模式下,所有消息被无限期追加在streams中,除非用于显示执行删除(XDEL)。
streams的Consumer Groups也是Pub/Sub无法实现的控制方式。
streams数据结构
streams数据结构本身非常简单,但是streams依然是Redis到目前为止最复杂的类型,其原因是实现的一些额外的功能:一系列的阻塞操作允许消费者等待生产者加入到streams的新数据。另外还有一个称为Consumer Groups(消费组)的概念,这个概念最先由kafka提出,Redis有一个类似实现,和kafka的Consumer Groups的目的是一样的:允许一组客户端协调消费相同的信息流!
streams基础
为了理解streams的目的,以及如何使用它,我们先忽略掉所有高级特性,只把注意力放在数据结构本身,以及那些操作和访问streams的命令。这基本上也是大多数其他Redis数据类型共有的部分,例如Lists,Sets,Sorted Sets等。然而需要注意的是,Lists也有一个更复杂的阻塞式的API,例如BLPOP,BRPOP等。streams这方便的API也没什么不同,只是更复杂,更强大(更牛逼,哈)!
streams命令
废话不多说,先上手玩玩这个全新的数据类型。streams这个数据类型对应有如下13个操作命令,所有命令都以"X"开头:
XADD
用法:XADD key ID field string [field string …]
正如其名,这个命令就是用来添加的,给streams追加(append,前面提到过:streams主要是一个append only的数据结构)一个新的entry(和Java里的Map类似,Redis里的streams中的数据也称为entry)。
key:的含义就是同一类型streams的名称;
ID: streams中entry的唯一标识符,如果执行XADD命令时,传入星号(*),那么,ID会自动生成,且自动生成的ID会在执行XADD后返回,默认生成的ID格式为millisecondsTime+sequenceNumber,即当前毫秒级别的时间戳加上一个自增序号值,例如"1540013735401-0"。并且执行XADD时,不接受少于或等于上一次执行XADD的ID,否则会报错:ERR The ID specified in XADD is equal or smaller than the target stream top item;
field&string:接下来就是若干组field string。可以把它理解为表示属性的json中的key-value。例如,某一streams的key命名为userInfo,且某个用户信息为{"username":"afei", "password":"123456"},那么执行XADD命令如下:
127.0.0.1:6379> xadd userInfo * name afei password 123456
"1594456377383-0"
127.0.0.1:6379>
由于命令中ID字段的值是 * ,所以自定生成ID,1594456377383-0 就是自动生成的ID。 XADD命令也支持显示指定ID,例如:XADD key 0-2 field string。
需要注意的是,ID的时间戳部分是部署Redis服务器的本地时间,如果发生时钟回拨会怎么样?如果发生时钟回拨,生成的ID的时间戳部分就是回拨后的时间,然后加上这个时间的递增序列号。例如当前时间戳1540014082060,然后这时候发生了时钟回拨,且回拨5ms,那么时间戳就是1540014082055。假设以前已经生成了1540014082055-0,1540014082055-1,那么这次由于时钟回拨,生成的ID就是1540014082055-2。所以允许自动生成的ID在发生时钟回拨时少于上次的ID,但是不允许显示指定一个少于上次的ID。
如果我们以相同的 key 插入一遍,他不会像普通的key-value一样做替换,而是在相同key维护这一个列表。
xdel
- 用法:XDEL key ID [ID …]
和XADD相反,这是命令用来从streams中删除若干个entry,并且会返回实际删除数,这个删除数可能和参数ID个数不等,因为某些ID表示的消息可能不存在。执行命令如下,第二个参数ID是不存在的,所以XDEL的返回结果是1:
127.0.0.1:6379> xdel userInfo 1594456377383-0
(integer) 1
xlen
- 用法:XLEN key
很好理解,这个命令就是用来返回相同 key 的数量,上面又说相同key是不会覆盖的,是维护了一个列表,所以这个是相同key 列表的size。执行如下:
127.0.0.1:6379> xadd user * name zhangsan
"1594457206541-0"
127.0.0.1:6379> xlen user
(integer) 1
127.0.0.1:6379> xadd user * name zhangsan sex 0
"1594457274424-0"
127.0.0.1:6379> xlen user
(integer) 2
127.0.0.1:6379> xadd user * name zhangsan sex 0 password 123
"1594457287981-0"
127.0.0.1:6379> xlen user
(integer) 3
127.0.0.1:6379> xdel user 1594457287981-0
(integer) 1
127.0.0.1:6379> xlen user
(integer) 2
127.0.0.1:6379>
streams三种查询模式
redis提供了三种查询streams数据的模式:
范围查询:因为streams的每个entry,其默认生成的ID是基于时间且递增的;
监听模式:类比linux中的tailf命令,实时接收新增加到streams中的entry(也有点像一个消息系统,事实上笔者认为它就是借鉴了kafka);
消费者组:即Consumer Groups,特殊的监听模式。从一个消费者的角度来看streams,一个streams能被分区到多个处理消息的消费者,对于任意一条消息,同一个消费者组中只有一个消费者可以处理(和kafka的消费者组完全一样)。这样还能够横向扩容消费者,从而提升处理消息的能力,而不需要只让把让一个消费者处理所有消息。
xrange
- 用法:XRANGE key start end [COUNT count]
这个命令属于第1种模式,即基于范围查询。这个命令用来返回streams某个顺序范围下的元素,start参数是更小的ID,end参数是更大的ID。有两个特殊的ID用符号"-"和"+"表示,符号"-"表示最小的ID,符号"+"表示最大的ID:
127.0.0.1:6379> XRANGE user 1540014096298-0 1594457274424-0
1) 1) "1594457206541-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1594457274424-0"
2) 1) "name"
2) "zhangsan"
3) "sex"
4) "0"
127.0.0.1:6379> xrange user - +
1) 1) "1594457206541-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1594457274424-0"
2) 1) "name"
2) "zhangsan"
3) "sex"
4) "0"
3) 1) "1594458356220-0"
2) 1) "name"
2) "wu"
XRANGE还能实现遍历某个范围区间的功能,例如我想遍历2018-10-20号新增的用户信息。首先得到2018-10-20 00:00:00对应的时间戳为1539964800000,再得到2018-10-20 23:59:59对应的时间戳为1540051199000,然后执行如下命令:
127.0.0.1:6379> xrange user 1594457206541-0 1594458356220-0 count 1
1) 1) "1594457206541-0"
2) 1) "name"
2) "zhangsan"
127.0.0.1:6379> xrange user 1594457206541-0 1594458356220-0 count 2
1) 1) "1594457206541-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1594457274424-0"
2) 1) "name"
2) "zhangsan"
3) "sex"
4) "0"
xrevrange
- 用法:XREVRANGE key end start [COUNT count]
这个命令也属于第1种模式,且和XRANGE相反,返回一个逆序范围。end参数是更大的ID,start参数是更小的ID
xread
- 用法:XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] ID [ID …]
很明显,这个命令就是用来实现第2个模式,即监听模式。其作用是返回streams中从来没有读取的,且比参数ID更大的元素。
这里我开了两个窗口测试,且第一个没有做新增,第二个做了新增.
127.0.0.1:6379> XREAD COUNT 10 BLOCK 60000 STREAMS user 1594458356220-0
(nil)
(60.02s)
127.0.0.1:6379> XREAD COUNT 10 BLOCK 60000 STREAMS user 1594458356220-0
1) 1) "user"
2) 1) 1) "1594458985980-0"
2) 1) "name"
2) "ceshi"
(13.37s)
127.0.0.1:6379>
使用xread 会阻塞特定时间,等待比我ID大的数据,如果使用最小ID进行测试,会跟xrange user - + 效果是一样的。
注意:BLOCK为0表示一致等待知道有新的数据,否则永远不会超时。并且ID的值我们用特殊字符$
表示,这个特殊字符表示我们只获取最新添加的消息。
127.0.0.1:6379> xread count 10 block 0 streams user $
xread 还支持同时监听多个streams
127.0.0.1:6379> XREAD BLOCK 0 STREAMS user_01 user_02 user_03 user_04 $ $ $ $
XREAD除了COUNT和BLOCK,没有其他选项了。所有XREAD是一个非常基本的命令。更多高级特性可以往下看接下来要介绍的XREADGROUP。
XREADGROUP
- 用法:XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key …] ID [ID …]
很明显,这就是第三种模式:消费者组模式。 - 如果你了解kafka的消费者组,那么你就也了解了streams的消费者组。如果不了解也没关系,笔者简单解释一下,假设有三个消费者C1,C2,C3。在streams中总计有7条消息:1, 2, 3, 4, 5, 6, 7,那么消费关系如下所示:
1 -> C1
2 -> C2
3 -> C3
4 -> C1
5 -> C2
6 -> C3
7 -> C1 - 消费者组具备如下几个特点:
同一个消息不会被投递到一个消费者组下的多个消费者,只可能是一个消费者。
同一个消费者组下,每个消费者都是唯一的,通过大小写敏感的名字区分。
消费者组中的消费者请求的消息,一定是新的,从来没有投递过的消息。
消费一个消息后,需要用命令(XACK)确认,意思是说:这条消息已经给成功处理。正因为如此,当访问streams的历史消息时,每个消费者只能看到投递给它自己的消息。
XACK
- 用法:XACK key group ID [ID …]
- 这是消费者组相关的另一个重要的命令。标记一个处理中的消息为已被正确处理,如此一来,这条消息就会被从消费者组的pending消息集合中删除,类似MQ中的ack。
XGROUP
- 用法:xgroup create key groupname id
- 这也是消费者组的一个重要命令,这个命令用来管理消费者组,例如创建,删除等。
XREADGROUP,XACK,XGROUP三种命令构成了消费者组相关的操作命令。
目前XGROUP CREATE的streams必须是一个存在的streams,否则会报错。
创建一个消费组
127.0.0.1:6379> XGROUP CREATE user GRP-AFEI $
OK
文中内容关于 Redis5 之 Streams 数据类型 来自 阿飞的博客