超详细redis知识点归纳
2020-01-06 11:35:33 0 举报
AI智能生成
redis面试超详细知识点归纳
作者其他创作
大纲/内容
Redis数据持久化
两种持久化方式
AOF
概念:以日志形式记录每一次对redis的写命令,可以通过重复执行记录的命令来进行数据恢复
AOF的重写机制:AOF提供了重写机制,去除无用指令以及合并多条指令达到压缩的目的。
更小的文件也意味着更快的加载速度。重写机制不会阻塞redis
更小的文件也意味着更快的加载速度。重写机制不会阻塞redis
缺点:
1.AOF文件记录的更详尽,意味着文件占用空间更大
2.AOF数据恢复的速度相对于RDB更慢
3.有一个罕见的BUG导致数据无法完全一致的恢复,但是暂未在实际使用中发现
1.AOF文件记录的更详尽,意味着文件占用空间更大
2.AOF数据恢复的速度相对于RDB更慢
3.有一个罕见的BUG导致数据无法完全一致的恢复,但是暂未在实际使用中发现
优点
1.AOF默认一秒钟执行一次fsync操作,即使发生故障,最多也只是丢失那没来得及写入日志的一秒钟的命令数据
2.AOF对误操作有更强的容错性,由于AOF是逐条命令的记录,因此当发生灾难性的数据误操作时(比如清库),只要这个时候AOF还没被重写(重写机制),先把redis停掉,然后把AOF文件拷贝出来,将最后的误操命令(比如清库的FLUSHALL)删除,然后用修改后的AOF做数据恢复即可。
1.AOF默认一秒钟执行一次fsync操作,即使发生故障,最多也只是丢失那没来得及写入日志的一秒钟的命令数据
2.AOF对误操作有更强的容错性,由于AOF是逐条命令的记录,因此当发生灾难性的数据误操作时(比如清库),只要这个时候AOF还没被重写(重写机制),先把redis停掉,然后把AOF文件拷贝出来,将最后的误操命令(比如清库的FLUSHALL)删除,然后用修改后的AOF做数据恢复即可。
fsync()是一个系统调用函数,告诉操作系统把数据写到硬盘上,而不是缓存更多数据才写到硬盘。
RDB
概念:生成某个时刻的redis数据快照,直接加载快照进行数据恢复
优点
1.数据恢复数据相对AOF更快
1.数据恢复数据相对AOF更快
缺点
1.因为是某个时刻的快照,在这个时刻和下一个备份点之间插入的数据会丢失。不适用于对数据丢失敏感的场景。
2.RDB需要经常fork()创建子进程来保存快照,创建的过程是阻塞的重量级的操作。如果数据量过大,会造成redis有短暂的无响应状态。
1.因为是某个时刻的快照,在这个时刻和下一个备份点之间插入的数据会丢失。不适用于对数据丢失敏感的场景。
2.RDB需要经常fork()创建子进程来保存快照,创建的过程是阻塞的重量级的操作。如果数据量过大,会造成redis有短暂的无响应状态。
持久化方式的选择:官方推荐的做法是RDB+AOF。如果系统可以容忍几分钟的数据丢失,那么可以只用RDB。但是不推荐仅使用AOF。因为AOF加载相对慢而且有那个罕见的BUG
数据持久化参考链接
Redis集群
基本概念
1.集群中的每个redis称为一个节点
2.有两种节点,主节点Master,从节点Slave,每个节点都必须设置一个优先级,即这个节点在故障切换过程中被选举为Master的优先级
3.集群的可用性判断:主从模式,master挂了就不可用了。另外两种模式,集群中的任意一个master节点挂了,且这个master没有slave可用,那么这个集群就是挂了的
2.有两种节点,主节点Master,从节点Slave,每个节点都必须设置一个优先级,即这个节点在故障切换过程中被选举为Master的优先级
3.集群的可用性判断:主从模式,master挂了就不可用了。另外两种模式,集群中的任意一个master节点挂了,且这个master没有slave可用,那么这个集群就是挂了的
主从复制
基本概念
复制ID:master节点的数据集的I一个随机字符串ID,标记了某个master节点的数据集.当一个master节点重启或者一个slave节点升级为master节点时,会重新生成新的复制ID
偏移量:理解成数据的版本号。每次写数据,偏移量都会递增。偏移量一致,则表示数据同步一致。
全量复制:顾名思义,使用RDB做master的完全拷贝。一般发生在新slave节点启动或旧slave节点重连且无法满足增量复制条件的时候
增量复制:master向slave发送每一次写操作的命令,是主从复制优先尝试的方式
主从复制过程:
1.当一个Slave启动的时候,会使用PSYNC命令将其原本的master的复制ID以及偏移量发送给现在的master,请求同步数据
2.如果复制ID还可追溯(复制ID没变或者复制ID是最近故障的master的ID,还保存在新的master中,详见参考链接的Relication ID Explained 章节 The reason why Redis instances have two replication IDs,节点升级为master尽管复制ID变了,可能还是做增量复制),复制积压缓冲足够,那就直接做增量复制
3.如果复制ID已经无法追溯,或者积压缓冲不足,则做全量复制
1.当一个Slave启动的时候,会使用PSYNC命令将其原本的master的复制ID以及偏移量发送给现在的master,请求同步数据
2.如果复制ID还可追溯(复制ID没变或者复制ID是最近故障的master的ID,还保存在新的master中,详见参考链接的Relication ID Explained 章节 The reason why Redis instances have two replication IDs,节点升级为master尽管复制ID变了,可能还是做增量复制),复制积压缓冲足够,那就直接做增量复制
3.如果复制ID已经无法追溯,或者积压缓冲不足,则做全量复制
全量复制的过程
1.master节点执行BGSAVE命令fork()子进程,生成RDB快照。同时在缓存新进来的写命令
2.master将快照发送给slave
3.slave收到RDB加载并刷新数据
4.master将缓存的新命令以命令流的形式发送给slave完成数据的完全同步
1.master节点执行BGSAVE命令fork()子进程,生成RDB快照。同时在缓存新进来的写命令
2.master将快照发送给slave
3.slave收到RDB加载并刷新数据
4.master将缓存的新命令以命令流的形式发送给slave完成数据的完全同步
积压区缓存的判断过程
(1)主从分别维护一个seq,主每次完成一个请求便seq+1,从每同步完后更新自己seq;
(2)从每次打算同步时都是携带着自己的seq到主,主将自身的seq与从做差结果与积压缓冲区大小比较,如果小于积压缓冲区大小,直接从积压缓冲区取相应的操作进行部分重同步;
(3)否则说明积压缓冲区不能够cover掉主从不一致的数据,进行全量同步。
(1)主从分别维护一个seq,主每次完成一个请求便seq+1,从每同步完后更新自己seq;
(2)从每次打算同步时都是携带着自己的seq到主,主将自身的seq与从做差结果与积压缓冲区大小比较,如果小于积压缓冲区大小,直接从积压缓冲区取相应的操作进行部分重同步;
(3)否则说明积压缓冲区不能够cover掉主从不一致的数据,进行全量同步。
参考链接
How Redis replication works
Replication ID explained
Replication ID explained
redis主从复制原理
如何保持集群对节点状态的数据一致性:gossip协议
Gossip protocol 最早是在 1987 年发表在 ACM 上的论文 《Epidemic Algorithms for Replicated Database Maintenance》中被提出。主要用在分布式数据库系统中各个副本节点同步数据之用(顺带提一下bitcoin也是用了这个协议来传播交易信息哦),这种场景的一个最大特点就是组成的网络的节点都是对等节点,是非结构化网络。Gossip 过程是由种子节点发起,当一个种子节点有状态需要更新到网络中的其他节点时,它会随机的选择周围几个节点散播消息,收到消息的节点也会重复该过程,直至最终网络中所有的节点都收到了消息。这个过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个最终一致性协议。
集群高可用
1.主从模式
概念:最简单的模式,一个集群中有且只有一个主节点,主节点可读写,从节点只读。主节点下线,影响写服务,不影响读服务。
数据同步机制:当slave启动后,主动向master发送SYNC命令。master接收到SYNC命令后在后台保存快照(RDB持久化)和缓存保存快照这段时间的命令,然后将保存的快照文件和缓存的命令发送给slave。slave接收到快照文件和命令后加载快照文件和缓存的执行命令。复制初始化后,master每次接收到的写命令都会同步发送给slave,保证主从数据一致性。
缺陷:master挂掉后不能对外提供写服务(salve不会自动升级为master)。因此主从模式,只提供了读写分离的特性,不满足高可用
2.哨兵模式(Sentinel)
自动故障切换机制:
1.当一个master被大多数sentinel标记为主观下线时,这个master从主观下线标记变为客观下线标记,failover故障切换机制会被触发
2.投票产生领头sentinel:每个发现master客观下线的sentinel都会要求其他sentinel将自己选为领头,去执行故障迁移;投票采用先到先得策略,已经给某个候选人投过票的sentinel,不再接受其他候选人的投票请求
3.选举Slave升级为master:在淘汰已线下、超时、响应慢的slave节点后,领头sentinel先后根据节点的优先级、复制偏移量(标记了slave复制了多少master数据)、进程id选择最优的Slave成为新的master,将原master和其下的slave全部归为新master的slave
4.更新节点配置信息
1.当一个master被大多数sentinel标记为主观下线时,这个master从主观下线标记变为客观下线标记,failover故障切换机制会被触发
2.投票产生领头sentinel:每个发现master客观下线的sentinel都会要求其他sentinel将自己选为领头,去执行故障迁移;投票采用先到先得策略,已经给某个候选人投过票的sentinel,不再接受其他候选人的投票请求
3.选举Slave升级为master:在淘汰已线下、超时、响应慢的slave节点后,领头sentinel先后根据节点的优先级、复制偏移量(标记了slave复制了多少master数据)、进程id选择最优的Slave成为新的master,将原master和其下的slave全部归为新master的slave
4.更新节点配置信息
概念:基于主从模式,多了哨兵的角色。Sentinel由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
缺陷:(其实是单master的缺陷)
1.每个节点保存的数据都一样,存在冗余,造成内存浪费。
2.因为每个节点保存的数据都一样,master的最大存储容量决定了整个集群的容量,上限有限
3.如果数据量较大,故障恢复会需要比较长的时间。
1.每个节点保存的数据都一样,存在冗余,造成内存浪费。
2.因为每个节点保存的数据都一样,master的最大存储容量决定了整个集群的容量,上限有限
3.如果数据量较大,故障恢复会需要比较长的时间。
参考链接:
3.集群模式(Cluster)
优点:高可用、可扩展。横向扩容可支持海量数据
概念:基于主从模式+哨兵模式,引入分片的设计,通过hash计算,将数据分开存储对应节点负责的槽(slot)
参考链接:
keepalived机制(双机热备)
优点:通过VIP的漂移实现主备切换,提供不间断的读写服务。实现简单,成本低
缺陷:单机吞吐量有限
集群的脑裂问题
应用
基本的数据缓存
常见问题
缓存击穿
问题描述:缓存的某个热点key值抗住了大量的查询。在这个key失效的瞬间,大量查询请求击穿缓存,涌向数据库(想象下防护屏障上破了一个小孔,大量的妖魔鬼怪涌入的场景)
解决方法:
1.热点数据设置为永不过期
2.限流(牺牲部分用户体验来保证系统可用性)
1.热点数据设置为永不过期
2.限流(牺牲部分用户体验来保证系统可用性)
缓存雪崩
问题描述:大批量的热点缓存在同一时间点过期,导致大面积的缓存击穿出现,数据库压力过大可能会挂掉
解决方法
1.热点数据设置为永过期
2.设置缓存有效期时加入随机数,确保热点数据不在同一个时间点过期
1.热点数据设置为永过期
2.设置缓存有效期时加入随机数,确保热点数据不在同一个时间点过期
缓存穿透
问题描述:redis缓存没有对应key的数据,数据库也没有对应key的数据,是为缓存穿透。常被用于使用不存在的key进行大批量查询的恶意攻击
解决方法:
1.接口的鉴权
2.BloomFilter 做预判,如果key不存在直接返回。如果key存在则查db刷缓存
1.接口的鉴权
2.BloomFilter 做预判,如果key不存在直接返回。如果key存在则查db刷缓存
BloomFilter的原理是使用多个哈希算法将一个字符串映射到多个bit上,仅当
每个bit都是1这个字符串才可能存在于全集中,否则一定不存在
每个bit都是1这个字符串才可能存在于全集中,否则一定不存在
缓存淘汰策略
常见的缓存淘汰策略
FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
redis提供的缓存淘汰策略
noeviction:不做任何淘汰。在内存达到最大限制时,客户端尝试会导致内存使用增加的写操作时,返回错误(DEL等不会导致内存增加的写操作例外)
allkeys-lru:为了新添加的键值有空间存放,会在全部key中淘汰最近最少使用的key
volatile-lru:为了新添加的键值有空间存放,会在有设置过期时间的key集中淘汰最近最少使用的key
allkeys-random:为了新添加的键值有空间存放,随机淘汰一些key
volatile-ttl:为了新添加的键值有空间存放,在有设置过期时间的key集合中,淘汰存活时间(TTL)最短的key
参考链接
分布式锁
RedLock算法
前提条件:有N个互相完全独立的master节点(节点完全互相独立,之间不存在主从复制或其他集群协调机制)
算法过程:
1.获取当前毫秒级时间
2.依次尝试对这个N个节点加锁。在尝试加锁的时候应该设置一个加锁的超时时间,这个超时时间应该小于锁的失效时间,避免redis节点已经挂掉了,锁都达到失效时间了,客户端还在等待加锁结果。如果redis没有在超时时间内响应,客户端应该放弃该节点,尝试下一个节点的加锁。
3.当且仅当超过 N/2+1个节点加锁成功时,进入第四步
4.客户端使用当前时间,减掉第一步的时间,得到整个加锁尝试过程耗时。如果加锁的耗时小于锁的失效时间,那么就认为加锁成功。
5.如果客户端尝试加锁失败(少于半数节点被加锁或加锁耗时超过了锁的有效期),那么客户端会休眠一段随机时间后,重新尝试加锁
1.获取当前毫秒级时间
2.依次尝试对这个N个节点加锁。在尝试加锁的时候应该设置一个加锁的超时时间,这个超时时间应该小于锁的失效时间,避免redis节点已经挂掉了,锁都达到失效时间了,客户端还在等待加锁结果。如果redis没有在超时时间内响应,客户端应该放弃该节点,尝试下一个节点的加锁。
3.当且仅当超过 N/2+1个节点加锁成功时,进入第四步
4.客户端使用当前时间,减掉第一步的时间,得到整个加锁尝试过程耗时。如果加锁的耗时小于锁的失效时间,那么就认为加锁成功。
5.如果客户端尝试加锁失败(少于半数节点被加锁或加锁耗时超过了锁的有效期),那么客户端会休眠一段随机时间后,重新尝试加锁
Redission提供了RedLock的Java实现
Q&A
1.redis加锁的时候,为啥既要key又要value呢?而且value通常是一个随机字符串?
这里的value其实可以理解为客户端的签名,是为了防止释放锁的时候,释放了其他客户端的锁。想象下这种场景,客户端A对加锁后,因为某种原因阻塞了,一段时间后,锁过期了。客户端B加锁,并开始跑业务。这个时候,阻塞的客户端A又可以继续走下去了,于是客户端A执行完毕后,进行锁的释放。如果不使用不同的value,那么这个时候客户端A就会把B的锁给释放掉。
2.客户获取锁失败后,在重试加锁之前,为何必须等待一段随机时间?
为了防止获取锁过程中的脑裂问题(即谁也无法成功给超过半数的实例加锁的情况)。比如同时有ABC三个客户端尝试给5个实例加锁,各自加锁2/2/1个实例,此时没有任何一个客户端胜出,全都加锁失败。如果不等待一段随机时间,又马上开始同时竞争,可能还是都加锁失败
3.单redis节点实现的简单分布式锁是否可应用于强一致性的场景?
单redis节点实现的简单分布式锁不适用于一致性要求高的场景。当master节点拿到了锁,但是锁还未同步到slave节点,此时master节点挂了,发生故障转移,slave节点被选举为master节点,丢失了锁。这样其他线程就能够获取到该锁。这个是由于redis的主从复制是异步非实时导致的。
参考链接
队列
0 条评论
下一页