一、Redis 性能压测脚本介绍
Redis 的所有数据保存在内存中,读写性能强悍,但内存断电即丢失。因此在实际项目中,需要针对应用场景对 Redis 性能进行估算,在数据安全性与读写性能之间找到平衡点。
Redis 提供了压测脚本redis-benchmark,可对 Redis 进行快速基准测试。
# 20个线程,100W个请求,测试redis的set指令(写数据) redis-benchmark -a 123qweasd -t set -n 1000000 -c 20redis-benchmark更多参数,使⽤redis-benchmark --help指令查看
二、Redis 数据持久化机制详解
1. 整体介绍
Redis 提供多种持久化策略,大体可组合为以下几种:
- 无持久化:完全关闭数据持久化,不保证数据安全,相当于将 Redis 完全当作缓存使用。
- RDB(Redis Database):按照一定时间间隔保存 Redis 所有数据快照。
- AOF(Append Only File):记录 Redis 收到的每一次写操作,通过操作重演的方式恢复数据。
- RDB + AOF:同时保存 Redis 的数据和操作。
RDB 优缺点:
- 优点:RDB文件紧凑,适合定期备份;RDB快照非常适合灾难恢复;RDB备份时主线程只需启动子线程,对主线程 IO 性能几乎没有影响;大数据量重启时比 AOF 快很多。
- 缺点:不能实时备份,总会有数据丢失的可能;fork 子线程时需要克隆内存数据,数据量过大或 CPU 性能不佳时,容易造成 Redis 短暂服务停顿。
AOF 优缺点:
- 优点:默认每秒写入一次,服务崩溃最多损失一秒操作;只追加不改写,不会出现记录不完整;文件过大时自动切换新日志文件;记录方式简单易懂,可手动调整日志(如误执行 FLUSHALL 后删除最后一条指令即可恢复)。
- 缺点:同样数据集下 AOF 文件通常比 RDB 更大;写操作频繁时,AOF 备份性能通常比 RDB 慢。
整体使用建议:
- 仅当缓存使用:直接关闭持久化。
- 关注数据安全、可接受少量数据损失:使用 RDB 策略,性能较高。
- 不建议单独使用 AOF;RDB 配合 AOF 可让数据恢复更快。
2. RDB 详解
RDB 能干什么:在指定时间间隔备份当前时间点内存中的全部数据集,保存到磁盘文件(通常是 dump.rdb)。恢复时将快照文件直接读回内存。由于存的是全量数据,甚至可以直接用 RDB 文件传递数据(如同版本间同步)。
相关重要配置:
- save 策略(核心配置):默认规则为 3600 秒内至少 1 次变更、300 秒内至少 100 次变更、60 秒内至少 10000 次变更时触发保存。例:save 3600 1 300 100 60 10000
- dir:文件目录。
- dbfilename:文件名,默认 dump.rdb。
- rdbcompression:是否启用 RDB 压缩,默认 yes;不想消耗 CPU 可设为 no。
- stop-writes-on-bgsave-error:默认 yes;设为 no 表示不在乎数据不一致,快照写入失败时仍接受新写入。
- rdbchecksum:默认 yes。在存储快照后,还可以让redis使⽤CRC64算法来进⾏数据校验,但是这 样做会增加⼤约10%的性能消耗。如果希望获得最⼤的性能提升,可以关闭此功能。
何时触发 RDB 备份:
- 到达配置文件中默认的快照配置时自动触发。
- 手动执行
save或bgsave指令触发。save 会阻塞主线程;bgsave 不阻塞主线程,但 fork 子线程会占用更多内存和 CPU。 - 主从复制时会触发 RDB 备份。
可使用LASTSAVE指令查看最后一次成功执行快照的时间(毫秒级 LONG 数字),Linux 中可用date -d @{timestamp}格式化。
3. AOF 详解
AOF 能干什么:以日志形式记录每个写操作(读操作不记录),只允许追加文件,不允许改写文件。
相关重要配置:
- appendonly:是否开启 AOF,默认不开启。
- appendfilename:文件名称。Redis 7 中调整为三个文件:base.rdb(二进制数据文件)、incr.aof(增量操作日志)、manifest(记录文件信息的元文件)。拆分后便于分别恢复文件,也便于控制 AOF 文件大小。
- appendfsync:同步方式。默认 everysec(每秒记录一次);no 表示不记录(交由操作系统刷盘);always 记录每次操作,数据更安全但性能较低。
- appenddirname:AOF 文件目录,实际目录为 {dir}+{appenddirname}。例:
- auto-aof-rewrite-percentage,auto-aof-rewrite-min-size:文件重写触发策略,默认每个文件 64M,写到 100% 时进行一次重写。Redis 会定期优化重写,如将多个 INCR 合并成一个 SET。也可通过
BGREWRITEAOF手动触发。 - no-appendfsync-on-rewrite:AOF 重写期间是否同步。
AOF 文件内容解析:AOF 增量文件按 Redis 协议记录每次操作。例如set k1 v1指令,*3表示由三个部分组成,$3 set表示三个字符长度的 set 组成第一部分。
[root@192-168-65-214 myredis]# redis-cli -a 123qweasd Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> set k2 v2 OKAOF 日志恢复:若 AOF 日志指令记录不完整(如手动编辑 incr.aof 文件末尾添加文字),Redis 重启会失败。需先修复日志文件再启动:
redis-check-aof --fix appendonly.aof.1.incr.aof修复过程实际上是将最后一条不完整的指令删除。RDB 文件也提供redis-check-rdb修复指令,但由于 RDB 是二进制压缩文件,一般不太可能被篡改,使用较少。
4. 混合持久化策略
RDB 和 AOF 各有优劣,Redis 支持同时开启两种持久化策略。配置参数:
aof-use-rdb-preamble yes同时开启时,Redis 恢复数据会优先从 AOF 文件恢复,因为 AOF 数据集通常比 RDB 更完整,且 AOF 已包含 RDB 和 AOF 两种格式,恢复效率较高。但仍建议保留 RDB 备份并定期备份,作为数据安全的后手。注意:持久化策略只能保证单机数据安全,若磁盘损坏则无法保证,需要集群化方案。
三、Redis 主从复制 Replica 机制详解
1. Replica作用
主从复制:当 Master 数据有变化时,自动将新数据异步同步到其他 Slave 中。最典型作用:
- 读写分离:Master 以写为主,Slave 以读为主。
- 数据备份 + 容灾恢复。
2. 如何配置 Replica
核心原则:配从不配主。相关核心操作:
REPLICAOF host port | NO ONE:一般配置到 redis.conf 中。SLAVEOF host port | NO ONE:运行期间修改 slave 节点信息;若已是某主库的从库,会停止与原 master 的同步关系。
3. 如何确定主从状态?从库可以写数据吗?
通过info replication查看主从状态。Master 节点重点观察slave0的state状态(应为 online)和master_repl_offset偏移量变化;
Slave 节点重点观察master_link_status(应为 up)。
默认情况下,从库是只读的,不允许写入数据,否则会造成数据不一致。写入会报错:READONLY You can't write against a read only replica.
#redis.conf中配置了slave的默认权限 replica-read-only yes。对于slave从节点,虽然禁止了对数据的写操作,但是并没有禁止CONFIG、DEBUG等管理指令,这些指令如果和主节点不一致,还是容易造成数据不一致。如果为了安全起见,可以使用rename-command方法屏蔽这些危险的指令。
例如在redis.conf配置文件中增加配置 rename-command CONFIG "" 。就可以屏蔽掉slave上的CONFIG指令。
很多企业在维护Redis时,都会通过rename 直接禁用keys , flushdb, flushall等这一类危险的指令。
4、如果Slave上已经有数据了,同步时会如何处理?
当解除主从关系后,从节点新数据更新后不变。重新建立主从关系后,由于同步需要时间,短时间内会出现主从数据不同步问题,此时从节点数据为当前最新数据。当同步完成后从节点数据会被覆盖与主节点数据一致,即slave节点数据被master覆盖。
5. 主从复制工作流程
主从复制是异步的,但可配置 master 在未连接足够数量 replica 时停止接受写入;replica 可在复制链接短暂断开时执行部分重新同步;复制是自动的,网络分区后 replica 会自动重连 master 并重新同步。
1》 Slave启动后,向master发送一个sync请求。等待建立成功后,slave会删除掉自己的数据日志文件,等待主节点同步。
2》master接收到slave的sync请求后,会触发一次RDB全量备份,同时收集所有接收到的修改数据的指令。然后master将RDB和操作指令全量同步给slave。完成第一次全量同步。
3》主从关系建立后,master会定期向slave发送心跳包,确认slave的状态。心跳发送的间隔通过参数repl-ping-replica-period指定。默认10秒。
4》只要slave定期向master回复心跳请求,master就会持续将后续收集到的修改数据的指令传递给slave。同时,master会记录offset,即已经同步给slave的消息偏移量。
5》如果slave短暂不回复master的心跳请求,master就会停止向slave同步数据。直到slave重新上线后,master从offset开始,继续向slave同步数据。
6. 主从复制的缺点
主从复制是后续哨兵集群和 Redis 集群的基础,三种方案层层递进。主从复制本身不具备自动故障转移能力,当 master 宕机时需要人工干预。
1》复制延时,信号衰减: 所有写操作都是先在master上操作,然后再同步到slave,所以数据同步一定会有延迟。当系统繁忙,或者slave数量增加时,这个延迟会更加严重。
2》master高可用问题: 如果master挂了,slave节点是不会自动切换master的,只能等待人工干预,重启master服务,或者调整主从关系,将一个slave切换成master,同时将其他slave的主节点调整为新的master。
后续的哨兵集群,就相当于做这个人工干预的工作。当检测到master挂了之后,自动从slave中选择一个节点,切换成master。
3》从数据安全性的角度,主从复制牺牲了服务高可用,但是增加了数据安全。
四、Redis 哨兵集群 Sentinel 机制详解
1. Sentinel作用
Redis的Sentinel不负责数据读写,主要就是给Redis的Replica主从复制提供高可用功能。主要作用有四个:
- 主从监控:监控主从Redis运行是否正常
- 消息通知:将故障转移的结果发送给客户端
- 故障转移:如果master异常,则会进行主从切换。将其中一个slave切换成为master。
- 配置中心:客户端通过连接哨兵可以获取当前Redis服务的master地址
Sentinel 用于监控 master 状态,在 master 宕机时自动将从节点切换为新的 master,实现自动故障恢复。
2. Sentinel 核心配置
最核心的配置是 sentinel.conf 中的:
sentinel monitor <master-name> <ip> <redis-port> <quorum>其中 quorum 是最抽象的参数,需要理解 Sentinel 的工作原理才能明白其含义。
3. 解析 Sentinel 工作原理
第一步:如何发现 master 宕机。涉及两个概念:
- S_DOWN(主观下线):每个 Sentinel 不断向 master 发送心跳,若超过
sentinel down-after-milliseconds(默认 30 秒)未收到响应,则主观认为 master 下线。 - O_DOWN(客观下线):为防止网络抖动误判,Sentinel 之间互相沟通,当超过 quorum 个 Sentinel 节点都认为 master 出现 S_DOWN 后,才标记为 O_DOWN,此时才真正确定宕机并开始故障切换。
配置 Sentinel 集群时通常搭建奇数个节点,将 quorum 配置为过半数,最大化保证可用性。
第二步:如何切换新的 master。故障切换经过以下步骤:
- master 变成 O_DOWN 后,Sentinel 集群通过Raft 算法选举产生一个 Leader,负责协调整个故障切换过程。
- Sentinel 在剩余健康 Slave 中选举新 Master,规则依次为:replica-priority 配置最低的从节点(默认 100)→ 复制偏移量 offset 最大的从节点(数据最全)→ RunID 字典顺序最小的节点。
- Sentinel Leader 给新 master 执行
slave of no one提升为 master,并让其他 slave 成为新 master 的 slave。 - 旧 master 恢复后,Sentinel Leader 让其降级为 slave,从新 master 同步数据恢复工作。
最终,各个Redis的配置信息,会输出到Redis服务对应的redis.conf文件中,完成配置覆盖。
4. Sentinel 的缺点
- 对客户端不太友好:master 切换后,客户端需要频繁切换写请求到新 master。
- 数据不安全:master 宕机时,已完成但未同步给其他 slave 的操作会彻底丢失,因为切换后所有数据以新 master 为准。
因此,在企业实际运用中,用得更多的是下面的Redis集群服务。
五、Redis 集群 Cluster 机制详解
1. Cluster作用
将多组 Redis Replica 主从集群整合到一起,像一个 Redis 服务一样对外提供服务。核心依然是 Replica 复制集,主要解决三个问题:
- 客户端需要频繁切换 master 的问题。
- 服务端数据量太大后,单个复制集难以承担的问题。
- master 节点挂了之后,主动将 slave 切换成 master,保证服务稳定。
2. Cluster 的核心配置
构建集群需在 redis.conf 中开启集群模式并指定集群配置文件:
cluster-enabled yes cluster-config-file nodes-6379.conf单机模拟三主三从集群的配置示例(以其中一个配置文件 6381 为例):
# 允许所有的IP地址 bind * -::* # 后台运行 daemonize yes # 允许远程连接 protected-mode no # 密码 requirepass 123qweasd # 主节点密码 masterauth 123qweasd # 端口 port 6381 # 开启集群模式 cluster-enabled yes # 集群配置文件 cluster-config-file nodes-6381.conf # 集群节点超时时间 cluster-node-timeout 5000 # log日志 logfile "/root/myredis/cluster/redis6381.log" # pid文件 pidfile /var/run/redis_6381.pid # 开启AOF持久化 appendonly yes # 配置数据存储目录 dir "/root/myredis/cluster" # AOF目录 appenddirname "aof" # AOF文件名 appendfilename "appendonly6381.aof" # RBD文件名 dbfilename "dump6381.rdb"依次创建 6381,6382,6383,6384,6385,6386六个端口的Redis配置文件并启动服务,构建集群命令,将多个独立的Redis服务整合成一个统一的集群:
redis-cli -a 123qweasd --cluster create --cluster-replicas 1 192.168.65.214:6381 192.168.65.214:6382 192.168.65.214:6383 192.168.65.214:6384 192.168.65.214:6385 192.168.65.214:63863. Redis Slot 槽位机制详解
Slot 槽位的作用
Redis Cluster 采用数据分片(Sharding)的方式存储数据,将整个数据集划分为16384 个哈希槽(Slot)。每个键通过 CRC16 算法计算哈希值,再对 16384 取模,得到该键所属的槽位,最终由负责该槽位的节点存储。
# 计算键所属槽位的公式 slot = CRC16(key) % 16384Slot 槽位机制解决了单节点数据量过大的问题,让数据可以均匀分布到集群中的多个节点上,实现水平扩展。
槽位分配与迁移
集群创建时,16384 个槽位会被平均分配到各个 master 节点。例如三主三从集群中,每个 master 节点负责约 5461 个槽位。可通过cluster info查看槽位分配情况,通过cluster nodes查看每个节点负责的槽位范围。
当需要扩容或缩容时,可以通过reshard操作将槽位从某个节点迁移到另一个节点,迁移过程中数据会同步转移,不影响集群对外服务。
# 增加6387,6388两个Redis服务,并启动 # 添加到集群当中 redis-cli -a 123qweasd -p 6381 --cluster add-node 192.168.65.214:6387 192.168.65.214:6388 # 确定集群状态 此时新节点上是没有slot分配的 redis-cli -a 123qweasd -p 6381 --cluster check 192.168.65.214:6381 # 手动触发reshard,重新分配槽位 redis-cli -a 123qweasd -p 6381 reshard 192.168.65.214:6381 # 再次确定集群状态 此时新节点上会有一部分槽位分配 redis-cli -a 123qweasd -p 6381 --cluster check 192.168.65.214:6381槽位slot与键key的关系
每个键只能属于一个槽位,但一个槽位可以包含多个键。当客户端访问某个键时,Redis 会先计算该键的槽位,再定位到负责该槽位的节点。如果客户端连接的节点不是目标节点,会返回MOVED重定向指令,客户端根据该指令重新连接正确的节点。
对于需要原子操作的多个键,Redis 提供了Hash Tag机制:只要键名中包含{}包裹的相同内容,这些键就会被分配到同一个槽位,从而支持在同一个节点上执行多键操作。
# 使用 Hash Tag 让多个键落在同一槽位 set {user:1001}:name "张三" set {user:1001}:age 25 # 这两个键都会落在同一个槽位Slot 槽位的核心配置
槽位数量固定为 16384,不可修改。相关配置项如下:
- cluster-enabled yes:开启集群模式,启用槽位机制。
- cluster-config-file nodes-6381.conf:集群配置文件,记录节点与槽位的映射关系。
- cluster-node-timeout 5000:节点超时时间,超过该时间未响应则判定节点故障。
4. Redis集群选举原理
1、gossip协议
Redis集群之间通过gossip协议进行频繁的通信,用于传递消息和更新节点状态。
主要作用有:
- 节点间发送心跳和确认其他节点的存在。
- 通知其他节点新节点的加入或已经下线的节点。
- 通过反馈机制更新节点的状态,如权重、过期时间等
gossip协议包含多种消息,包括ping,pong,meet,fail等等。
- meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信;
- ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping交换元数据(类似自己感知到的集群节点增加和移除,hash slot信息等);
- pong: 对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新;
- fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
gossip集群是去中心化的,各个节点彼此之间通过gossip协议互相通信,保证集群内部各个节点最终能够达成统一。gossip协议更新元数据并不是同时在集群内部同步,而是陆陆续续请求到所有节点上。因此gossip协议的数据统一是有一定的延迟的。
gossip协议最大的好处在于,即使集群节点的数量增加,每个节点的负载也不会增加很多,几乎是恒定的。因此在Redis集群中,哪怕构建非常多的节点,也不会对服务性能造成很大的影响。但是gossip协议的数据同步是有延迟的,如果集群节点太多,数据同步的延迟时间也会增加。这对于Redis是不合适的。因此,通常不建议构建太大的Redis集群。
需要注意下的是,Redis集群中,每个节点都有一个专门用于节点之间进行gossip通信的端口,就是自己提供服务的端口+10000.因此,在部署Redis集群时,要注意防火墙配置,不要把这个端口屏蔽了。
2、Redis集群选举流程
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master 可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:
1》slave发现自己的master变为FAIL
2》将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息(currentEpoch可以理解为选举周期,通过cluster info指令可以看到)
3》其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个 epoch只发送一次ack
4》尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5》slave收到超过半数master的ack后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两 个,当其中一个挂了,只剩一个主节点是不能选举成功的)
6》slave广播Pong消息通知其他集群节点
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待 FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
延迟计算公式: DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方 式下,持有最新数据的slave将会首先发起选举(理论上)。
七、总结与要点回顾
1. 核心知识点总结
- 性能压测:使用
redis-benchmark对 Redis 进行基准测试,评估读写性能。 - 持久化机制:RDB 适合定期备份、恢复快;AOF 记录每次写操作、数据更安全;混合持久化兼顾两者优势。
- 主从复制:实现读写分离和数据备份,但 master 宕机需要人工干预,不具备自动故障转移能力。
- 哨兵集群:在主从复制基础上提供高可用,自动监控 master 状态并完成故障切换。
- Cluster 集群:通过 16384 个 Slot 槽位实现数据分片,解决单节点容量瓶颈,支持水平扩展。
- Slot 槽位:数据分布的核心机制,通过 CRC16 算法计算槽位,支持 Hash Tag 实现多键原子操作。
2. 三种方案对比
| 方案 | 解决的核心问题 | 优点 | 缺点 |
|---|---|---|---|
| 主从复制 | 读写分离、数据备份 | 配置简单、数据安全 | master 宕机需人工干预 |
| 哨兵集群 | 自动故障转移 | 高可用、自动切换 | 客户端需频繁切换、数据可能丢失 |
| Cluster 集群 | 数据分片、水平扩展 | 容量大、扩展性强 | 配置复杂、多键操作受限 |
八、常见面试提问与解答
1. Redis 的持久化方式有哪些?各自有什么优缺点?
解答:Redis 提供 RDB 和 AOF 两种持久化方式。RDB 按时间间隔保存数据快照,文件紧凑、恢复速度快,但不能实时备份,可能丢失部分数据;AOF 记录每次写操作,数据更安全,但文件较大、性能略低。实际生产中通常同时开启两种方式,兼顾数据安全和恢复效率。
2. 主从复制和哨兵集群有什么区别?
解答:主从复制实现数据的读写分离和备份,但 master 宕机时需要人工干预切换;哨兵集群在主从复制基础上增加了自动监控和故障转移能力,当 master 宕机时自动从 slave 中选举新的 master,实现高可用。哨兵集群是主从复制的增强方案。
3. Redis Cluster 是如何实现数据分片的?
解答:Redis Cluster 将数据划分为 16384 个哈希槽,每个键通过 CRC16 算法计算哈希值后对 16384 取模,得到所属槽位。槽位被平均分配到各个 master 节点,客户端访问时根据槽位定位到对应节点。通过槽位迁移可以实现集群的扩容和缩容。
4. 什么是 Slot 槽位?为什么是 16384 个?
解答:Slot 槽位是 Redis Cluster 数据分片的基本单位,整个集群被划分为 16384 个槽位,每个键通过 CRC16(key) % 16384 计算归属。16384 这个数字是经过权衡的:槽位数量足够多,可以保证数据分布均匀;同时槽位信息在节点间传递时开销可控,心跳包中携带的槽位位图不会过大。
5. 什么是 Hash Tag?有什么作用?
解答:Hash Tag 是 Redis Cluster 中让多个键落在同一槽位的机制。当键名中包含{}包裹的相同内容时,Redis 只对花括号内的内容计算哈希值,从而使这些键被分配到同一个槽位。这样可以保证多个键在同一个节点上执行,支持多键原子操作,如事务和 Lua 脚本。
6. 哨兵集群中 quorum 参数的含义是什么?
解答:quorum 是哨兵集群中确认 master 客观下线所需的最少哨兵节点数。当超过 quorum 个哨兵节点都认为 master 主观下线(S_DOWN)后,才标记为客观下线(O_DOWN),触发故障切换。quorum 通常配置为哨兵节点总数的过半数,防止网络抖动导致误判。
7. Redis 集群中客户端访问数据时,如果连接的节点不是目标节点会怎样?
解答:客户端连接的节点会计算目标键的槽位,如果该槽位不属于当前节点,会返回MOVED重定向指令,告知客户端目标节点的地址。客户端根据该指令重新连接正确的节点完成操作。这也是 Redis Cluster 客户端需要实现集群协议的原因。
8. Redis集群能不能保证数据安全?
解答:在Redis集群相对比较稳定的时候,Redis集群是能够保证数据安全的。因为Redis集群中每个master都是可以配置slave从节点的。这些slave节点会即时备份master的数据。在master宕机时,slave会自动切换成master。继续提供服务。
但是,由于Redis集群的gossip协议在同步元数据时不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统收到的写入请求命令。这些特定条件通常都比较苛刻,概率比较小。比如网络抖动产生的脑裂问题。在企业中,有良好运维支持,通常可以认为Redis集群的数据是安全的。