前言
Redis复习思路
一 Redis基础
1.1 Redis是什么?
Redis是基于键值对的NoSQL数据库,其数据都存放在内存当中,读写性能出色,是互联网技术领域中使用最广泛的缓存中间件。
相比MySQL:
Redis:基于键值对型数据库NoSQL,存储在内存中,读写性能好。
Mysql:关系型数据库,存储在硬盘中,支持事务。
1.2 Redis可以用来干什么
缓存、计数器、排行榜(ZSet)、消息队列、分布式锁
1.3 Redis有哪些数据类型
五种基本数据类型:String、hash、Set、ZSet、List
1.4 Redis为什么这么快呢
Redis是基于内存存储有较好的读写性能
Redis有高效的数据结构
单线程模型:Redis 使用单线程模型来处理客户端的请求,避免了锁的竞争带来的消耗
1.5 单线程的Redis的QPS最多是多少
Redis可以达到每秒数万到数几十万的QPS(每秒查询率)
1.6 Redis常用命令
操作字符串的命令有:
SET key value :设置key的值为value
GET key :获取key的值
DEL key :删除key
列表操作命令:
LPUSH key value:插到列表头部
RPUSH key value:插到列表尾部
LPOP:移除并返回左边
RPOP:移除并返回右边
操作集合的命令:
SADD key member:向集合key添加一个元素
SREM key member:向集合key中移除一个元素
操作有序集合:
ZADD key member
ZREM key member
操作哈希的命令有:
HSET key field value:向键为 key 的哈希表中设置字段 field 的值为 value。
HGET key field:获取键为 key 的哈希表中字段 field 的值。
HDEL key field:删除键为 key 的哈希表中的一个或多个字段。
二 持久化
2.1 Redis持久化的方式有哪些?
RDB持久化和AOF持久化
RDB持久化是通过拍快照的方式来工作,在指定时间间隔内将Redis在某一刻的数据状态存储到RDB文件中
redis配置文件中可以自动设置RDB持久化条件,通过save ** **
save 900 1
save 300 10
save 60 10000
至少有一个键修改时900秒后自动触发一次RDB持久化
AOF持久化是通过将每个写命令追加到AOF文件中来工作的,恢复时通过重写执行这些命令来重建数据集。目前是redis持久化的主流方式。
有几种AOF持久化同步策略:
always:每次写命令都会同步到AOF
everysec:每秒同步一次,系统崩溃最多损失最后一秒的数据
no:在AOF关闭或者Redis关闭时执行
2.2 RDB和AOF持久化各有什么优势?
RDB是一个非常紧凑的单文件,代表某个时间点的数据快照。适合用于备份数据,比如夜间备份数据,然后将RDB文件复制到远程服务器。但可能会丢失最后一次持久化之后的数据。
AOF持久化灵活、实时性好。缺点是AOF文件较大,恢复速度慢。
2.3 RDB和AOF 如何选择?
如果尽可能减少数据的丢失可选择AOF
如果性能是首要考虑,RDB 可能更适合。RDB 的快照生成通常对性能影响较小,并且数据恢复速度快。
如果系统需要经常重启,并且希望系统重启后快速恢复,RDB 可能是更好的选择。虽然 AOF 也提供了良好的恢复能力,但重写 AOF 文件可能会比较慢。
2.4 Redis数据恢复?
把AOF或RDB文件拷贝到Redis数据目录结构下。
存在AOF文件 优先加载AOF
AOF关闭或不存在加载RDB
加载成功,Redis启动成功
2.5 混合持久化?
混合持久化模式会在 AOF 重写的时候同时生成一份 RDB 快照,然后将这份快照作为 AOF 文件的一部分,最后再附加新的写入命令。
三 高可用
Redis可以通过主从复制、哨兵模式、集群部署实现高可用。
3.1 主从复制
允许Redis服务器将数据从一个节点复制到一个或者多个从节点。适合读多写少的场景。
作用是:实现数据的热备份,持久化之外的数据冗余的一种方式。
故障恢复:如果主节点挂了,可以将从节点提升为主节点。
负载均衡: 主从复制的基础上,配合读写分离,分担服务器负载。
高可用的基石。
3.2 Redis主从复制原理
1. 从机保存主节点信息,ip和端口
2. 建立soket连接,建立网络连接
3.权限认证
4.同步数据集
5.命令持续复制
3.3 主从数据同步方式
全量复制:主从刚建立连接时,会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。
部分复制:当从节点(slave)正在复制主节点 (master)时,如果出现网络闪断、命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,如果主节点的复制积压缓冲区内存在这部分数据则直接发送给从节点,这样就可以保持主从节点复制的一致性
3.4 主从复制存在哪些问题
一旦主节点出现异常需要手动提升从节点为主节点
主节点的写能力受单机限制
主节点的存储能力受单机限制
3.5 哨兵模式实现原理
概念
哨兵节点:哨兵节点是特殊的Redis节点,不存储数据
数据节点:主节点和从节点都是数据节点
主观下线:一个哨兵节点认为这个节点下线为主观下线
客观下线:超过一定数量的哨兵节点认为该节点下线
一般为先发现下线的哨兵节点选取为领导者,进行故障转移
从节点选取一个节点作为新的主节点
让其他从节点变为新的主节点的从节点
将原来的主节点更新为从节点,恢复后命令他去复制新的主节点
3.6 新的主节点如何被挑选出来的
1 过滤不健康的从节点,5秒内无回复哨兵节点的和与主节点断连超过10秒的
2 优先选节点优先级高的从节点
3 选择复制主节点数据量大的从节点为主节点
4 选择ruid最小的从节点
3.7 Redis集群了解吗
集群部署解决了高可用和分布式的问题
作用
1 数据分区:数据分区是集群的核心功能。集群将数据分散到多个节点,存储容量大大增加,每个主节点都对外提供写和读的服务,提高集群的响应能力。
2 高可用:集群支持主从复制和主节点的自动故障转移,任一节点发生故障集群仍可继续对外提供服务。
3.8 切片集群了解吗
切片集群就是将数据分片存储在具有多个Redis实例上的集群框架,每个Redis实例复杂存储部分实例
数据和实例之间如何映射呢
Redis Cluster是Redis提供的分布式解决方案
数据和实例映射是通过hash槽来实现的。Redis cluster的哈希槽被均匀分部在所有Redis实例上
3.9 集群中数据如何分区
节点取余分区、Redis Cluster哈希槽分区、一致性哈希分区
- 节点在圆环上分布不平均,会造成部分缓存节点的压力较大
- 当某个节点故障时,这个节点所要承担的所有访问都会被顺移到另一个节点上,会对后面这个节点造成压力。
3.10 Redis集群原理
Redis 集群通过数据分区来实现数据的分布式存储,通过自动故障转移实现高可用。
集群创建
设置节点->节点握手->分配槽
设置节点:节点数量至少为6个才能保证组成完整高可用集群
节点握手:确保彼此决定通讯
分配槽: 把16384个槽映射到每个实例
故障转移
Redis 集群中所有的节点都要承担状态维护的任务。
3.11 集群伸缩
集群扩容和缩容的关键点,就在于槽和节点的对应关系,扩容和缩容就是将一部分槽
和数据
迁移给新节点
如果希望加入 1 个节点希望实现集群扩容时,需要通过相关命令把一部分槽和内容迁移给新节点。
缩容也是类似,先把槽和数据迁移到其它节点,再把对应的节点下线
四 缓存设计
4.1 什么是缓存穿透、缓存击穿、缓存雪崩
缓存穿透是数据库中根本没有存这个键值,redis中也不会有它的缓存,所以每次请求都要到达数据库,如果这种操作非常频繁,会给数据库造成巨大压力,这就是缓存穿透
解决方法:采用布隆过滤器、第一次查询不存在的数据在缓存中可以存null值。
缓存击穿是有一个或几个数据被高频访问,这些数据在缓存过期的那一刻,大量的查询直接到达数据库,导致数据库压力过大这就是缓存击穿
解决方法:设置逻辑过期时间、加锁更新(比如查询A A缓存过期 对其key加锁 再去数据库中查,再写入缓存中,后面的请求就可在缓存中查到)
缓存雪崩是有大量缓存数据到期了或者服务器宕机了,导致大量的请求到达数据库上,对数据库造成巨大压力,这时是缓存雪崩
解决方法:集群部署
4.2 说一下布隆过滤器
布隆过滤器用于快速检查一个元素是否存在于一个集合中。
其维护长度为m的一个位数组,k个哈希函数
开始时,每个位置都是0
当一个元素添加到过滤器时,它会被k个哈希函数得到k个位置,然后位数组对应的位置设为1
查询时同样用k个hash函数计算位置,任一位置为0则证明该元素不存在过滤器中;全为1,可能在过滤器中。
4.3 如何保证缓存和数据库数据的一致性
先写MySQL,再删除Redis的方式保证缓存和数据库的数据一致性
不一致的根本:
并发导致的脏数据
redis缓存未删除
对一致性要求很高的话采用:
消息队列保证缓存删除
数据库订阅+消息队列保证缓存被删除
延时双删防止脏数据
设置缓存过期时间
4.4 如何处理热Key
将热Key打散到不同的服务器,基本思路就是给热Key加上前缀和后缀
加入二级缓存,出现热Key,把热Key加入到JVM,后续的请求直接从JVM中读取
4.5 缓存预热
提前将一些预定义的数据加载到缓存中,以避免在系统运行初期由于缓存未命中(cache miss)导致的性能问题。
4.5 Redis报内存不足怎么处理
使用集群模式,进行横向扩容
修改淘汰策略,即使释放空间
修改配置文件,增加redis内存空间
4.6 Redis的过期回收策略有哪些?
惰性删除:只有用户查询时检查是否key过期
定期删除:定时检测过期的key删除
4.7 Redis有哪些内存溢出策略
五 Redis 应用
5.1 如何使用Redis实现异步队列
list最为队列,lpush生产消息,rpop消费消息
5.2 如何使用Redis实现延时队列
使用zset来实现延时队列
将任务添加到 zset 中,score 为任务的执行时间戳,value 为任务的内容。
定期(例如每秒)从 zset 中获取 score 小于当前时间戳的任务,然后执行任务。
任务执行后,从 zset 中删除任务。
5.3 Redis支持事务吗
可以利用Lua脚本增强Redis命令,
- Lua 脚本在 Redis 中是原子执行的,执行过程中间不会插入其他命令。
5.4 Redis实现分布式锁了解吗
可以使用 Redis 的 SET 命令实现分布式锁。SET 命令支持设置键值对的同时添加过期时间,这样可以防止死锁的发生。
SET key value NX PX 30000
key
是锁名。value
是锁的持有者标识,可以使用 UUID 作为 value。NX
只在键不存在时设置。PX 30000
:设置键的过期时间为 30 秒(防止死锁)
六 Redis底层
6.1 Redis底层数据结构
动态字符串、链表list、字典、跳表、整数集合、压缩链表
string是由动态字符串实现的
list是由链表实现的
hash是通过字典实现的
set是通过字典实现的
zset是通过跳表、压缩链表实现的
6.2 动态字符串SDS
struct sdshdr {
int len; // buf 中已使用的长度
int free; // buf 中未使用的长度
char buf[]; // 数据空间
};
长度、未使用长度、字符串数组
6.3 list链表
Redis的链表是双向无环链表
每个节点都有前节点的指针和后节点的指针 类似于LinkedList
链表类型中有链表头节点指针 和链表尾节点指针和节点数量
6.4 dict字典
用于保存键值对的抽象数据结构。
hash节点 有键值key 和值 和下一个哈希节点的指针
哈希表 存储hash节点 节点个数 已使用节点数
字典则包含了两个哈希表供平时使⽤和 rehash 时使⽤,hash 表使⽤链地址法来解决键冲突,被分配到同⼀个索引位置的多个键值对会形成⼀个单向链表,在对 hash 表进⾏扩容或者缩容的时候,为了服务的可⽤性,rehash 的过程不是⼀次性完成的,⽽是渐进式的。
6.5 跳表
跳表是有序集合Zset的底层实现之一,以前是由压缩列表来实现的
跳表节点是
typedef struct zskiplistNode {
sds ele;
double score;
struct zskiplistNode *backward;
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned int span;
} level[];
} zskiplistNode;
sds 成员对象
节点分值score,跳表中所有节点得按分值从小到大来排序
前进指针,用于从表头向表尾方向访问节点
层: 跳跃表节点的 level 数组可以包含多个元素,每个元素都包含一个指向其它节点的指针。层数越多访问节点速度越快。
跨度用来计算两个节点之间的距离
6.6 压缩列表
一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。
zlbyttes:记录整个压缩列表的内存字节数
zltail:记录压缩列表表尾节点距离其起始地址有多少个字节
zlen:记录压缩列表的节点数量
entry:列表节点 一个字节数组或整数值
zlend:标记压缩列表末端
总结
redis底层知识一览,看看能不能照着目录回答出来呢