一、单点redis问题:
1、数据丢失问题
实现redis数据持久化
2、并发问题
搭建主从集群,实现读写分离
3、故障恢复问题
搭建redis哨兵,实现监控监测和自动恢复
4、存储能力问题
搭建分片集群,利用插槽机制实现动态扩容
二、Redis持久化
1、定义
利用永久性存储介质将数据进行保存,在特定的时间将保存的数据恢复的工作机制称为持久化。
(持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。)
2、RDB持久化
(1)定义
- RDB全称Redis Database Backup file(Redis数据备份文件),也叫Redis数据快照。是把内存中的所有数据记录到磁盘中。
- 当redis实例故障重启后,从磁盘中读取快照文件,恢复数据。
- 快照文件称为RDB文件,默认保存在当前运行文件。
(2)命令
- save
由Redis主进程来执行RDB,会阻塞所有命令。服务端正常停止,会执行一次。
- bgsave
开启子进程执行RDB,避免主进程受影响。
- redis.conf配置
修改redis.conf文件中的save指令,redis会按照命令自动执行(bgsave)。
#900秒内,至少有1个key被修改,则执行bgsave
save 900 1
#文件保存的路径目录
dir ./
#RDB文件名称
dbfilename dump.rdb
(3)底层原理
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后,读取内存数据写入Rdb文件,如下图:
- 所有的进程都不能直接操作物理内存,而是由操作系统给每个进程分配一个虚拟内存,主进程只能操作虚拟内存。操作系统会维护一个物理内存与虚拟内存之间映射关系表,即页表。
- 主进程操作虚拟内存,而虚拟内存基于页表的映射关系,到物理内存真正的存储地址。
- fork的过程是把页表进行拷贝给子进程。
问题:
由于bgsave是异步的,子进程在生成rdb文件时,主进程接收请求对数据进行修改。主进程写,子进程读,冲突,怎么办?
回答:
fork采用copy-on-write技术:
·当主进程执行读操作时,访问共享内存;
·当主进程执行写操作时,则会拷贝一份数据执行写操作
(4)优缺点
(5)总结
3、AOF持久化
(1)定义
AOF全称Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件中,可以看做是命令日志文件。
(2)conf文件
AOF默认是关闭的,需要在redis.conf文件开启
//是否开启AOF功能,默认是no
appendonly yes
//AOF文件名称
appendfilename "appendonly.aof"
//AOF命令记录的频率
//1、表示每执行一次写命令,都记录到AOF文件
appendfsync always
//2、写命令执行完,先放入AOF缓存区中,然后每隔一秒将缓存区数据写入AOF文件(默认)
appendfsync everysec
//3、写命令执行完,先放入AOF缓存区中,由操作系统决定何时写入磁盘
appendfsync no
(3)AOF文件重写
因为是记录命令,AOF文件会比RDB文件大的多;AOF会记录同一个key的多次写操作,但只有最后一次有意义 bgrewriteaof
//重写文件
bgrewriteaof
//AOF文件比上次文件 增长超过多少百分比才触发重写
auto-aof-rewrite-percentage 100
//AOF文件体积最小在64m以上才触发重写
auto-aof-rewrite-min-size 64mb
作用:降低磁盘占用量;提高持久化效率;提高数据恢复效率
4、RDB和AOF区别
三、Redis主从架构
1、定义
单节点Redis的并发能力是有上限,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
主节点master,负责写操作;从节点slave,负责读操作,一主多从,增大读的能力;master数据同步slave节点
2、搭建主从集群
(1)创建目录
mkdir 7001 7002 7003
(2)复制redis.conf文件
cp redis-6.1.4/redis.conf 7001
修改port,dir
添加 声明ip replica-announce-ip 162.168.150.101
(3)配置主从
-
从节点修改配置文件(永久生效)
在redis.conf中添加replicaof/slaveof <master_ip><master_port> -
使用redis-cli客户端连接redis服务时,执行replicaof命令(重启后失效)
-
查看情况 info replication
3、数据同步原理
(1)主从第一次同步是全量同步
问题: master如何判断slave是第一次来同步数据?
- Replication Id:简称replid,是数据集的标记,id一致则说明是统一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid。
- offset:偏移量。随着记录在master节点中的repl_baklog中的数据增多而逐渐增大。slave节点在同步时,也会记录offset。如果slave的offset小于master的offset,说明slave落后于master,需要更新
总结:简述全量同步的流程
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
- slave执行接收到的命令,保持与slave之间的同步
(2)增量同步
如果slave重启后同步,则执行增量同步。
4、优化
5、总结
(1)简述全量同步和增量同步的区别?
- 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
- 增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave。
(2)什么时候执行全量同步?
- slave节点第一次连接master节点时
- slave节点断开时间太久,repl_baklog中的offset已经被覆盖
(3)什么时候执行增量同步?
slave节点断开又恢复,并且在repl_baklog中能找到offset时。
四、Redis哨兵(Sentinel)
1、哨兵的作用和原理
(1)作用:实现主从集群的自动故障恢复。
(2)功能:
- 监控:Sentinel会不断检查master和slave状态【
如何获取节点状态?
】。 - 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障恢复后,也是以新的master为主。
【选择slave依据是什么?
】【如何实现故障转移
】 - 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将消息推送给Redis客户端
(3)获取节点状态:(判断一个redis实例是否健康)
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令
- 主观下线:如果sentinel节点发现某Redis实例未在规定时间响应则认为该实例主观下线。
- 客观下线:如果超过指定数量的sentinel都认为该实例主观下线,则该实例客观下线。数量值最好超过sentinel节点数量的一半。
(4)选择slave依据:(故障转移步骤有哪些)
-
首先会判断slave节点与master节点断开时间长短,如果超过指定值down-after-milliseconds * 10,则会排除该节点
-
判断salve节点的slave-priority,值越小优先级越高,如果是0,则永不参与
-
判断salve节点的offset值,值越大说明数据越新,优先级越高【最重要】
-
判断slave节点的运行id大小,越小优先级越高
(5)如何实现故障转移:
当选择一个slave节点作为新的master后,故障转移步骤如下:
-
sentinel给备选的slave节点发送slaveof no one 命令,让该节点成为master节点
-
sentinel给所有其他的slave发送slaveof 【ip】【port】命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
-
sentinel将故障节点标记为slave,执行slaveof命令,当故障恢复后,自动成为slave节点。
2、搭建哨兵集群
(1)mkdir s1 s2 s3
(2)在s1下新建sentinel.conf文件
(3)启动
redis-sentinel s1/sentinel.conf
3、RedisTemplate的哨兵模式
(1)在pom文件中引入spring-boot-starter-data-redis
(2)application.yml指定sentinel相关信息
(3)配置主从读写分离
五、分片集群
主从和哨兵可以解决高可用、高并发读的问题,但是不能解决海量数据存储和高并发写的问题。
特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点。(主从)
- master之间通过ping监测彼此监控状态(哨兵)
- 客户端请求key访问集群任意节点,最终都会转发到正确节点
1、搭建
(1)mkdir 7001 7002 7003 8001 8002 8003
(2)redis.conf文件
(3)复制文件到文件夹下,并修改
(4)启动
查看状态ps -ef|grep redis
(5)创建集群
redis-cli --cluster create --cluster-replicas 1 ip1:port1 ip2:port2 …
命令说明:
- redis-cli --cluster:集群操作命令
- create:创建集群
- –replicas 1或 --cluster-replicas 1 :指定集群中每个master的副本个数为1,此时
n = 节点总数 / (replicas + 1)
得到的就是master的数量。因此前n个是master,其他的是slave节点。
(6)测试
redis-cli -p 7001 cluster nodes
2、散列插槽
-
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上。
-
根据key的有效部分计算hash值,在对16384取余,得到的结果就是slot值。
-
数据key不是与节点绑定,而是与插槽绑定。【为什么?】
-
将同一类数据固定的保存在同一个Reids实例中,需要数据使用相同的有效数据,如key都已{typeId}为前缀
3、集群收缩
(1)添加节点
redis-cli --cluster add-node 192.168.150.101:7004 192.168.150.101:7001
(2)分 插槽
redis-cli --cluster reshard 192.168.150.101:7001
4、故障转移
master宕机发生什么?
答:首先是该实例与其他实例失去连接;然后是疑似宕机,最后是确定下线,自动提升一个slave成为新的master
5、RedisTemplate访问
(1)引入redis的starter依赖
在pom文件中引入spring-boot-starter-data-redis
(2)配置分片集群地址
(3)配置读写分离