文章目录
前言
redis八股文总结,后面有待补充
提示:以下是本篇文章正文内容,下面案例可供参考
1、什么是redis
redis是一种基于内存
的数据库,对数据的读写操作都是在内存中完成的,因此读写速度非常快
,常用于缓存、消息队列、分布式锁等场景
。
redis提供了多种数据类型来支持不同的业务场景,比如string(字符串)、hash(哈希)、List(列表)、set(集合)、Zset(有序集合)、Bitmaps(位图)、HyperLogLog(基数统计)、GEO(地理信息)、Stream(流),并且对数据类型的操作都是原子性
的,因为redis执行命令是单线程,不存在并发竞争的问题
为什么用redis作为mysql的缓存
主要是因为redis具备高性能和高并发两种特性
- redis具备高性能
用户第一次访问mysql中的某些数据,因为是从硬盘上读取的,所以过程会比较慢。将该用户访问的数据缓存在redis中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了,操作redis就是直接操作内存
,不用访问硬盘,所以速度相当快。
由于mysql数据改变后,需要同步改变redis缓存中的数据,不过这里会有redis和mysql双写一致性的问题。 - redis具备高并发
单台设备的redis的QPS(每秒钟处理完请求的次数)是mysql的十倍,所以redis能够承受的请求是远远大于mysql的,因此可以考虑把数据库中的部分数据转移到缓存中去。
2、redis数据结构
2.1 五种类型是什么及使用场景
redis提供了丰富的数据类型,常见的有五种:String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(有序集合)
redis五种数据类型的应用场景:
- String类型的应用场景:缓存对象、常规计数、分布式锁、共享session信息等。
- List类型的应用场景:消息队列(2 problems:
生产者需要自行实现全局唯一ID
不能以消费组形式消费数据
- Hash类型:缓存对象、购物车
- set类型:集合计算(并集、交集、差集)场景,比如点赞、共同关注、抽奖活动等。
- Zset类型:排序场景,比如排行榜、电话和姓名排序等 。
redis后续又支持四种数据类型:
- BitMap:二值状态统计的场景,比如签到、判断用户登录状态、连续签到用户总数等。
- HyperLogLog:海量数据基数统计的场景,比如百万级网页UV计数等。
- GEO:存储地理位置信息的场景,比如滴滴叫车
- Stream:消息队列,相比于基于List类型实现的消息队列,可以自动生成全局唯一消息ID,支持以消费组形式消费数据。
2.2 五种常见数据类型怎么实现
String类型内部实现
string类型底层数据结构使用简单动态字符串(SDS),SDS相比于C的原生字符串:
- SDS不仅可以保存文本数据,还可以保存二进制数据(即能保存图片、音频、视频、压缩文件)
- SDS获取字符串长度的时间复杂度是O(1),用len属性记录了字符串长度,复杂度为O(1)
- Redis的SDS API 是安全的,拼接字符串不会造成缓冲区溢出。
String类型的使用场景:
- 常规计数,redis执行命令是单线程的,所以执行命令的过程是原子的。因此String类型适合用于计算访问次数、点赞、转发、库存数量等。
- 分布式锁,setNx,如果key不存在才插入,即
- 如果key不存在,则显示插入成功,可以用来表示加锁成功
- 如果key存在,会显示插入失败,即可用来表示加锁失败
一般而言,还会对分布式锁设置过期时间,防止某一线程崩溃,锁一直无法释放
- 共享session信息
在分布式系统中,借助redis对session信息进行统一的存储和管理,这样无论请求发送到哪台服务器,服务器都会去同一个redis获取相关的session信息,这就解决了分布式系统下session存储的问题。
List类型内部实现
双向链表或压缩列表
实现,简单的字符串列表,按照插入顺序排序
元素较少,使用压缩列表(连锁更新情况保存前一个entry的长度,比较耗性能);元素较多使用双向链表;后期改为quickList,其实就是双向链表+压缩链表。
quickList
应用场景:消息队列
消息队列有三大需求:消息保序(list先进先出保证
)、处理重复的消息(每个消息都会有个全局的id,消费者记录已处理过的消息id,来判断当前收到的消息有没有经过处理,如果处理过,消费者程序就不再进行处理
)和保证消息可靠性(BRPOPLPUSH
命令,让消费者程序从一个list读取消息,同时,redis将这个消息插入到另一个list(备份list)中留存
)
List作为消息队列,有缺陷:
list不支持多个消费者消费同一条消息,即不支持消费组的实现
Hash内部实现
压缩列表或者哈希表
实现,redis7后压缩表列表舍弃,交由listpack数据结构实现(不存储上一个节点的长度,不出现连锁更新问题)。元素个数较少,使用压缩列表(listpack),较多使用哈希表
应用场景
- 缓存对象
- 购物车
set内部实现
用哈希表或整数集合
来实现
元素个数较少,使用整数集合;较多使用哈希表。
set集合的几个特性:无序、不可重复、支持并交差
应用场景:
- 点赞 (一篇文章有多少用户点赞,去重)
- 共同关注
- 抽奖活动(去重,保证一个用户不会中奖两次)
zset内部实现
小:压缩列表(listpack),多:跳表
有序集合
使用场景
- 排行榜
- 电话、姓名排序
Bitmap
位图,可以通过偏移量(offset)定位元素,即可以将最小的单位bit来进行0/1的设置,表示某个元素的值或者状态,特别适合一些数据量大且使用二值统计的场景
,用String类型作为底层数据结构
应用场景
- 签到统计
- 判断用户登录状态
- 连续签到用户总数
hyperLogLog
统计基数的数据集合类型,提供不精确的去重计数
,用很小的内存空间,计算出很多元素的基数
使用场景
百万级网页UV计数
GEO
存储地理位置信息,并对存储的信息进行操作,使用数据类型为zset,sorted set
应用场景
滴滴叫车
Stream
消息队列,在list基础上增加了消费组的实现。
2.3 redis线程模型
2.3.1 redis是单线程嘛
redis单线程是指[接受客户端请求 -> 解析请求 -> 进行数据读写操作 -> 发送数据给客户端]这个过程是由一个线程来完成的
redis程序并不是单线程的
,redis在启动的时候,会启动后台线程
的。
redis会为很耗时的任务创建单独的线程来处理,如关闭文件、AOF刷盘、释放内存
注意redis的单线程只局限于网络IO和执行命令