【Redis】常见数据类型
常见数据类型
- 最基本的5种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)。
- 新版本:BitMap(2.2)、HyperLogLog(2.8)、GEO(3.2)、Stream(5.0)。
String
组成:string、int、float,最长512MB
数据结构
-
int:编码整数
-
SDS简单动态字符串:编码raw、embstr
-
界限:
-
redis 2.+:32 字节
-
redis 3.0-4.0:39 字节
-
redis 5.0:44 字节
-
-
Why?🤔
-
embstr一次内存分配一块连续的内存空间来保存redisObject和SDS,raw两次内存分配
应用场景
-
缓存对象
- 缓存json:
SET user:1 '{"name":"xiaolin", "age":18}'
- 分离字段缓存(user:ID:字段):
MSET user:1:name xiaolin user:1:age 18 user:2:name xiaomei user:2:age 20
- 缓存json:
-
常规计数:利用其原子性加减对计算访问次数、点赞、转发、库存数量等进行计数
-
分布式锁:
-
NX参数:不存在才插入
- key 不存在,则显示插入成功,表示加锁成功
- key 存在,则会显示插入失败,表示加锁失败
-
加锁:
SET lock_key unique_value NX PX 10000
- lock_key:key 键;
- unique_value:客户端生成的唯一的标识;
- NX:只在 lock_key 不存在时,才对 lock_key 进行设置操作;
- PX 10000:设置 lock_key 的过期时间为 10s,避免客户端发生异常无法释放锁。
-
解锁:将 lock_key 键删除,保证执行操作的客户端就是加锁的客户端。
- Lua 脚本来保证解锁的原子性
-
-- 释放锁时,先比较 unique_value 是否相等,避免锁的误释放 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
-
-
共享 Session 信息
- 所有应用服务器把session存储在redis,实现跨服务器读取
List
组成:双向链表
数据结构
-
Redis 3.2 版本前:
- 压缩列表:列表的元素个数小于 512 个 & 列表每个元素的值都小于
64
字节 - 双向链表
- 压缩列表:列表的元素个数小于 512 个 & 列表每个元素的值都小于
-
Redis 3.2 版本后:
- quicklist
应用场景
-
消息队列
-
需求:
- 消息保序:生产者LPUSH,消费者RPOP(可阻塞BRPOP)
- 处理重复的消息:生产者为每个消息加一个全局 ID,消费者可避免重复消费
- 可靠性:BRPOPLPUSH,读取后还有备份,避免处理失败数据丢失
-
缺点:不支持多个消费者消费同一条消息
-
Hash
组成:key - value 集合
value=[{field1,value1},...{fieldN,valueN}]
数据结构
-
Redis 7.0 前:
- 压缩列表:哈希类型元素个数小于 512 个 & 所有值小于 64 字节
- 哈希表:其他情况
-
Redis 7.0 后:
- listpack替换压缩列表
应用场景
-
缓存对象:
HMSET uid:1 name Tom age 15
- 一般使用String + Json,当字段变化频繁使用Hash
Set
组成:无序并唯一的集合
数据结构
- 整数集合:元素都是整数且元素个数小于 512
- 哈希表:不满足上面条件
应用场景
-
数据去重,保障数据的唯一性
- 点赞
- 共同关注
- 抽奖活动
-
统计多个集合的交集、错集和并集等
- 缺点:计数复杂度高
Zset
组成:有序集合,元素值+排序值
数据结构
-
Redis 7.0 前:
- 压缩列表:元素个数小于 128 个 & 每个元素的值小于 64 字节
- 跳表:其他情况
-
Redis 7.0 后:
- listpack替换压缩列表
应用场景
-
对需要展示最新列表、排行榜等场景
- 排行榜
- 电话、姓名排序
-
数据更新频繁或者需要分页显示
BitMap
组成:一串连续的二进制数组
数据结构
- String,bit数组
应用场景
-
二值状态统计
- 签到统计
- 判断用户登陆态
HyperLogLog
用于「统计基数」的数据集合类型,基数统计就是指统计一个集合中不重复的元素个数,标准误算率是 0.81%。
- 只需要花费 12 KB 内存,就可以计算接近 2^64 个元素的基数
应用场景
-
百万级网页 UV 计数
-
计数:PFADD page1:uv user1 user2 user3 user4 user5
-
统计:PFCOUNT page1:uv
-
GEO
存储地理位置信息
数据结构
直接使用了 Sorted Set 集合类型
-
GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换、
- 对二维地图做区间划分
- 对区间进行编码
应用场景
-
滴滴叫车:
-
记录车位置:
GEOADD cars:locations 116.034579 39.030452 33
-
用户读取附近的车:
GEORADIUS cars:locations 116.054579 39.030452 5 km ASC COUNT 10
-
Stream
Why?
- 发布订阅模式,不能持久化
- 不能读取历史消息
- 不能重复消费
What?
专门为消息队列设计的数据类型,支持消息的持久化、支持自动生成全局唯一 ID、支持 ack 确认消息的模式、支持消费组模式等
应用场景
-
消息队列
- 消息保序:XADD/XREAD
- 阻塞读取:XREAD block
- 重复消息处理:Stream 在使用 XADD 命令,会自动生成全局唯一 ID;
- 消息可靠性:内部使用 PENDING List 自动保存消息,使用 XPENDING 命令查看消费组已经读取但是未被确认的消息,消费者使用 XACK 确认消息;
- 支持消费组形式消费数据
-
与专业的消息队列的差距:
-
会丢消息:
- AOF 持久化配置为每秒写盘,但这个写盘过程是异步的,Redis 宕机时会存在数据丢失的可能
- 主从复制也是异步的,主从切换时,也存在丢失数据的可能
-
消息可堆积性差
- 消息积压时,如果指定了最大长度,队列长度超过上限后,旧消息会被删除。
-
Redis 发布/订阅机制为什么不可以作为消息队列?
- 没有基于任何数据类型实现,所以不具备「数据持久化」的能力,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,发布/订阅机制的数据也会全部丢失。
- 发布订阅模式是“发后既忘”的工作模式,如果有订阅者离线重连之后不能消费之前的历史消息。
- 当消费端有一定的消息积压时,也就是生产者发送的消息,消费者消费不过来时,如果超过 32M 或者是 60s 内持续保持在 8M 以上,消费端会被强行断开,这个参数是在配置文件中设置的,默认值是
client-output-buffer-limit pubsub 32mb 8mb 60
。
转载自:https://juejin.cn/post/7232272098755395644