1. 数据类型
String、Hash、List、Set、Zset、BitMaps、Hyperloglogs、Geo、Streams ….
Redis底层基于C语言实现。
1.1 String
1.1.1 存储类型
底层存储: int、float、String …
1.1.2 底层编码
编码方式:int(存储8字节长整型)、embstr(SDS格式:存储小于44字节的字符串)、raw(储存大于44字节的字符串)
1.1.3 应用场景
- 缓存热点数据
- 分布式数据共享(服务集群不会出现数据不一致情况)
-
分布式锁:setnx方法
- redis分布式锁自动延长过期时间
- 聊聊redis分布式锁的8大坑
-
非原子操作
setnx 与 expire 两个操作分开了
- 忘了释放锁
- 释放了别人的锁
-
大量请求失败(都同时竞争1把锁,成均匀秒杀)
=》分段、while(ture)自旋
- 锁重入问题 =》使用可重入锁(redission框架=》Lua脚本实现)
- 锁竞争问题(读、写)
- 锁超时问题(watchdog:看门狗,定时续期,需要有总时间,不能无线续约)
- 主从复制问题 (RedissonRedLock =》 大部分加锁成功,则加锁成功。(用的少,CP:zookeeper,AP:redis)
-
非原子操作
-
全局ID
- INT类型,INCRBY, 利用原子性
- 分库分表场景(一次获取一段,每段新增/获取不同的ID)
- 计数器
- INT类型,INCRBY, 利用原子性
- 文章阅读量、点赞数(允许一定的延迟、先写入redis,再定时同步到mysql)
- 限流
- 以访问者IP或其他信息作为KEY,访问一次增加1,超过次数,则返回false
- INT类型,INCRBY, 利用原子性
如果一个对象有多个值,需要存储,应该怎么办?
1.2 Hash
1.2.1 存储类型
跟String一样,String可以做的事,Hash基本都可以做。用来存储多个无序键值对,最大存储(2的32次方-1) 约40亿。
底层存储:zipList(双向链表:KV键值对小于512个 & KV长度小于64byte)
hashtable: (dictionary) hash冲突、rehash、扩容 (数组+ 链表)
结构:Map<Strig,Map<String,Object»
1.2.2 应用场景
购物车信息
key:用户id, field:商品id, value:商品数量
+1:hincr
-1:hdecr
删除:hincrby key field -1
全选:hgetall
商品数:hlen
1.2.3 不适合场景
- Field不能单独设置过期时间
- 考虑数量分布问题(如果数据量多,无法分布到多节点)
1.3 List
1.3.1 存储类型
存储有序字符串,数据可重复,最大存储数据量约40亿。quicklist (有序双向链表) 数据+链表(与hash存储结构不一样的是内部编码)
lpush/rpush
lpop/rpop
1.3.2 应用场景
1. 排序列表: 用户消息列表、公告列表、活动列表、博客的文章列表等等。
思路:存储所有字段,LRANGE 取出一页内容,按顺序显示。
2. 消息队列: 分布式消息队列(PUB/SUB)
1.4 Set
1.4.1 存储类型
存储String类型的无序集合,最大存储数量约40亿(2的32次方-1);用hashtable(数组+链表) 或intset 存储
1.4.2 常用命令
# 添加元素(1个或多个)
sadd key a b c d
# 获取所有元素
smembers key
# 统计元素
scard key
# 随机获取元素
srandmember key
# 随机弹出元素 (可用作抽奖)
spop key
# 移除元素
spop key a b
# 查看元素是否存在
sismember key a
1.4.3 应用场景
-
抽奖: spop key => 随机弹出
-
点赞、签到、打卡: sadd key(like:消息id) userId1 userId2 userId3 ....
-
商品筛选:
集合操作:交集
# 商品属性 sadd brand:lenovo 联想小新Pro14 sadd type:small 联想小新Pro14 sadd cpu:intel 联想小新Pro14 ... #商品筛选 sinter brand:lenovo type:small cpu:intel ==> 联想小新Pro14
-
用户关注、推荐模型 (结构、交集)
1.5 ZSet
1.5.1 存储类型
sorted set 存储有序元素。每个元素都有个score,按照scocre 从小到大排列,socre相同,按照key 的ASCII码排序。
默认使用ziplist编码。
跳表:
1.5.2 常用命令
# 添加元素(注意顺序:分值在前)
zadd myzsetkey 10 a 20 b 30 c 40 d
# 获取全部元素
zrange myzsetkey 0 -1 withscores
zrevrange myzsetkey 0 -1 withscores
# 根据分值区间获取值
zrangebyscore myzsetkey 20 40
# 获取元素分值
zscore myzsetkey c
# 根据value 或 分值移除元素
zrem myzsetkey a b
zrem myzsetkey 10
# 统计元素个数
zcard myzsetkey
# 根据分值区间或个数
zcount myzsetkey 10 30
# 分值递增(分值增加2)
zincrby myzsetkey 2 a
# 获取元素排名
zrank myzsetkey b
# 获取倒序
zrev myzsetkey
1.5.3 应用场景
会动态变化的顺序列表
-
商品标签:
-
排行榜:(热榜、热搜)
# 为新闻id为ID1000点击数增加1: zincrby hotnews:22222222 1 ID1000 # 获取今天点击最多的10条数据:zrevrange hotnews:22222222 0 15 withscores
1.6 BitMaps
字符串类型上定义的位操作,1个字节有8个二进制表示。bit非常节省空间,可以用来做大数据量统计。在线用户统计
思路:如果用户id,对应一个ASCII码,即数字(且不重复)我们将设置具体的值,0101001..... 可以表示:从0-> 指定位数的最大值。如果某一个用户线下了,我们将对应bit位上的值设置0即可
=》类比:海量不重复数据中,查找数据是否存在。
1.7 HyperLogLog
不太精确的基数统计法,用来统计一个集合中不重复的元数个数,网页的UV;Redis中实现的HyperLogLog,只需要12K就能存储2的64次方个数据。
1.8 Geo
经纬度相关类型:计算距离等