目录一.Redis持久化RDB(1)RDB介绍(2)RDB的fork原理AOFRDB和AOF对比编辑Redis 混合持久化(aof-use-rdb-preamble yes,Redis4.0+)✅ 存储流程(核心发生在【AOF 重写】阶段)文件结构✅ 平时正常运行(非重写阶段)怎么存?✅ 重启恢复读取逻辑✅ 开启配置✅ 优缺点小结总结:二.Redis主从主从集群结构编辑搭建主从集群一、主节点 master 配置 redis.conf二、从节点 replica 配置 redis.conf三、验证主从四、哨兵 Sentinel(在主从基础上部署,推荐 3 个哨兵,奇数)五、Redis Cluster 分片集群(6 节点起步:3 主 3 从)数据同步原理(1)全量同步(2)增量同步编辑三.Redis哨兵(1)哨兵(Sentinel)的作用和工作原理(2)搭建哨兵集群Redis 哨兵集群搭建(1 主 2 从 + 3 哨兵,面试 + 实操版)Master 配置 redis.conf(192.168.1.10)步骤 1:先搭建 Redis 一主两从(哨兵依赖主从复制)步骤 2:3 台机器分别编写 sentinel.conf(哨兵配置)步骤 3:启动哨兵(3 台都执行)步骤 4:验证哨兵集群步骤 5:故障模拟测试(面试必问)核心参数面试解释坑点 & 生产注意事项(3)SpringBoot 客户端哨兵配置四.Redis分片集群(1)分片集群搭建编辑1、节点配置文件(每个节点一份,只改 port)2、启动全部 6 个 redis 实例3、创建集群(核心命令)4、验证集群连接集群(必须加 -c,自动重定向跳转槽位)5、Java 客户端连接(Lettuce/Jedis)重要考点 + 避坑(面试重点)区分:分片集群 vs 哨兵(2)散列插槽(3)集群伸缩(4)故障转移(5)RedisTemplate访问分片集群一.Redis持久化RDB(1)RDB介绍核心差别:SAVE 主线程同步阻塞;BGSAVE fork 子进程后台执行,几乎不阻塞主线程。Redis停机时会自动执行一次RDB,如果服务器突然宕机,数据就会丢失,所以可以通过设置,让Redis每隔一段固定时间,自动执行RDB。bgsave的时间应该设置多少?如果时间太长,刚好写入了数据,如果此时服务器宕机了,数据就丢失了。如果时间太短,比如1s,如果数据量比较大,1s根本忙不过来所以时间不能太长,也不能太短,一般按默认就可以了如果服务器真的宕机了,怎么办?后面还会有其他持久化方式来配合RDB(2)RDB的fork原理AOFRDB和AOF对比Redis 混合持久化(aof-use-rdb-preamble yes,Redis4.0+)一句话:不是两个独立文件,是同一个 AOF 文件,文件头部存 RDB 二进制快照,后面追加 AOF 增量写命令✅ 存储流程(核心发生在【AOF 重写】阶段)触发 AOF 重写,主进程fork子进程(写时复制)子进程:把重写瞬间内存里全部 key-value,序列化成RDB 二进制格式,写入新 AOF 文件的头部主进程:重写进行期间,新收到的写命令,同时写入两处:旧 AOF 缓冲区(正常持续落盘,保证宕机不丢)AOF 重写缓冲区(临时缓存这段时间新增命令)子进程写完 RDB 头部之后,主进程把重写缓冲区里的增量命令,以 AOF 协议格式追加到这个新文件尾部全部写完,用这个「RDB 头 + AOF 尾」的新文件,原子替换旧 AOF 文件腾讯云文件结构appendonly.aof ├─ 头部:RDB二进制快照(重写那一刻的全量数据,带RDB魔数REDIS标识) └─ 尾部:AOF文本命令(重写过程中新产生的增量写操作)✅ 平时正常运行(非重写阶段)怎么存?正常业务写请求,依然只追加 AOF 命令,和普通 AOF 一样,按appendfsync策略刷盘(everysec 常用)。 混合持久化只有 AOF 重写的时候,才会生成带 RDB 前缀的混合 AOF 文件,不是每次写都写 RDB。✅ 重启恢复读取逻辑Redis 启动,读取 AOF 文件识别到文件开头是 RDB 魔数,直接加载前面 RDB 二进制快照,快速重建全量数据(比一条条回放千万条 AOF 命令快很多)RDB 部分读完后,继续往后回放尾部 AOF 增量命令,补齐重写期间新增数据✅ 开启配置appendonly yes aof-use-rdb-preamble yes # 开启混合持久化(Redis5默认yes)✅ 优缺点小结优点:兼顾 AOF 的数据安全性 + RDB 快速加载;AOF 文件体积远小于纯 AOF缺点:混合 AOF 文件前半段是二进制,无法人工阅读编辑;Redis4.0 以下版本不能识别这种文件总结:当并发量比较大的时候,数据库扛不住,于是就需要缓存(Redis)Redis是基于内存的,读起来就比较快, 但是内存里的数据,断电会丢失,RDB就是把当前Redis里的数据,以二进制的方式,写入RDB文件里面,RDB存的是二进制的全量数据,每次把数据存到磁盘中,数据量大的话,就会很慢,Redis是执行命令的线程是单线程,不全是单线程,于是就有save和bgsave两个方法,save是让主线程去保存RDB快照,这样就会造成主线程堵塞,也没有办法去执行读写命令了,所以不推荐使用bgsave是开启一个子线程,在后台慢慢保存RDB快照,就不会阻塞 执行命令的主线程了即便是这样,保存RDB快照还是很慢,因为保存的是全量数据,而且保存的只是当前的数据快照,下一秒保存新的数据快照,不保存的话,数据又丢了,所以涉及到频率,保存RDB全量数据比较慢,不可能频繁执行,所以需要设置一个频率,比如5分钟保存一次,但是如果Redis宕机,还是会丢失这五分钟的数据,没办法解决,这就是RDB的缺点,容易丢失数据,但是恢复速度快,因为RDB存的是二进制数据,Redis重启后,直接把数据写入内存就能直接恢复。那么子线程去保存这个RDB快照的时候,主线程还能修改数据吗?能,这里涉及到并发编程的思想,copy on write就是写入式复制,当子线程去读某块内存这个数据,然后要保存到RDB文件的时候,如果主线程刚好也要修改这个数据,那就会把这个数据复制一份,然后主线程去修改这个数据备份,然后子线程去读原始数据,就能在不加锁的情况下,解决这个线程安全问题,这也是种无锁的思想,Java里也有对应的实现,比如JUC包下的一个CopyOnWriteArrayListRDB是保存数据到日志文件里来实现持久化,那反过来,能不能不保存数据,直接保存写命令?Redis宕机后直接把这些写命令全部重新执行一遍,数据也能恢复,这就是AOF的思想。之前的Mysql日志,也不是直接写到磁盘里的。所以写AOF也是先写到AOF的缓存区,然后再写入到磁盘中,所以Redis收到写命令时,先执行,然后再写入到AOF的缓存区,然后再写入操作系统的内核缓冲区page cache,然后在某个时间之内再刷入到磁盘中,具体什么时候刷入磁盘呢?这又是频率的问题,Redis提供了三个选项,在前面已经分析过了之前讲过Mysql是先写redo log 再提交事务的,这是日志先行保证持久性的思想,那AOF为什么要先执行命令再写日志呢?因为Mysql是数据库,核心目标是保证事物的ACID,保证数据的持久性,数据绝对不能丢,但是Redis是做缓存的,需要优先保证速度,先执行命令再写日志,更快,不会阻塞当前命令的执行,而且记录日志必须保证命令是有效的,写操作执行完毕,说明这个命令一定是对的,可以不检查命令是否正确,直接写入日志,代价是没来得及写日志,Redis就宕机,会丢失数据。问题又来了,如果Redis就一个key,我写入再删除,循环一百万次,其实redis里就一条数据,但是AOF文件里存了一大堆无效的命令,导致AOF文件很大,而且Redis重启后还会执行这些无效的指令,浪费大量的时间,性能很差,所以就有了AOF重写,AOF重写就是当AOF文件膨胀到一定程度的时候,Redis就会单独开一个子线程,去扫描Redis里的数据,生成对应的写命令,放入到AOF文件中,新的文件就很小了总结一下 ,RDB是全量数据快照,保存慢,所以每隔一段时间就会保存一次,容易丢数据,但是Redis重启后,数据恢复快,AOF保存Redis写命令,保存的快,不容易丢数据,但是Redis重启后,数据恢复慢又没有一种方案能兼顾RDB恢复速度快和AOF不容易丢数据的两大优点呢?混合持久化方案。做AOF重写的时候,把数据以RDB的方式写入AOF文件,命令以AOF的方式写入AOF文件,重写之后的AOF文件,前半段是RDB的二进制数据,后半段是命令,这样恢复速度快,还不容易丢命令。二.Redis主从主从集群结构搭建主从集群Redis 三种集群方案区分主从复制(基础,无自动故障转移):一主多从,写主、读从,异步复制;主挂了要手动切换Sentinel 哨兵(生产中小项目高可用):主从 + 哨兵监控,主宕机自动选新主,解决故障转移;不能扩容写性能Redis Cluster 集群(大数据量、分片):16384 个 slot 哈希分片,多主多从,可以水平扩容写下面先讲【一主一从】实操(Linux,Redis6+/7+) 环境: Master:192.168.10.20 6379 Replica:192.168.10.21 6379一、主节点 master 配置 redis.confbind 0.0.0.0 protected-mode no port 6379 requirepass Redis@123456 # 设置密码 repl-backlog-size 128mb # 复制积压缓冲区,断点续传 # 持久化(建议开RDB+AOF) save 60 1000 appendonly yes启动:redis-server redis.conf二、从节点 replica 配置 redis.confbind 0.0.0.0 protected-mode no port 6379 requirepass Redis@123456 masterauth Redis@123456 # 主库密码,必须写,否则同步失败 replicaof 192.168.10.20 6379 # 指定主节点IP端口 replica-read-only yes # 从节点默认只读启动从节点redis-server redis.conf三、验证主从登录 redis-cliredis-cli -h 192.168.10.20 -p 6379 -a Redis@123456 INFO replicationmaster 里看到role:master,replica 列表replica 里看到role:slave,master 地址、同步状态 测试:主 set key,从 get key,能拿到 = 成功。临时命令方式(重启失效,测试用)# 在从redis-cli执行 REPLICAOF 192.168.10.20 6379 CONFIG SET masterauth Redis@123456取消主从:REPLICAOF NO ONE四、哨兵 Sentinel(在主从基础上部署,推荐 3 个哨兵,奇数)sentinel.conf(3 台机器都放一份)port 26379 sentinel monitor mymaster 192.168.10.20 6379 2 # mymaster:集群名;2:quorum,至少2个哨兵判定客观下线 sentinel down-after-milliseconds mymaster 5000 # 5s不通=主观下线 sentinel failover-timeout mymaster 60000 sentinel auth-pass mymaster Redis@123456启动哨兵:redis-sentinel sentinel.conf原理:哨兵自动发现主、所有从;主宕机,哨兵投票选出新主;旧主恢复后自动变成从节点。 ⚠️ 主从复制是异步,故障切换存在极小丢写风险五、Redis Cluster 分片集群(6 节点起步:3 主 3 从)每个节点单独 redis.conf,开启 clusterport 6379 bind 0.0.0.0 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 appendonly yes6 个节点全部启动后,执行创建集群命令:redis-cli --cluster create 192.168.10.10:6379 192.168.10.11:6379 192.168.10.12:6379 192.168.10.13:6379 192.168.10.14:6379 192.168.10.15:6379 --cluster-replicas 1--cluster-replicas 1代表每个主分配 1 个从节点,3 主 3 从。黑马的视频是用一台主机开多个端口模拟的,现实情况下,公司已经搭建好了,而且是多台服务器,这里不过多赘述了数据同步原理(1)全量同步(2)增量同步repl_backlog(复制积压缓冲区,repl_baklog 是简称)本质就是一个固定大小的环形数组(环形缓冲区 circular buffer),存在 Master 的内存里增量同步逻辑(PSYNC)从节点断线重连,带上自己的replid和slave_repl_offset;master 判断:replid 一致,并且 offset 对应的数据还在环形缓冲区中 →增量同步,只补发断线期间缺失命令;如果 offset 对应的旧数据已经被环形缓冲区新数据覆盖 →只能全量同步。slave断开太久,数据如果被覆盖,只能全量同步,无法避免,那怎么优化?三.Redis哨兵(1)哨兵(Sentinel)的作用和工作原理(2)搭建哨兵集群Redis 哨兵集群搭建(1 主 2 从 + 3 哨兵,面试 + 实操版)核心原则:哨兵至少 3 个实例,奇数;主从先搭好,再部署哨兵;哨兵会自动发现从节点、其他哨兵,不用手动写从库配置Redis 环境规划(推荐 3 台机器,也可单机多进程测试) | 节点 | IP|Redis 端口 | Sentinel 端口 | 角色 | | ---- | ---- | ---- | ---- | ---- | |node1|192.168.1.10|6379|26379|Redis Master + Sentinel1| |node2|192.168.1.11|6379|26379|Redis Slave1 + Sentinel2| |node3|192.168.1.12|6379|26379|Redis Slave2 + Sentinel3|Master 配置 redis.conf(192.168.1.10)步骤 1:先搭建 Redis 一主两从(哨兵依赖主从复制)bind 0.0.0.0 protected-mode no port 6379 daemonize yes requirepass 123456 masterauth 123456 # 持久化(建议开启混合持久化) appendonly yes rdb-enabled yes aof-use-rdb-preamble yes两个 Slave 配置 redis.conf(node2、node3)bind 0.0.0.0 protected-mode no port 6379 daemonize yes requirepass 123456 masterauth 123456 # 指定主节点 replicaof 192.168.1.10 6379启动 3 个 redis,验证主从:redis-cli -a 123456 info replication,确认两个从库连上 master。步骤 2:3 台机器分别编写 sentinel.conf(哨兵配置)三台哨兵配置基本一致,只改端口(同机多哨兵才需要改端口,跨机默认 26379)port 26379 daemonize yes protected-mode no pidfile /var/run/redis-sentinel.pid logfile "/var/log/sentinel.log" dir /tmp 核心配置:监控主节点 mymaster(名字自定义) IP 端口 法定人数quorum=2 quorum=2:至少2个哨兵主观认为master下线,才判定客观下线 sentinel monitor mymaster 192.168.1.10 6379 2 多久ping不通,主观判定下线(毫秒,5s) sentinel down-after-milliseconds mymaster 5000 故障转移超时时间,60s内没完成切换则重试 sentinel failover-timeout mymaster 60000 故障转移时,同时向新master同步的从节点数量,生产建议1,避免网络压力 sentinel parallel-syncs mymaster 1 Redis密码,主从统一密码必须配置 sentinel auth-pass mymaster 123456⚠️ 重点:哨兵启动后会自动修改这个配置文件,写入新的 master、其他哨兵、从节点信息;不要手动编辑运行中的 sentinel.conf!步骤 3:启动哨兵(3 台都执行)两种启动方式等价:# 方式1 redis-sentinel /etc/sentinel.conf # 方式2,用redis-server加--sentinel参数 redis-server /etc/sentinel.conf --sentinel步骤 4:验证哨兵集群连接任意哨兵查看信息redis-cli -p 26379 # 查看哨兵状态 INFO sentinel # 查看主节点信息 SENTINEL master mymaster # 查看所有从节点(自动发现) SENTINEL replicas mymaster # 查看其他哨兵(自动发现) SENTINEL sentinels mymaster输出看到sentinel_masters:1,3 个哨兵实例全部识别,代表集群成功。步骤 5:故障模拟测试(面试必问)停掉 master 节点 redis:redis-cli -a 123456 shutdown观察哨兵日志:哨兵协商,选举新 master,自动修改剩余从库的replicaof指向新主执行INFO replication验证:一台从晋升为主,另一台跟随新主旧 master 恢复上线,会自动变成新 master 的从节点核心参数面试解释quorum:法定票数,只是判定客观下线;故障转移的选举,需要超过半数哨兵同意(3 哨兵至少 2 票同意才能切换)<blockquote>quorum=2,3 个哨兵,判定下线需要 2 个认为宕机;故障转移选举需要≥2 个哨兵投票成功。down-after-milliseconds:主观下线(SDOWN),单个哨兵 ping 不通标记 SDOWN;多个 SDOWN 达到 quorum → 客观下线 ODOWN,才开始故障转移。parallel-syncs:切换主库后,多少个从库同时同步新 master,生产设 1,防止主库网络打满。坑点 & 生产注意事项防火墙:26379 端口放行,哨兵之间、哨兵和 redis 主从之间网络互通不要用 1 个哨兵,单点故障;2 个哨兵也不行,网络分区会出现脑裂;推荐≥3 奇数哨兵,跨机器部署哨兵只做高可用故障自动切换,不做数据分片(这是和 Redis Cluster 的本质区别)异步复制,故障切换会有短暂丢数据风险,可以配置min-replicas-to-write减少风险客户端不直接连主从 IP,连接哨兵集群,向哨兵询问当前 master 地址。(3)SpringBoot 客户端哨兵配置示例:四.Redis分片集群(1)分片集群搭建Redis 分片集群(Redis Cluster)搭建原理:一共16384 个哈希槽,key 经过 CRC16 算法算槽号,分到不同主节点;最小高可用推荐3 主 3 从(6 个实例),至少要有 3 个主节点才能搭建集群。 实验环境:单机开 6 个 redis 进程,端口:7000~70051、节点配置文件(每个节点一份,只改 port)新建redis-7000.conf,7001~7005 同理,只替换端口port 7000 # bind 0.0.0.0 云服务器要放开 daemonize yes cluster-enabled yes # 开启集群分片模式 cluster-config-file nodes-7000.conf # 集群节点信息文件,自动生成,不要手动改 cluster-node-timeout 5000 # 节点失联判定时间ms appendonly yes # AOF持久化,防止丢数据 # 跨机器部署必须加下面两个 # cluster-announce-ip 你的机器内网ip # cluster-announce-port 70002、启动全部 6 个 redis 实例redis-server redis-7000.conf redis-server redis-7001.conf redis-server redis-7002.conf redis-server redis-7003.conf redis-server redis-7004.conf redis-server redis-7005.conf检查进程:ps -ef | grep redis3、创建集群(核心命令)--cluster-replicas 1含义:每个主节点分配 1 个从节点,3 主自动配 3 从redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1回车后,会打印分配方案,输入yes确认,自动分配 16384 槽位,建立主从关系。4、验证集群连接集群(必须加-c,自动重定向跳转槽位)redis-cli -c -p 7000# 查看集群整体信息 cluster info # 查看所有节点、主从、槽分配 cluster nodes看到cluster_state:ok代表集群正常。5、Java 客户端连接(Lettuce/Jedis)连接任意节点即可,客户端会自动拉取 16384 槽位映射# SpringBoot Redis集群配置 spring: redis: cluster: nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002重要考点 + 避坑(面试重点)哈希槽 16384 个,不是按 key 数量均分;只有主节点持有槽,从节点只做副本、不分配槽,写操作只能在主节点多 key 命令(mget、mset)不能跨槽执行,报错。如果业务必须放一块,用哈希标签{user}id1{user}id2,只拿大括号内容算 hash,放到同一个槽生产建议:cluster-require-full-coverage no,某个分片故障,其余分片还能正常对外提供服务故障转移:主节点宕机,集群自动把它的从节点升级为主;原主重启后变成新主的从节点扩容缩容:添加新节点 → 迁移哈希槽redis-cli --cluster reshard删除节点:先迁移槽,再删除节点区分:分片集群 vs 哨兵Sentinel 哨兵:主从高可用,不分片,所有数据都在一套主从,不能水平扩容存储Redis Cluster 分片集群:既做主从高可用,又做数据分片,水平扩容,数据分散在多个主节点(2)散列插槽(3)集群伸缩(4)故障转移(5)RedisTemplate访问分片集群
目录一.Redis持久化RDB(1)RDB介绍(2)RDB的fork原理AOFRDB和AOF对比编辑Redis 混合持久化(aof-use-rdb-preamble yes,Redis4.0+)✅ 存储流程(核心发生在【AOF 重写】阶段)文件结构✅ 平时正常运行(非重写阶段)怎么存?✅ 重启恢复读取逻辑✅ 开启配置✅ 优缺点小结总结:二.Redis主从主从集群结构编辑搭建主从集群一、主节点 master 配置 redis.conf二、从节点 replica 配置 redis.conf三、验证主从四、哨兵 Sentinel(在主从基础上部署,推荐 3 个哨兵,奇数)五、Redis Cluster 分片集群(6 节点起步:3 主 3 从)数据同步原理(1)全量同步(2)增量同步编辑三.Redis哨兵(1)哨兵(Sentinel)的作用和工作原理(2)搭建哨兵集群Redis 哨兵集群搭建(1 主 2 从 + 3 哨兵,面试 + 实操版)Master 配置 redis.conf(192.168.1.10)步骤 1:先搭建 Redis 一主两从(哨兵依赖主从复制)步骤 2:3 台机器分别编写 sentinel.conf(哨兵配置)步骤 3:启动哨兵(3 台都执行)步骤 4:验证哨兵集群步骤 5:故障模拟测试(面试必问)核心参数面试解释坑点 & 生产注意事项(3)SpringBoot 客户端哨兵配置四.Redis分片集群(1)分片集群搭建编辑1、节点配置文件(每个节点一份,只改 port)2、启动全部 6 个 redis 实例3、创建集群(核心命令)4、验证集群连接集群(必须加 -c,自动重定向跳转槽位)5、Java 客户端连接(Lettuce/Jedis)重要考点 + 避坑(面试重点)区分:分片集群 vs 哨兵(2)散列插槽(3)集群伸缩(4)故障转移(5)RedisTemplate访问分片集群一.Redis持久化RDB(1)RDB介绍核心差别:SAVE 主线程同步阻塞;BGSAVE fork 子进程后台执行,几乎不阻塞主线程。Redis停机时会自动执行一次RDB,如果服务器突然宕机,数据就会丢失,所以可以通过设置,让Redis每隔一段固定时间,自动执行RDB。bgsave的时间应该设置多少?如果时间太长,刚好写入了数据,如果此时服务器宕机了,数据就丢失了。如果时间太短,比如1s,如果数据量比较大,1s根本忙不过来所以时间不能太长,也不能太短,一般按默认就可以了如果服务器真的宕机了,怎么办?后面还会有其他持久化方式来配合RDB(2)RDB的fork原理AOFRDB和AOF对比Redis 混合持久化(aof-use-rdb-preamble yes,Redis4.0+)一句话:不是两个独立文件,是同一个 AOF 文件,文件头部存 RDB 二进制快照,后面追加 AOF 增量写命令✅ 存储流程(核心发生在【AOF 重写】阶段)触发 AOF 重写,主进程fork子进程(写时复制)子进程:把重写瞬间内存里全部 key-value,序列化成RDB 二进制格式,写入新 AOF 文件的头部主进程:重写进行期间,新收到的写命令,同时写入两处:旧 AOF 缓冲区(正常持续落盘,保证宕机不丢)AOF 重写缓冲区(临时缓存这段时间新增命令)子进程写完 RDB 头部之后,主进程把重写缓冲区里的增量命令,以 AOF 协议格式追加到这个新文件尾部全部写完,用这个「RDB 头 + AOF 尾」的新文件,原子替换旧 AOF 文件腾讯云文件结构appendonly.aof ├─ 头部:RDB二进制快照(重写那一刻的全量数据,带RDB魔数REDIS标识) └─ 尾部:AOF文本命令(重写过程中新产生的增量写操作)✅ 平时正常运行(非重写阶段)怎么存?正常业务写请求,依然只追加 AOF 命令,和普通 AOF 一样,按appendfsync策略刷盘(everysec 常用)。 混合持久化只有 AOF 重写的时候,才会生成带 RDB 前缀的混合 AOF 文件,不是每次写都写 RDB。✅ 重启恢复读取逻辑Redis 启动,读取 AOF 文件识别到文件开头是 RDB 魔数,直接加载前面 RDB 二进制快照,快速重建全量数据(比一条条回放千万条 AOF 命令快很多)RDB 部分读完后,继续往后回放尾部 AOF 增量命令,补齐重写期间新增数据✅ 开启配置appendonly yes aof-use-rdb-preamble yes # 开启混合持久化(Redis5默认yes)✅ 优缺点小结优点:兼顾 AOF 的数据安全性 + RDB 快速加载;AOF 文件体积远小于纯 AOF缺点:混合 AOF 文件前半段是二进制,无法人工阅读编辑;Redis4.0 以下版本不能识别这种文件总结:当并发量比较大的时候,数据库扛不住,于是就需要缓存(Redis)Redis是基于内存的,读起来就比较快, 但是内存里的数据,断电会丢失,RDB就是把当前Redis里的数据,以二进制的方式,写入RDB文件里面,RDB存的是二进制的全量数据,每次把数据存到磁盘中,数据量大的话,就会很慢,Redis是执行命令的线程是单线程,不全是单线程,于是就有save和bgsave两个方法,save是让主线程去保存RDB快照,这样就会造成主线程堵塞,也没有办法去执行读写命令了,所以不推荐使用bgsave是开启一个子线程,在后台慢慢保存RDB快照,就不会阻塞 执行命令的主线程了即便是这样,保存RDB快照还是很慢,因为保存的是全量数据,而且保存的只是当前的数据快照,下一秒保存新的数据快照,不保存的话,数据又丢了,所以涉及到频率,保存RDB全量数据比较慢,不可能频繁执行,所以需要设置一个频率,比如5分钟保存一次,但是如果Redis宕机,还是会丢失这五分钟的数据,没办法解决,这就是RDB的缺点,容易丢失数据,但是恢复速度快,因为RDB存的是二进制数据,Redis重启后,直接把数据写入内存就能直接恢复。那么子线程去保存这个RDB快照的时候,主线程还能修改数据吗?能,这里涉及到并发编程的思想,copy on write就是写入式复制,当子线程去读某块内存这个数据,然后要保存到RDB文件的时候,如果主线程刚好也要修改这个数据,那就会把这个数据复制一份,然后主线程去修改这个数据备份,然后子线程去读原始数据,就能在不加锁的情况下,解决这个线程安全问题,这也是种无锁的思想,Java里也有对应的实现,比如JUC包下的一个CopyOnWriteArrayListRDB是保存数据到日志文件里来实现持久化,那反过来,能不能不保存数据,直接保存写命令?Redis宕机后直接把这些写命令全部重新执行一遍,数据也能恢复,这就是AOF的思想。之前的Mysql日志,也不是直接写到磁盘里的。所以写AOF也是先写到AOF的缓存区,然后再写入到磁盘中,所以Redis收到写命令时,先执行,然后再写入到AOF的缓存区,然后再写入操作系统的内核缓冲区page cache,然后在某个时间之内再刷入到磁盘中,具体什么时候刷入磁盘呢?这又是频率的问题,Redis提供了三个选项,在前面已经分析过了之前讲过Mysql是先写redo log 再提交事务的,这是日志先行保证持久性的思想,那AOF为什么要先执行命令再写日志呢?因为Mysql是数据库,核心目标是保证事物的ACID,保证数据的持久性,数据绝对不能丢,但是Redis是做缓存的,需要优先保证速度,先执行命令再写日志,更快,不会阻塞当前命令的执行,而且记录日志必须保证命令是有效的,写操作执行完毕,说明这个命令一定是对的,可以不检查命令是否正确,直接写入日志,代价是没来得及写日志,Redis就宕机,会丢失数据。问题又来了,如果Redis就一个key,我写入再删除,循环一百万次,其实redis里就一条数据,但是AOF文件里存了一大堆无效的命令,导致AOF文件很大,而且Redis重启后还会执行这些无效的指令,浪费大量的时间,性能很差,所以就有了AOF重写,AOF重写就是当AOF文件膨胀到一定程度的时候,Redis就会单独开一个子线程,去扫描Redis里的数据,生成对应的写命令,放入到AOF文件中,新的文件就很小了总结一下 ,RDB是全量数据快照,保存慢,所以每隔一段时间就会保存一次,容易丢数据,但是Redis重启后,数据恢复快,AOF保存Redis写命令,保存的快,不容易丢数据,但是Redis重启后,数据恢复慢又没有一种方案能兼顾RDB恢复速度快和AOF不容易丢数据的两大优点呢?混合持久化方案。做AOF重写的时候,把数据以RDB的方式写入AOF文件,命令以AOF的方式写入AOF文件,重写之后的AOF文件,前半段是RDB的二进制数据,后半段是命令,这样恢复速度快,还不容易丢命令。二.Redis主从主从集群结构搭建主从集群Redis 三种集群方案区分主从复制(基础,无自动故障转移):一主多从,写主、读从,异步复制;主挂了要手动切换Sentinel 哨兵(生产中小项目高可用):主从 + 哨兵监控,主宕机自动选新主,解决故障转移;不能扩容写性能Redis Cluster 集群(大数据量、分片):16384 个 slot 哈希分片,多主多从,可以水平扩容写下面先讲【一主一从】实操(Linux,Redis6+/7+) 环境: Master:192.168.10.20 6379 Replica:192.168.10.21 6379一、主节点 master 配置 redis.confbind 0.0.0.0 protected-mode no port 6379 requirepass Redis@123456 # 设置密码 repl-backlog-size 128mb # 复制积压缓冲区,断点续传 # 持久化(建议开RDB+AOF) save 60 1000 appendonly yes启动:redis-server redis.conf二、从节点 replica 配置 redis.confbind 0.0.0.0 protected-mode no port 6379 requirepass Redis@123456 masterauth Redis@123456 # 主库密码,必须写,否则同步失败 replicaof 192.168.10.20 6379 # 指定主节点IP端口 replica-read-only yes # 从节点默认只读启动从节点redis-server redis.conf三、验证主从登录 redis-cliredis-cli -h 192.168.10.20 -p 6379 -a Redis@123456 INFO replicationmaster 里看到role:master,replica 列表replica 里看到role:slave,master 地址、同步状态 测试:主 set key,从 get key,能拿到 = 成功。临时命令方式(重启失效,测试用)# 在从redis-cli执行 REPLICAOF 192.168.10.20 6379 CONFIG SET masterauth Redis@123456取消主从:REPLICAOF NO ONE四、哨兵 Sentinel(在主从基础上部署,推荐 3 个哨兵,奇数)sentinel.conf(3 台机器都放一份)port 26379 sentinel monitor mymaster 192.168.10.20 6379 2 # mymaster:集群名;2:quorum,至少2个哨兵判定客观下线 sentinel down-after-milliseconds mymaster 5000 # 5s不通=主观下线 sentinel failover-timeout mymaster 60000 sentinel auth-pass mymaster Redis@123456启动哨兵:redis-sentinel sentinel.conf原理:哨兵自动发现主、所有从;主宕机,哨兵投票选出新主;旧主恢复后自动变成从节点。 ⚠️ 主从复制是异步,故障切换存在极小丢写风险五、Redis Cluster 分片集群(6 节点起步:3 主 3 从)每个节点单独 redis.conf,开启 clusterport 6379 bind 0.0.0.0 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 appendonly yes6 个节点全部启动后,执行创建集群命令:redis-cli --cluster create 192.168.10.10:6379 192.168.10.11:6379 192.168.10.12:6379 192.168.10.13:6379 192.168.10.14:6379 192.168.10.15:6379 --cluster-replicas 1--cluster-replicas 1代表每个主分配 1 个从节点,3 主 3 从。黑马的视频是用一台主机开多个端口模拟的,现实情况下,公司已经搭建好了,而且是多台服务器,这里不过多赘述了数据同步原理(1)全量同步(2)增量同步repl_backlog(复制积压缓冲区,repl_baklog 是简称)本质就是一个固定大小的环形数组(环形缓冲区 circular buffer),存在 Master 的内存里增量同步逻辑(PSYNC)从节点断线重连,带上自己的replid和slave_repl_offset;master 判断:replid 一致,并且 offset 对应的数据还在环形缓冲区中 →增量同步,只补发断线期间缺失命令;如果 offset 对应的旧数据已经被环形缓冲区新数据覆盖 →只能全量同步。slave断开太久,数据如果被覆盖,只能全量同步,无法避免,那怎么优化?三.Redis哨兵(1)哨兵(Sentinel)的作用和工作原理(2)搭建哨兵集群Redis 哨兵集群搭建(1 主 2 从 + 3 哨兵,面试 + 实操版)核心原则:哨兵至少 3 个实例,奇数;主从先搭好,再部署哨兵;哨兵会自动发现从节点、其他哨兵,不用手动写从库配置Redis 环境规划(推荐 3 台机器,也可单机多进程测试) | 节点 | IP|Redis 端口 | Sentinel 端口 | 角色 | | ---- | ---- | ---- | ---- | ---- | |node1|192.168.1.10|6379|26379|Redis Master + Sentinel1| |node2|192.168.1.11|6379|26379|Redis Slave1 + Sentinel2| |node3|192.168.1.12|6379|26379|Redis Slave2 + Sentinel3|Master 配置 redis.conf(192.168.1.10)步骤 1:先搭建 Redis 一主两从(哨兵依赖主从复制)bind 0.0.0.0 protected-mode no port 6379 daemonize yes requirepass 123456 masterauth 123456 # 持久化(建议开启混合持久化) appendonly yes rdb-enabled yes aof-use-rdb-preamble yes两个 Slave 配置 redis.conf(node2、node3)bind 0.0.0.0 protected-mode no port 6379 daemonize yes requirepass 123456 masterauth 123456 # 指定主节点 replicaof 192.168.1.10 6379启动 3 个 redis,验证主从:redis-cli -a 123456 info replication,确认两个从库连上 master。步骤 2:3 台机器分别编写 sentinel.conf(哨兵配置)三台哨兵配置基本一致,只改端口(同机多哨兵才需要改端口,跨机默认 26379)port 26379 daemonize yes protected-mode no pidfile /var/run/redis-sentinel.pid logfile "/var/log/sentinel.log" dir /tmp 核心配置:监控主节点 mymaster(名字自定义) IP 端口 法定人数quorum=2 quorum=2:至少2个哨兵主观认为master下线,才判定客观下线 sentinel monitor mymaster 192.168.1.10 6379 2 多久ping不通,主观判定下线(毫秒,5s) sentinel down-after-milliseconds mymaster 5000 故障转移超时时间,60s内没完成切换则重试 sentinel failover-timeout mymaster 60000 故障转移时,同时向新master同步的从节点数量,生产建议1,避免网络压力 sentinel parallel-syncs mymaster 1 Redis密码,主从统一密码必须配置 sentinel auth-pass mymaster 123456⚠️ 重点:哨兵启动后会自动修改这个配置文件,写入新的 master、其他哨兵、从节点信息;不要手动编辑运行中的 sentinel.conf!步骤 3:启动哨兵(3 台都执行)两种启动方式等价:# 方式1 redis-sentinel /etc/sentinel.conf # 方式2,用redis-server加--sentinel参数 redis-server /etc/sentinel.conf --sentinel步骤 4:验证哨兵集群连接任意哨兵查看信息redis-cli -p 26379 # 查看哨兵状态 INFO sentinel # 查看主节点信息 SENTINEL master mymaster # 查看所有从节点(自动发现) SENTINEL replicas mymaster # 查看其他哨兵(自动发现) SENTINEL sentinels mymaster输出看到sentinel_masters:1,3 个哨兵实例全部识别,代表集群成功。步骤 5:故障模拟测试(面试必问)停掉 master 节点 redis:redis-cli -a 123456 shutdown观察哨兵日志:哨兵协商,选举新 master,自动修改剩余从库的replicaof指向新主执行INFO replication验证:一台从晋升为主,另一台跟随新主旧 master 恢复上线,会自动变成新 master 的从节点核心参数面试解释quorum:法定票数,只是判定客观下线;故障转移的选举,需要超过半数哨兵同意(3 哨兵至少 2 票同意才能切换)<blockquote>quorum=2,3 个哨兵,判定下线需要 2 个认为宕机;故障转移选举需要≥2 个哨兵投票成功。down-after-milliseconds:主观下线(SDOWN),单个哨兵 ping 不通标记 SDOWN;多个 SDOWN 达到 quorum → 客观下线 ODOWN,才开始故障转移。parallel-syncs:切换主库后,多少个从库同时同步新 master,生产设 1,防止主库网络打满。坑点 & 生产注意事项防火墙:26379 端口放行,哨兵之间、哨兵和 redis 主从之间网络互通不要用 1 个哨兵,单点故障;2 个哨兵也不行,网络分区会出现脑裂;推荐≥3 奇数哨兵,跨机器部署哨兵只做高可用故障自动切换,不做数据分片(这是和 Redis Cluster 的本质区别)异步复制,故障切换会有短暂丢数据风险,可以配置min-replicas-to-write减少风险客户端不直接连主从 IP,连接哨兵集群,向哨兵询问当前 master 地址。(3)SpringBoot 客户端哨兵配置示例:四.Redis分片集群(1)分片集群搭建Redis 分片集群(Redis Cluster)搭建原理:一共16384 个哈希槽,key 经过 CRC16 算法算槽号,分到不同主节点;最小高可用推荐3 主 3 从(6 个实例),至少要有 3 个主节点才能搭建集群。 实验环境:单机开 6 个 redis 进程,端口:7000~70051、节点配置文件(每个节点一份,只改 port)新建redis-7000.conf,7001~7005 同理,只替换端口port 7000 # bind 0.0.0.0 云服务器要放开 daemonize yes cluster-enabled yes # 开启集群分片模式 cluster-config-file nodes-7000.conf # 集群节点信息文件,自动生成,不要手动改 cluster-node-timeout 5000 # 节点失联判定时间ms appendonly yes # AOF持久化,防止丢数据 # 跨机器部署必须加下面两个 # cluster-announce-ip 你的机器内网ip # cluster-announce-port 70002、启动全部 6 个 redis 实例redis-server redis-7000.conf redis-server redis-7001.conf redis-server redis-7002.conf redis-server redis-7003.conf redis-server redis-7004.conf redis-server redis-7005.conf检查进程:ps -ef | grep redis3、创建集群(核心命令)--cluster-replicas 1含义:每个主节点分配 1 个从节点,3 主自动配 3 从redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1回车后,会打印分配方案,输入yes确认,自动分配 16384 槽位,建立主从关系。4、验证集群连接集群(必须加-c,自动重定向跳转槽位)redis-cli -c -p 7000# 查看集群整体信息 cluster info # 查看所有节点、主从、槽分配 cluster nodes看到cluster_state:ok代表集群正常。5、Java 客户端连接(Lettuce/Jedis)连接任意节点即可,客户端会自动拉取 16384 槽位映射# SpringBoot Redis集群配置 spring: redis: cluster: nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002重要考点 + 避坑(面试重点)哈希槽 16384 个,不是按 key 数量均分;只有主节点持有槽,从节点只做副本、不分配槽,写操作只能在主节点多 key 命令(mget、mset)不能跨槽执行,报错。如果业务必须放一块,用哈希标签{user}id1{user}id2,只拿大括号内容算 hash,放到同一个槽生产建议:cluster-require-full-coverage no,某个分片故障,其余分片还能正常对外提供服务故障转移:主节点宕机,集群自动把它的从节点升级为主;原主重启后变成新主的从节点扩容缩容:添加新节点 → 迁移哈希槽redis-cli --cluster reshard删除节点:先迁移槽,再删除节点区分:分片集群 vs 哨兵Sentinel 哨兵:主从高可用,不分片,所有数据都在一套主从,不能水平扩容存储Redis Cluster 分片集群:既做主从高可用,又做数据分片,水平扩容,数据分散在多个主节点(2)散列插槽(3)集群伸缩(4)故障转移(5)RedisTemplate访问分片集群