Redis在线测试:http://try.redis.io/,可用来练习大部分命令
Redis命令官方文档:https://redis.io/commands/
Redis的String能表达3种值的类型:字符串、整数、浮点数。
应用场景:
分布式全局自增id
使用incr递增数字
普通的字符串缓存
setnx用于分布式锁
当value不存在时采用赋值,可用于实现分布式锁
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
SET | SET key value | 赋值,设置key对应的value 如果对一个key执行多次SET操作,则会覆盖之前的值 |
GET | GET key | 取值,获取key对应的value |
MGET | MGET key1 [key2…] | 获取所有(一个或多个)给定key的值 |
MSET | MSET key value [key value …] | 同时设置一个或多个key-value对 |
GETSET | GETSET key value | 赋值并获取旧的值,Redis 6.2.0版本之后,这个命令已经被标记为过时的,可用SET命令 + GET作为参数替代 |
SETNX | SETNX key value | 当value不存在时才赋值 |
SETEX | SETEX key seconds value | 设置key对应的value,并将key的过期时间设为seconds(以秒为单位) |
STRLEN | STRLEN key | 返回key所储存的字符串值的长度 |
INCR | INCR key | 将key中储存的数字值加一 |
INCRBY | INCRBY key increment | 将key所储存的值加上给定的增量值(increment) |
DECR | DECR key | 将key中储存的数字值减一 |
DECRBY | DECRBY key decrement | 将key所储存的值减去给定的减量值(decrement) |
APPEND | APPEND key value | 如果key已经存在并且是一个字符串, APPEND命令将指定的value追加到该key原来值的末尾 如果key不存在,则类似SET命令,初始化一个key-value键值对 |
示例:
127.0.0.1:6379> set test-key hello #设置test-key的value为hello
OK
127.0.0.1:6379> get test-key #获取test-key的值
"hello"
127.0.0.1:6379>
127.0.0.1:6379> del test-key #删除key
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> get test-key #删除后,获取不存在的key返回nil
(nil)
127.0.0.1:6379>
127.0.0.1:6379> getset color red #赋值并获取,key没有旧值返回nil
(nil)
127.0.0.1:6379> getset color green #赋值并获取之前的值
"red"
127.0.0.1:6379>
127.0.0.1:6379> set message hello
OK
127.0.0.1:6379> append message world #拼接指定字符串至key对应的value后
(integer) 10
127.0.0.1:6379> get message
"helloworld"
127.0.0.1:6379>
127.0.0.1:6379> set count 0
OK
127.0.0.1:6379> incr count #将count对应的数值加1
(integer) 1
127.0.0.1:6379> incrby count 10 #将count对应的数值加10
(integer) 11
127.0.0.1:6379> decr count #将count对应值减1
(integer) 10
127.0.0.1:6379>
List列表类型可以存储有序、可重复的元素。Redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
应用场景:
列表有序,结合不同的命令可以模拟栈(先入后出)或队列(先入先出);
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
LPOP | LPOP key [count] | 移除并获取列表头部的一个或几个元素(从左边移除并获取) |
RPOP | RPOP key [count] | 移除并获取列表尾部的一个或几个元素(从右边移除并获取) |
LPUSH | LPUSH key value1 [value2…] | 向列表左边(头部)添加一个或多个值 |
RPUSH | RPUSH key value1 [value2…] | 向列表右边(尾部)添加一个或多个值 |
LLEN | LLEN key | 获取列表长度 |
LRANGE | LRANGE key start stop | 获取列表指定范围内的元素 |
LREM | LREM key count element | 删除列表元素 count > 0 : 从左至右删除和element相等的指定个数的元素 count < 0 : 从右至左删除和element相等的指定个数的元素 count = 0 : 删除所有和element相等的元素 |
LSET | LSET key index value | 通过索引设置列表元素的值 |
LINDEX | LINDEX key index | 通过索引获取列表中的元素 |
示例:
127.0.0.1:6379> rpush language java c c++ go python php ruby # 向列表中依次从左至右添加7个元素
(integer) 7
127.0.0.1:6379> lpush language scala #从列表左边添加一个元素
(integer) 8
127.0.0.1:6379> lrange language 0 7 #查看所有列表数据,注意:下表是从0开始的
1) "scala"
2) "java"
3) "c"
4) "c++"
5) "go"
6) "python"
7) "php"
8) "ruby"
127.0.0.1:6379> rpop language #从右边移除并获取(弹出)一个元素
"ruby"
127.0.0.1:6379> llen language
(integer) 7
127.0.0.1:6379> lpop language 2 #从左边移除并获取(弹出)两个元素
1) "scala"
2) "java"
127.0.0.1:6379> llen language
(integer) 5
127.0.0.1:6379> lrange language 0 4
1) "c"
2) "c++"
3) "go"
4) "python"
5) "php"
127.0.0.1:6379> lindex language 2 #获取列表中坐标为2(第三个)元素
"go"
127.0.0.1:6379>
127.0.0.1:6379> lset language 2 c# #将坐标为2的元素go替换为c#
OK
127.0.0.1:6379> lindex language 2
"c#"
127.0.0.1:6379>
问题:
如何使用Redis的List结构实现队列和栈?
队列:(保证添加和移除方向相反即可)
RPUSH + LPOP (所有数据从尾部/右边添加、从头部/左边移除)<更贴近生活>
LPUSH + RPOP
栈:(保证添加和移除方向相同即可)
LPUSH + LPOP (所有数据从头部添加、从头部移除)<更贴近栈的实现>
RPUSH + RPOP
Redis的Set是String类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
应用场景:
黑白名单
使用SISMEMBER命令可快速判断元素是否在集合内
共同好友、可能认识的人
使用SINTER、SDIFF命令可判断两个集合的交集、差集
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
SADD | SADD key member1 [member2…] | 向集合添加一个或多个成员 |
SCARD | SCARD key | 获取集合的成员数 |
SMEMBERS | SMEMBERS key | 返回集合中的所有成员 |
SPOP | SPOP key | 返回集合中的一个随机元素,并删除该元素 |
SRANDMEMBER | SRANDMEMBER key [count] | 返回集合中一个或多个随机元素,不会删除该元素 |
SREM | SREM key member1 [member2] | 移除集合中一个或多个元素,不会返回该元素 |
SISMEMBER | SISMEMBER key member | 判断元素是否在集合内 |
SINTER | SINTER key1 [key2…] | 返回给定所有集合的交集(相同的元素) |
SDIFF | SDIFF key1 [key2…] | 返回给定所有集合在第一个指定的集合中的公共差集(不相同的元素) |
SUNION | SUNION key1 [key2…] | 返回给定所有集合的并集(合并所有集合) |
示例:
127.0.0.1:6379> sadd languages:lucy java python golang # Lucy掌握的变成语言
(integer) 3
127.0.0.1:6379> sadd languages:tony java scala c # Tony掌握的变成语言
(integer) 3
127.0.0.1:6379> sadd languages:henry java python php # Henry掌握编程语言
(integer) 3
127.0.0.1:6379> scard languages:lucy # 查看集合成员数
(integer) 3
127.0.0.1:6379> smembers languages:lucy # 查看集合所有成员
1) "java"
2) "golang"
3) "python"
127.0.0.1:6379> sdiff languages:lucy languages:henry # 查看Lucy掌握的语言中,Henry不掌握的
1) "golang"
127.0.0.1:6379> sdiff languages:henry languages:lucy # 查看Henry掌握的语言中,Lucy不掌握的
1) "php"
127.0.0.1:6379> sdiff languages:lucy languages:henry languages:tony # 查看Lucy掌握的语言中,Henry和Tony都不掌握的
1) "golang"
127.0.0.1:6379> sinter languages:lucy languages:henry # 查看Lucy和Henry掌握的共同语言
1) "java"
2) "python"
127.0.0.1:6379> sunion languages:lucy languages:henry # 查看Lucy和Henry两人掌握的所有语言
1) "java"
2) "golang"
3) "php"
4) "python"
127.0.0.1:6379>
127.0.0.1:6379> sismember languages:lucy java # 判断Lucy是否掌握Java (1代表true,0代表false)
(integer) 1
127.0.0.1:6379> sismember languages:lucy c
(integer) 0
127.0.0.1:6379>
127.0.0.1:6379> spop languages:tony # 随机取出并删除一个集合元素
"scala"
127.0.0.1:6379> smembers languages:tony
1) "java"
2) "c"
127.0.0.1:6379>
Redis 有序集合又叫Zset,和Set一样也是String类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个Double类型的分数。Redis正是通过分数来为集合中的成员进行排序。
有序集合的成员是唯一的,但分数(Score)却可以重复。
应用场景:
由于可以按照分值排序,所以适用于各种排行榜。比如:点击排行榜、销量排行榜、搜索排行榜等。
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
ZADD | ZADD key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD | ZCARD key | 获取有序集合的成员数 |
ZCOUNT | ZCOUNT key min max | 返回有序集合中score值在[min,max]区间的元素数量 |
ZINCRBY | ZINCRBY key increment member | 集合中对指定成员的分数加上增量 increment |
ZSCORE | ZSCORE key member | 返回有序集合中,成员的分数值 |
ZRANK | ZRANK key member | 获得有序集合中member的排名(按分值从小到大),需要注意的是,排名序号是从0开始的 |
ZREVRANK | ZREVRANK key member | 获得有序集合中member的排名(按分值从大到小) |
ZRANGE | ZRANGE key start stop [WITHSCORES] | 获得有序集合中指定排名区间成员,按分数递增排序 |
ZREVRANGE | ZREVRANGE key start stop [WITHSCORES] | 获得有序集合中指定排名区间成员,按分数递减排序 |
ZREM | ZREM key member [member …] | 移除有序集合中的一个或多个成员 |
示例:
127.0.0.1:6379> zadd examination 80.5 xiaozhao 87.0 xiaoli 76.5 xiaowang 92 xiaozhang # 添加四名学生的考试成绩到有序集合
(integer) 4
127.0.0.1:6379> zcard examination # 查看成员数
(integer) 4
127.0.0.1:6379>
127.0.0.1:6379> zcount examination 80 90 # 统计成绩在80~90分的数量
(integer) 2
127.0.0.1:6379> zscore examination xiaoli # 查看小李的成绩
"87"
127.0.0.1:6379> zrank examination xiaoli # 查看小李的分数排名(从小到大)<注:起始为0>
(integer) 2
127.0.0.1:6379> zrevrank examination xiaoli # 查看小李的分数排名(从大到小)
(integer) 1
127.0.0.1:6379> zrange examination 0 2 withscores # 查看成绩倒数三名
1) "xiaowang"
2) "76.5"
3) "xiaozhao"
4) "80.5"
5) "xiaoli"
6) "87"
127.0.0.1:6379>
127.0.0.1:6379> zrevrange examination 0 2 withscores # 查看成绩正数三名
1) "xiaozhang"
2) "92"
3) "xiaoli"
4) "87"
5) "xiaozhao"
6) "80.5"
Redis Hash是一个String类型的Field(字段)和Value(值)的映射表,也称作散列表、哈希表、字典,Hash特别适合用于存储对象。
应用场景:
更适合存储结构化的数据,如对象的存储 ,表数据的映射。
购物车
以用户id作为key,每位用户创建一个hash存储结构存储对应的购物车信息
将商品编号作为field,购买数量作为value进行存储
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
HSET | HSET key field value | 单个字段赋值,将哈希表key中的字段field的值设为value,如果该field之前有值,则做更新操作 |
HMSET | HMSET key field1 value1 [field2 value2…] | 给多个字段赋值 |
HSETNX | HSETNX key field value | 只有在字段field不存在时,设置哈希表字段的值 |
HGET | HGET key field | 获取存储在哈希表中指定字段的值 |
HMGET | HMGET key field1 [field2…] | 获取所有给定字段的值 |
HGETALL | HGETALL key | 获取在哈希表中指定key的所有字段和值 |
HEXISTS | HEXISTS key field | 查看哈希表key中,指定的字段是否存在 |
HDEL | HDEL key field1 [field2…] | 删除一个或多个哈希表字段 |
HKEYS | HKEYS key | 获取所有哈希表中的字段 |
HLEN | HLEN key | 获取所有哈希表长度(field-value映射数量) |
HVALS | HVALS key | 获取所有哈希表中的值 |
示例:
127.0.0.1:6379> hmset user:zhangfei username zhangfei password 123456 age 23 sex male # 批量给user:zhangfei赋值
OK
127.0.0.1:6379> hkeys user:zhangfei # 获取所有的字段名
1) "username"
2) "password"
3) "age"
4) "sex"
127.0.0.1:6379> hvals user:zhangfei # 获取所有的值
1) "zhangfei"
2) "123456"
3) "23"
4) "male"
127.0.0.1:6379> hexists user:zhangfei address # 检查字段是否存在
(integer) 0
127.0.0.1:6379> hexists user:zhangfei age
(integer) 1
127.0.0.1:6379> hdel user:zhangfei password # 删除指定字段
(integer) 1
127.0.0.1:6379> hkeys user:zhangfei
1) "username"
2) "age"
3) "sex"
127.0.0.1:6379> hlen user:zhangfei # 查看field-value映射数量
(integer) 3
127.0.0.1:6379>
127.0.0.1:6379> hgetall user:zhangfei # 获取所有field以及对应的value
1) "username"
2) "zhangfei"
3) "age"
4) "23"
5) "sex"
6) "male"
127.0.0.1:6379>
Redis GEO主要用于存储地理位置信息,并对存储的信息进行操作,该功能在Redis 3.2版本新增。
应用场景:
1、记录地理位置
2、计算外卖配送-骑手距离
3、查找"附近的人"
4、搜索某地附近的美食
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
GEOADD | GEOADD key longitude latitude member [longitude latitude member …] | 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中 |
GEOPOS | GEOPOS key member [member …] | 从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。 |
GEODIST | GEODIST key member1 member2 [m|km|ft|mi] | 返回两个给定位置之间的距离 m :米,默认单位 km :千米 mi :英里 ft :英尺 |
GEORADIUS | GEORADIUS key longitude latitude radius [m|km|ft|mi] | 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素 |
GEORADIUSBYMEMBER | GEORADIUSBYMEMBER key member radius | 以给定的成员为中心,返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素 |
示例:
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" # 给西西里岛添加两座地点:巴勒莫和卡塔尼亚,并分别指定经纬度
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania km # 计算两个地点的距离
"166.2742"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km # 列举以(15,37)为中心,相距200km的地点
1) "Palermo"
2) "Catania"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST # 列举以(15,37)为中心,相距200km的地点,并计算其距离
1) 1) "Palermo"
2) "190.4424"
2) 1) "Catania"
2) "56.4413"
127.0.0.1:6379> GEOPOS Sicily Palermo # 查询指定地点的经纬度
1) 1) "13.36138933897018433"
2) "38.11555639549629859"
127.0.0.1:6379>
127.0.0.1:6379> GEORADIUSBYMEMBER Sicily Palermo 200 km # 列举以指定地点为中心,相距200km的地点(结果包含本身)
1) "Palermo"
2) "Catania"
127.0.0.1:6379>
127.0.0.1:6379> GEORADIUSBYMEMBER Sicily Palermo 1 km
1) "Palermo"
127.0.0.1:6379>
127.0.0.1:6379>
Redis Stream 是 Redis 5.0 版本新增加的数据结构。
Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。而 Redis Stream提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
每个Stream都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加消息时自动创建。
应用场景:
订单处理
消息队列
聊天室
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
XADD | XADD key ID field value [field value …] | 向队列添加消息,消息由一组或多组field-value组成,如果指定的队列不存在,则先创建一个队列 ID:消息 id,我们使用 * 表示由 redis 生成,可以自定义,但是要自己保证递增性 |
XREAD | XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …] | 从一个或多个Stream中读取消息,可指定读取的数量,是否以阻塞的方式去取,以及从每个Stream读取消息的起始id (不包含指定id) |
XLEN | XLEN key | 获取队列包含的元素数量,即队列长度 |
XDEL | XDEL key ID [ID …] | 根据id删除队列中的一条或者多条消息 |
XRANGE | XRANGE key start end [COUNT count] | 消息id从小到大,读取队列中给定ID范围的消息 key :队列名 start :开始值, - 表示最小值 end :结束值, + 表示最大值 count :数量 |
XREVRANGE | XREVRANGE key end start [COUNT count] | 消息id从大到小,读取队列中给定ID范围的消息 |
XGROUP CREATE | XGROUP CREATE key groupname id-or-$ | 创建消费组 key:指定消费的队列名称,如果不存在就创建 groupname:组名 id-or- :指定从哪消费,可指定从具体的 i d 开始消费,如果设置为 : 0 − 0 ,表示从头开始消费,也可设置为 : 指定从哪消费,可指定从具体的id开始消费,如果设置为: 0-0,表示从头开始消费,也可设置为 :指定从哪消费,可指定从具体的id开始消费,如果设置为:0−0,表示从头开始消费,也可设置为,表示从尾部开始消费,只接受新消息,当前 Stream旧的消息会全部忽略 |
XGROUP SETID | XGROUP SETID key groupname id-or-$ | 修改一个消费组从那开始消费 |
XGROUP DESTROY | XGROUP DESTROY key groupname | 删除指定消费组 |
XREADGROUP GROUP | XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key …] id [id …] | 和XREAD相似,指定消费者组进行读取消息 group:消费组名,需要提前创建 consumer:消费者名,一个消费组可以由多名消费者组成,同时消费一个Stream,会自动创建(也可以使用命令创建),如果消息队列中的消息被消费组的一个消费者消费了,这条消息就不会再被这个消费组的其他消费者读取到 id:这里的id含义比较特殊,在后面解释 |
XGROUP | XGROUP CREATECONSUMER key groupname consumername | 创建一个消费组的消费者 |
XACK | XACK key group id [id …] | 将消息标记为”已处理“ ACK:acknowledge的缩写,消息队列的一种确认机制,客户端收到消息或处理完业务之后,告知服务端消息已正常消费 |
示例:
127.0.0.1:6379> xadd order * name iphone type "iphone 13 pro max" storage 256GB color blue # 创建队列order,并添加一条消息流
"1661169438466-0"
127.0.0.1:6379> xadd order * name iphone type "iphone 13 pro" storage 128GB color white # 向Stream中添加消息流
"1661169496826-0"
127.0.0.1:6379> xlen order # 查看消息数量
(integer) 2
127.0.0.1:6379> xdel order 1661169496826-0 # 根据id删除消息
(integer) 1
127.0.0.1:6379> xlen order
(integer) 1
127.0.0.1:6379> xrange order - + # 获取指定范围内的所有消息
1) 1) "1661169438466-0"
2) 1) "name"
2) "iphone"
3) "type"
4) "iphone 13 pro max"
5) "storage"
6) "256GB"
7) "color"
8) "blue"
127.0.0.1:6379> xread streams order 0-0 # 从起始位置读取所有消息
1) 1) "order"
2) 1) 1) "1661169438466-0"
2) 1) "name"
2) "iphone"
3) "type"
4) "iphone 13 pro max"
5) "storage"
6) "256GB"
7) "color"
8) "blue"
127.0.0.1:6379>
127.0.0.1:6379> xadd order * name Xiaomi type "Xiaomi 12 ultra" storage 512GB color black
"1661224305535-0"
127.0.0.1:6379> xread streams order 1661169438466-0 # 从大于id:1661169438466-0的地方开始读取所有消息
1) 1) "order"
2) 1) 1) "1661224305535-0"
2) 1) "name"
2) "Xiaomi"
3) "type"
4) "Xiaomi 12 ultra"
5) "storage"
6) "512GB"
7) "color"
8) "black"
127.0.0.1:6379>
127.0.0.1:6379> xgroup create order warehouse 0-0 # 创建order的消费者组warehouse,指定从队列最开始位置消费
OK
127.0.0.1:6379> xinfo stream order # 查看order队列的信息
1) "length"
2) (integer) 2
3) "radix-tree-keys"
4) (integer) 1
5) "radix-tree-nodes"
6) (integer) 2
7) "last-generated-id"
8) "1661224305535-0"
9) "groups"
10) (integer) 1
11) "first-entry"
12) 1) "1661169438466-0"
2) 1) "name"
2) "iphone"
3) "type"
4) "iphone 13 pro max"
5) "storage"
6) "256GB"
7) "color"
8) "blue"
13) "last-entry"
14) 1) "1661224305535-0"
2) 1) "name"
2) "Xiaomi"
3) "type"
4) "Xiaomi 12 ultra"
5) "storage"
6) "512GB"
7) "color"
8) "black"
127.0.0.1:6379> xinfo groups order # 查看order队列的所有消费组信息
1) 1) "name"
2) "warehouse"
3) "consumers"
4) (integer) 0
5) "pending"
6) (integer) 0
7) "last-delivered-id"
8) "0-0"
127.0.0.1:6379>
127.0.0.1:6379> xgroup create order store 0-0
OK
127.0.0.1:6379> xgroup createconsumer order store consumer-1 # 手动创建消费者
(integer) 1
127.0.0.1:6379> xreadgroup group store consumer-1 count 2 streams order > # 消费新消息
1) 1) "order"
2) 1) 1) "1661169438466-0"
2) 1) "name"
2) "iphone"
3) "type"
4) "iphone 13 pro max"
5) "storage"
6) "256GB"
7) "color"
8) "blue"
2) 1) "1661224305535-0"
2) 1) "name"
2) "Xiaomi"
3) "type"
4) "Xiaomi 12 ultra"
5) "storage"
6) "512GB"
7) "color"
8) "black"
127.0.0.1:6379>
127.0.0.1:6379> xreadgroup group store consumer-1 count 2 streams order 0-0 # 读取pending状态的消息
1) 1) "order"
2) 1) 1) "1661169438466-0"
2) 1) "name"
2) "iphone"
3) "type"
4) "iphone 13 pro max"
5) "storage"
6) "256GB"
7) "color"
8) "blue"
2) 1) "1661224305535-0"
2) 1) "name"
2) "Xiaomi"
3) "type"
4) "Xiaomi 12 ultra"
5) "storage"
6) "512GB"
7) "color"
8) "black"
127.0.0.1:6379>
注意:
使用XREADGROUP时,要在STREAMS选项后面指定id,可以是以下两种类型之一:
特殊标识:>,这意味着消费者只希望接收从未传递给任何其他消费者的消息,这意味着消费新的消息。
任何其他id,即0或任何其他有效id或不完整id,达到的效果是:在处于pending状态的消息列表中,返回大于指定id的消息。因此,基本上,如果id不是 ‘>’ ,那么该命令将只允许客户端访问其pending的条目:即传递给它但尚未确认的消息。注意,在这种情况下,BLOCK和NOACK都被忽略。
这里比较不易理解,消费最新的消息,使用第一种方式即可,第二种方式,更像是为了处理消息被消费者消费了,但是程序异常或不可抗力的因素导致消息未ack的情况,是一种补偿措施。或者简单地用来查看处于pending状态的消息。
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8},基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
应用场景:
估算一个游戏的日活量
估算一个游戏公司旗下多款游戏的日活总量
估算一个网站被多少用户访问过
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
PFADD | PFADD key element [element…] | 添加指定元素到 HyperLogLog中 |
PFCOUNT | PFCOUNT key [key …] | 返回给定 HyperLogLog 的基数估算值 |
PFMERGE | PFMERGE destkey sourcekey [sourcekey …] | 将多个 HyperLogLog 合并为一个 HyperLogLog |
示例:
127.0.0.1:6379> pfadd numbers 1 3 2 5 3 4 6 9 10 # 添加元素
(integer) 1
127.0.0.1:6379> pfcount numbers # 查看基数预估值
(integer) 8
127.0.0.1:6379>
在平时开发过程中,经常会有一些 bool 类型数据需要存取。比如记录用户一年内签到的次数,签了是 1,没签是 0。如果使用 key-value 来存储,那么每个用户都要记录 365 次,当用户成百上亿时,需要的存储空间将非常巨大。为了解决这个问题,Redis 提供了位图结构。
位图(Bitmap)同样属于 string 数据类型。Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,这大大增加了 value 存储数量。
应用场景:
用户签到
统计一个月内每天都登陆过游戏的用户
统计超过一个月未登录游戏的用户
统计用户活跃数量
常用命令:
命令 | 用法示例 | 描述 |
---|---|---|
SETBIT | SETBIT key offset value | 用来设置或者清除某一位上的值,其返回值是原来位上存储的值 key:在初始状态下所有的位都为 0 offset:可根据业务实际需求设计 value:只能是 0 或者 1 |
GETBIT | GETBIT key offset | 获得key在offffset处的bit值 |
BITCOUNT | BITCOUNT key [start end [BYTE | BIT]] | 获得key的bit位为1的个数 |
BITOP | BITOP operation destkey key [key …] | 对多个key 进行逻辑运算后存入destkey中 语法:operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种: BITOP AND destkey key [key …]:对一个或多个key求逻辑与&,并将结果保存到 destkey BITOP OR destkey key [key …]:对一个或多个key求逻辑或|,并将结果保存到 destkey BITOP XOR destkey key [key …]:对一个或多个key求逻辑异或^,并将结果保存到destkey BITOP NOT destkey key:对给定key求逻辑非~,并将结果保存到destkey 除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入 命令的返回值表示存储在目标键中的字符串的大小 |
示例:
127.0.0.1:6379> setbit user:sign:1000 20220101 1 # 模拟用户签到
(integer) 0
127.0.0.1:6379> setbit user:sign:1000 20220102 1
(integer) 0
127.0.0.1:6379> setbit user:sign:1000 20220104 1
(integer) 0
127.0.0.1:6379> getbit user:sign:1000 20220102 # 判断用户是否签到
(integer) 1
127.0.0.1:6379> bitcount user:sign:1000 # 统计用户签到次数
(integer) 3
127.0.0.1:6379> setbit login_09_19 100 1 # 设置9.19有四位用户登录,9.20有三位用户登录
(integer) 0
127.0.0.1:6379> setbit login_09_19 101 1
(integer) 0
127.0.0.1:6379> setbit login_09_19 102 1
(integer) 0
127.0.0.1:6379> setbit login_09_19 103 1
(integer) 0
127.0.0.1:6379> setbit login_09_20 100 1
(integer) 0
127.0.0.1:6379> setbit login_09_20 101 1
(integer) 0
127.0.0.1:6379> setbit login_09_20 103 1
(integer) 0
127.0.0.1:6379> bitop and login_in_09_19_and_20 login_09_19 login_09_20 # 计算9.19和9.20两天都登陆过的用户
(integer) 13
127.0.0.1:6379> bitcount login_in_09_19_and_20 # 查看9.19和9.20两天都登陆过的用户
(integer) 3
127.0.0.1:6379> bitop or login_in_09_19_or_20 login_09_19 login_09_20 # 计算两天登录过的用户总数
(integer) 13
127.0.0.1:6379> bitcount login_in_09_19_or_20
(integer) 4
127.0.0.1:6379>