Redis面试
Redis的过期键的删除策略
可以设置Redis中缓存的key的过期时间。
Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理。
- 惰性过期:只有当访问一个key时,才会判断该key是否已经过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好,极端情况下可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量的内存。
- 定期过期:每隔一定时间,会扫描一定数量的数据库的
expires 字典中一定数量的key,并清除其中已经过期的Key,该策略是前两者的一个折中方案,通过调整定期扫描的时间间隔和每次扫描的限定耗时,可以在不同的情况下使得CPU和内存资源达到最优的平衡效果。
Redis集群方案
哨兵模式
主从模式
sentinel,哨兵是Redis集群中非常重要的一个组件,主要有以下功能
- 集群监控:负责监控Redis master和slave进程是否正常工作。
- 消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
- 故障转移:如果master node挂掉了,会自动转移到slave node上。
- 配置中心:如果故障转移发生了,通知client客户端新的master地址。
哨兵用于实现redis集群的高可用,本身也是也是分布式的,作为一个哨兵集群去运行,互相协同工作。
- 故障转移时,需要大部分的哨兵同意才行,涉及到了分布式选举。
- 即使部分哨兵节点挂掉了,哨兵集群还能正常工作。
- 哨兵通常需要3个实例,来保证自己的健壮性。
- 哨兵+redis主从的部署结构,是不保证数据零丢失的,只能保证redis集群的高可用性。
Redis cluster
Redis cluster是一种服务端的Sharding技术。Redis cluster采用slot槽的概念,一共分成16384个槽位。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。
方案说明
- 通过hash的方式,将数据分片,每个节点均分存储一定哈希槽区间的数据,默认分配了16384个槽位。
- 每份数据分片会存储在多个互为主从的多节点上。
- 数据写入先写入主节点,再同步到从节点。
- 同一分片多个节点间的数据不保持强一致性。
- 读取数据时,当客户端操作的key没有分配在该节点上,redis会返回转向指令,指向正确的节点
- 扩容时需要把旧节点的数据迁移一部分到新节点
在Redis cluster架构下,每个redis要放开两个端口号,一个是6379,另外一个就是加10000的端口号,比如16379。
16379端口号是用来进行节点间通信的,也就是cluster bus的通信,用来进行故障检测,配置更新,故障转移授权。
优点:
- 无中心架构,支持动态扩容,对业务透明。
- 具备哨兵的监控和自动的故障转移能力。
- 客户端不需要连接集群所有节点,连接集群中任意一个可用节点即可。
- 高性能,客户端直接连接Redis服务,免去了proxy代理的损耗。
缺点:
- 运维很复杂,数据迁移需要人工干预。
- 只能使用0号数据库。
- 不支持批量操作。
Redis Sharding
Redis Sharding是Redis cluster出来之前,业界普遍使用的多Redis实例集群方法,其主要思想是采用哈希算法将Redis数据的key进行散列,通过hash函数,特定的key会映射到特定的Redis节点上。
优点: 优势在于非常简单,服务端的redis实例彼此独立,相互无关联,每个Redis实例像单服务器一样运行,非常容易线性扩展,系统的灵活性很强。
缺点: 由于sharding处理放到客户端,规模进一步扩大时给运维带来挑战。
客户端sharding不支持动态增删节点,服务端Redis实例群拓扑结构有变化时,每个客户端都需要更新调整,连接不能共享,当应用规模扩大时,资源浪费制约优化。
Redis单线程为什么快?
(1)纯内存操作
(2)核心是基于非阻塞的IO多路复用机制
(3)单线程反而避免了多线程的频繁上下文切换带来的性能问题
Redis基于Reactor模式开发了网络事件处理器,文件事件处理器file event handler。它是单线程的,所以Redis才叫做单线程的模型,它采用IO多路复用机制来同时监听多个Socket,根据Socket上的事件类型来选择对应的事件处理器来处理这个事件,可以实现高性能的网络通信模型,又可以跟内部其他单线程的模块进行对接,保证了Redis内部的线程模型的简单性。
文件事件处理器的结构包含4个部分,多个Socket,IO多路复用程序,文件事件分派器以及事件处理器。
多个Socket可能并发的产生不同的事件,IO多路复用程序会监听多个Socket,会将Socket放入一个队列中排队,每次从队列中有序,同步取出一个Socket给事件分派器,事件分派器把Socket给对应的事件处理器。然后一个Socket的事件处理完之后,IO多路复用程序才会将队列中的下一个Socket给事件分派器,文件事件分派器会根据每个Socket当前产生的事件,来选择对应的事件处理器来处理。
Redis分布式锁底层是如何实现的?
- 首先利用
setnx 来保证:如果key 不存在才能获取到锁,如果key 存在,则获取不到锁; - 然后还要利用LUA脚本来保证多个Redis操作的原子性;
- 同时还要考虑到锁过期,所以需要额外的一个看门狗定时任务来监听锁是否需要续时;
- 同时还要考虑到Redis节点挂掉后的情况,所以需要采用红锁的方式来同时向
N
/
2
+
1
N/2 + 1
N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个Redis节点挂掉了,所也不能被其他客户端获取到。
Redis事务实现
事务开始
MULTI 命令的执行,标识着一个事务的开始,MULTI 命令会将客户端状态的flags 属性中打开REDIS_MULTI 标识来完成。
命令入队
当一个客户端切换到事务状态之后,服务器会根据这个客户端发送来的命令来执行不同的操作,如果客户端发送的命令为MULTI ,EXEC ,WATCH ,DISCARD 中的一个,立即执行这个命令,否则将命令放入一个事务队列里面,然后向客户端返回QUEUED回复。
- 如果客户端发送的命令为
MULTI ,EXEC ,WATCH ,DISCARD 四个命令的其中一个,那么服务器立即执行这个命令。 - 如果客户端发送的是四个命令以外的其他命令,那么服务器并不立即执行这个命令。首先检查此命令的格式是否正确,如果不正确,服务器会在客户端状态的flag属性关闭
REDIS_MULTI 标识,并且返回错误信息给客户端。 - 如果正确,将这个命令放入一个事务队列里面,然后向客户端返回QUEUED回复。
事务队列按照FIFO的方式保存入队的命令。
事务执行
客户端发送EXEC命令,服务器执行EXEC命令逻辑。
- 如果客户端状态的flags属性不包含REDIS_MULTI标识,那么直接取消事务的执行。
- flags中有REDIS_MULTI标识,服务器会遍历客户端的事务队列,然后执行事务队列中的所有命令,最后将返回结果全部返回客户端。
redis不支持事务回滚机制,但是它会检查每一个事务中的命令是否错误。
Redis事务不支持检查程序逻辑错误。
WATCH 命令是一个乐观锁,可以为Redis事务提供check-and-set(CAS)行为。可以监控一个或多个键。一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。MULTI 命令用于开启一个事务,返回OK,MULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。EXEC :执行所有事务块的命令,返回事务块内所有命令的返回值,按命令执行的先后顺序排列,当操作被大端时,返回空值。DISCARD :客户端可以清空事务队列,并放弃执行事务,并且客户端会从事务状态中退出。UNWATCH 命令可以取消WATCH对所有Key的监控。
Redis的持久化机制
RDB
redis database 将某一个时刻的内存快照,以二进制的方式写入磁盘。
手动触发:
save 命令,使Redis处于阻塞状态,直到RDB持久化完成,才会响应其他客户端发来的命令,所以在生产环境中要慎用。bgsave 命令,fork 出一个子进程执行持久化,主进程只在fork 过程中有短暂的阻塞,子进程创建之后,主进程就可以响应客户端请求了。
自动触发:
save m n :在m秒内,如果有n个键发生改变,则自动触发持久化,通过bgsave 执行,如果设置多个,只要满足其一就会触发,配置文件有默认配置。- 主从同步:全量同步时会自动触发
bgsave 命令,生成rdb发送给从节点。
优点:
- 整个Redis数据库只包含一个文件
dump.rdb ,方便持久化。 - 容灾性好,方便备份。
- 性能最大化,
fork 子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了Redis的高性能。 - 在处理大数据集时,比AOF的启动效率更高。
缺点:
- 数据安全性低。RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失,所以这种方式更适合数据要求不严谨的时候。
- 由于RDB是通过
fork 子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟,会占用CPU。
AOF
Append only File 以日志的形式记录服务器所处理的每一个写,删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
- 所有的写命令会追加到AOF缓冲中。
- AOF缓冲区根据对应的策略向硬盘进行同步操作。
- 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
- 当Redis重启时,可以加载AOF文件进行数据恢复。
优点:
- 数据安全
- 通过append模式写文件,即使中途服务器宕机也不会破坏已经存在的内容,可以通过redis-check-aof工具解决数据一致性问题。
- AOF机制的rewrite模式,定期对AOF文件进行重写,以达到压缩的目的。
缺点
- AOF文件比RDB文件大,且恢复速度慢。
- 数据集大的时候,比RDB启动效率低。
- 运行效率没有RDB高。
|