目录
Redis分布式缓存
单机Redis存在的四大问题
Redis持久化
RDB持久化
-
简介
- Redis的一种数据持久化方案,也叫Redis数据快照,简单来说就是将内存数据保存到磁盘中去,当redis实例故障重启后,就可以从磁盘中读取快照文件,恢复数据
-
执行时机
- 执行save命令时(主进程执行save时进程会阻塞,无法执行其他命令)
- 执行bgsave命令时(bgsave命令会开启子进程去保存数据,基本不会阻塞主进程)
- Redis停机时会自动执行一次
- 满足RDB条件时,如900秒内至少有一个key被改变时
-
RDB其他配置,可在redis.conf文件中配置
# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱 rdbcompression yes # RDB文件名称 dbfilename dump.rdb # 文件保存的路径目录 dir ./
-
bgsave命令原理
- 在linux系统中,所有的进程都无法直接操作物理内存,而是给进程提供一个虚拟内存,进程只能操作虚拟内存,由操作系统维护虚拟内存与物理内存的映射关系表,从而实现进程操作物理内存,当执行bgsave命令时,主进程会folk出一个子线程,子线程复制了一份主进程的映射关系表,由子进程读取内存中的数据并写入到新的RDB文件中去,然后使用新的RDB文件替换旧的RDB文件,这里采用了copy-on-write技术,此时,内存中的数据被设置为了只读状态,在子进程读取的过程中,主进程可能会接到修改内存数据的请求,即主进程需要读取数据时访问的是共享的数据,主进程需要修改数据时会复制一份内存数据再进行修改,修改后再次读取读取的就会是拷贝的数据
-
原理图
-
缺点
- 执行间隔时间长,两次RDB之间可能会有数据丢失
- folk子进程,压缩,写出RDB文件都比较耗时
AOF持久化
-
简介
- 将Redis处理的每一个命令都记录到aof文件中去,可看作是命令日志
-
AOF配置
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
三种策略对比:
-
AOF文件重写
- 因为aof文件记录的是所有命令,其中必然有很多命令是不需要记录的,例如对同一个key的多次修改,仅需记录最后一次修改命令即可,通过执行bgrewriteaof命令,即可实现重写aof文件,使其记录的命令更加精简,Redis会在触发阈值时自动去重写aof文件,阈值可以在配置文件中设置
RDB与AOF对比
Redis主从架构
搭建意义
- 单节点的redis并发能力是有上限的,要提高redis的并发能力,就要搭建redis主从集群,实现读写分离
主从数据同步原理
-
全量同步
- 第一次建立连接时,会进行一次全量同步,将master节点的所有数据全部拷贝给slave节点
- 流程图
-
master如何判断slave是否是第一次连接?
-
两个概念:
-
replicatioin id: 简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
-
offset: 偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
slave向master请求数据同步时需要声明自己的replication id和offset,因为slave原本也是一个master,有自己的replid和offset,当第一次变成slave,与master建立连接时,发送的replid和offset是自己的replid和offset。
master判断发现slave发送来的replid与自己的不一致,说明这是一个全新的slave,就知道要做全量同步了。
master会将自己的replid和offset都发送给这个slave,slave保存这些信息。以后slave的replid就与master一致了。
因此,master判断一个节点是否是第一次同步的依据,就是看replid是否一致
-
-
-
执行时机
- slave节点第一次连接master节点时
-
slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
-
增量同步
- 除了第一次建立连接时会做全量同步,其他时候都是做增量同步,即同步master与slave不同的地方
- 流程图
-
repl_backlog原理
repl_backlog文件是一个环形数组,即当文件写满后,新的数据会从文件开头开始覆盖就的数据,这个文件里面记录了reids处理的命令日志,master和slave的偏移量offset,做增量同步时,会根据master和slave的偏移量大小差异拷贝不一致的数据,若slave断开连接太久,导致它尚未同步的数据已经被master写入的新数据覆盖,则无法基于该文件做增量同步,只能做全量同步
-
执行时机
- slave节点断开又恢复,并且在repl_baklog中能找到offset时
-
全量同步和增量同步区别
- 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
- 增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
主从同步优化
- Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
- 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
- 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
主从架构图
Redis哨兵
Redis哨兵结构图
哨兵作用
-
监控: Sentinel会不断检测master和slave是否按照预期正常工作
- 集群监控原理:
Sentinel基于心跳机制检测服务状态,每隔一秒向客户端实例发送ping命令
主观下线: 如果某个sentinel发现某个服务实例未在指定时间内响应,则认为该实例主观下线
客观下线: 如果指定数量(quorum)的Sentinel都认为某个服务实例主观下线,则认为该实例客观下线,quorum值最好超过Sentinel数量的一半
- 集群监控原理:
-
故障自动恢复: 如果一个master故障,Sentinel会将一个slave提升为master,故障的实例恢复后也将以新的master为准,成为slave
- 集群故障恢复原理:
如果某个master故障,Sentinel需要在slave中选择一个作为新的master,选择依据如下:
首先判断slave和master断开的时长,若断开时间超过指定值(down-after-milliseconds*10)则会排除该slave
然后判断slave的slave-priority值,值越小优先级越高,为0则不参与选举
若slave-priority值一致,则比较offset值的大小,越大表示数据越新,优先级越高
最后判断slave的运行id大小,越小优先级越高
选举成功后,切换流程如下:
Sentinel给被选中的slave节点slave1发送slave of no one命令,使该节点成为master节点
Sentinel向所有其他slave节点发送slaveof slave1(新master节点的ip地址和端口号),是他们成为新master节点的从节点,开始从新master上同步数据
Sentinel将故障节点标记为slave,故障节点恢复后也将成为新master节点的slave
- 集群故障恢复原理:
-
通知: Sentinel充当Redis的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis客户端
Redis分片集群
作用
- 解决海量数据储存和高并发写问题
Redis分片集群结构图
分片集群特征
- 每个集群中由多个master,每个master保存不同的数据
每个master都可以有多个slave节点
master之间通过ping互相检测健康状态
客户端请求可以访问任意节点,最终请求会被转发到正确节点
散列插槽
- 插槽原理:
Redis将每一个master映射到0-16383共16384个插槽(hash slot)上,数据的key并不与master绑定,而是与插槽绑定,redis会根据数据key的有效部分计算插槽值,分为两种情况:
- 若key中带有’{}‘,且’{}‘中至少有一个字符,则’{}'中的内容为有效部分
- 若key中不带’{}',则整个key为有效部分
插槽值的计算方式为利用CRC16算法计算得到一个hash值,再对16384取余得到插槽值
集群伸缩
- 集群伸缩是指在一个集群中增加或减少节点的数量,以适应不同的工作负载需求。集群伸缩的目的是为了自动化地分配和处理工作,同时最大化系统的利用率和可用性。当工作负载较轻时,可以减少集群的节点数量,以降低资源消耗和成本;而当工作负载增加时,可以增加集群的节点数量,以扩展系统容量,提高系统响应速度和性能。
windows集群操作命令可通过redis-cli --cluster help查看
故障转移
- 自动故障转移:
若集群中某个master故障下线,则会经历从疑似宕机到确认下线的判断过程,然后自动提升一个slave为master,下线实例恢复后会成为slave节点 - 手动故障转移:
使用cluster failover命令可以将集群中指定的master宕机,并将执行该命令的slave提升为master,实现无感知数据迁移
此命令可指定三种模式:
缺省:不指定,默认如下图中1-6步
force: 省略了对offset一致性的校验
takevoer: 直接执行第五步,省略数据一致性校验,忽略master状态和其他master意见 - 手动故障转移流程图