【Redis】数据结构及应用
一. 说明
二. 数据结构
1. String
- 二进制安全(能保存任意格式的数据)
2. List
- 链表结构
- 快速的列头、列尾操作,时间复杂度O(1)
- 列表查询时间复杂度O(N),考虑用Sorted List替代
应用:朋友圈点赞列表
lpush id
lrange 0 -1
ltrim
3. Hash
- 文档
- 特点
- 键值对,时间复杂度O(1)
应用:用户标签
- Hash存储用户标签ID和名称键值对
# 设置
hmset usertag tagID1 tagName1 tagID2 tagName2 tagID3 tagName3 tagID4 tagName4 tagID5 tagName5
# 获取
hget usertag tagID3
# 获取所有
hgetall usertag
# 获取多个
hmget usertag tagID1 tagID2
4. Set
1. 说明
- 文档
- 特点
- 无序
- 去重
- 随机读取
- 集合操作(交集、并集、差集)
2. 应用(扑克牌)
- 命令
# 初始化
sadd poker T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 TJ TQ TK X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 XJ XQ XK M1 M2 M3 M4 M5 M6 M7 M8 M9 M10 MJ MQ MK F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 FJ FQ FK XW DW
# 数量
scard poker
# 复用扑克牌
sunionstore pokernew poker
# 成员
smembers poker
# 是否包含
sismember poker T1
# 随机读取
spop poker
3. 集合操作
# 设置
sadd user1tag tagID1 tagID2 tagID3
sadd user2tag tagID2 tagID3
sadd user3tag tagID2 tagID4 tagID5
# 获取
smembers user3tag
# 获取共同拥有的tag(交集)
sinter user1tag user2tag user3tag
# 获取拥有的所有tag(并集)
sunion user1tag user2tag user3tag
# 获取两个之间的区别(差集)
sdiff user2tag user3tag
5. Sorted Set
1. 说明
-
特点
- 有序(根据浮点类型分数)
- 自动去重(zadd命令多次执行会自动更新值及排序)
- 范围查询
- 数据结构:跳表(范围查询) + Hash(根据value查分数zscore)
- 时间复杂度(不同命令,时间复杂度不同,以zadd为例)
-
不足
- 只能存单值,比如ID,不能保存整个用户信息,可根据ID到数据中获取,关联数据也放在缓存中
- 原子操作:获取分数-->修改分数
- 利用lua脚本
- zincrby命令
- 分数存储到另外的地方(比如单独的缓存),每次重新设置
2. 应用(排行版)
- 命令
# rank:key 100: 分数 u1: ID
# 初始化 时间复杂度: O(log(N))
zadd rank 100 u1
zadd rank 200 u2
zadd rank 300 u3
zadd rank 400 u4
zadd rank 500 u5
# 数量
zcard rank
# 内容(正序、倒序)时间复杂度: O(log(N)+M)
zrange rank 0 -1
zrange rank 0 -1 withscores
zrevrange rank 0 -1 withscores
zrevrange rank 0 -2 withscores
zrevrange rank 0 -1
# 获取用户分数(不存在返回空) 时间复杂度: O(1)
zscore rank u1
# 修改分数
zadd rank 800 u3
# 修改分数(累加:新增或减少,返回修改后的分数)
zincrby rank 100 u3
zincrby rank -100 u3
# 查询分数范围内容(正序、倒序)
zrangebyscore rank (200 800 withscores
zrevrangebyscore rank (200 800 withscores
# 移除元素
zrem rank u3
- RedisTemplate
redisTemplate.opsForZSet().add
redisTemplate.opsForZSet().remove
redisTemplate.opsForZSet().score
redisTemplate.opsForZSet().incrementScore
# 排序后的ID集合(分数从高到低排序)
Set<Integer> zsets = redisTemplate.opsForZSet().reverseRange(key, 0, 10)
# 排序后的ID集合(分数从低到高排序)
Set<Integer> zsets = redisTemplate.opsForZSet().range(key, 0, 10)
redisTemplate.opsForZSet().size
# 返回ID的索引位置
redisTemplate.opsForZSet().rank(key,id)
6. Bitmap
1. 说明
- 文档
- 原理(按位设置值)
Bitmaps are not an actual data type, but a set of bit-oriented operations defined on the String type. Since strings are binary safe blobs and their maximum length is 512 MB, they are suitable to set up to 2 32 different bits
2. 应用(打卡/签到)
- 命令
# usersign:key 0 位数(按月/年) 0/1(签到标识)
# 设置位数状态(按月、按年)
setbit usersign 0 1
setbit usersign 1 1
setbit usersign 2 0
setbit usersign 5 1
setbit usersign 6 1
# 返回设置为1的数量
bitcount usersign
# 返回第一个设置为1的位置
bitpos usersign 1
# 返回指定位置的值(值为0或未设置返回0)
getbit usersign 1
7. Stream
- 消息队列实现方案
- 对比
参数 | List | Stream |
---|---|---|
消息写入 | lpush | xadd |
消息读取 | rpop brpop | xread xdel xreadgroup |
有序 | 业务方处理 | 自动生成全局唯一递增ID(时间戳+时间戳内自增) |
幂等 | 业务方处理 | 业务方处理 |
消息可靠 | 无 | xpending xack |
消费者组 | 无 | xgroup |
- List
# 写入消息队列
lpush mqlist m1
lpush mqlist m2
lpush mqlist m3
# 队列长度
llen mqlist
# 队列内容
lrange mqlist 0 -1
# 队列取数据
rpop mqlist
# 队列取数据(阻塞)
brpop mqlist
brpop mqlist 3(timeout sec)
# 消息备份(消费者程序从一个 List 中读取消息,再把这个消息插入到另一个 List)
brpoplpush mqlist
- Stream
# 队列长度
xlen mqstream
# 队列内容
xrange mqstream - +
# 队列取数据(不会删除元素)
xread count 1 streams mqstream 0
# 队列取数据(阻塞)
xread count 1 block 3000(timeout millisec) streams mqstream 0
# 删除元素
xdel mqstream ID
# 消费者组(多个消费者消费同一个队列消息)
# 最后一个参数 0:表示从队头开始消费 $:表示从队尾(即新元素)开始消费 ID:从指定ID位置开始消费
xgroup create mqstream group1 0
xreadgroup group group1 consumer1 streams mqstream >
xreadgroup group group1 consumer2 streams mqstream >
# 确认消息(正常读不用调用此命令)
# 为了保证消费者在发生故障或宕机再次重启后,仍然可以读取未处理完的消息,Streams 会自动使用内部队列
#(也称为 PENDING List)留存消费组里每个消费者读取的消息,直到消费者使用 XACK 命令通知 Streams "消息已经处理完成"
xpending mqstream group1
xack mqstream group1 ID