Redis 内容及相关实验Redis 就像一个请了个「24 小时不睡觉、记忆力还超群」的数据管家你把数据丢给它它直接放在内存里随取随用快得离谱。目录Redis 简介Redis 安装部署Redis 主从复制Redis 哨兵模式 SentinelRedis Cluster 集群三种高可用方案对比小结总结一、Redis 简介1.1 Redis 是什么RedisRemote Dictionary Server是一个开源的、基于内存的键值对Key-Value数据库。它把所有数据放在内存里因此读写速度能达到10 万 QPS同时通过 RDB / AOF 把数据落地到磁盘宕机后也能恢复所以它既快又不怕丢。它和 MySQL 这种把数据放硬盘、用的时候再读的传统关系型数据库不一样MySQL 是仓库规整但取货慢Redis 是手边的保险柜随手就能拿。典型使用场景场景说明缓存Cache把热点数据放 Redis挡在数据库前面扛住高并发读数据库DB直接当主存储配合持久化保证数据不丢消息队列 / 发布订阅用 List、Stream 做轻量队列、用 Pub/Sub 做消息广播排行榜 / 计数器用 ZSet、incr 做实时排名、访问计数分布式锁用SET key value NX实现跨进程互斥1.2 为什么这么快数据在内存没有磁盘 IO 瓶颈单线程模型避免了多线程上下文切换和锁竞争6.0 后引入多线程 IO但命令执行仍是单线程IO 多路复用epoll一个线程就能同时hold住海量连接高效的数据结构SDS、跳表、哈希表等底层结构都为性能量身设计。1.3 数据类型Redis 的 key 都是字符串value 支持多种结构。记住五大基础类型 扩展类型就够了String字符串最常用可存文本、数字、序列化对象支持incr自增List列表双向链表可做队列 / 栈Hash哈希键值对集合适合存对象属性如用户资料Set集合无序去重支持交集/并集做共同好友、抽奖ZSet有序集合带分数的有序集合做排行榜神器扩展类型Bitmaps位图在线状态、HyperLogLogUV 统计、Geospatial地理附近的人、Streams消息流。1.4 持久化RDB 与 AOF内存数据断电即失所以 Redis 提供两种持久化方式生产环境建议两个都开RDB快照定时把内存全量数据 dump 成.rdb二进制文件。文件小、恢复快适合备份缺点是可能丢最后一次快照之后的数据。AOF日志把每一条写命令追加到.aof文件。数据更安全可配置每秒/每次刷盘文件大、恢复稍慢。重启时 Redis优先用 AOF恢复数据更全RDB 主要用来做快速备份和主从全量同步。二、Redis 安装部署实验实验环境3 台机器redis-node1/2/3IP 分别为172.25.254.10/20/30系统已配置好主机名解析。以下以 node1 为例其余节点同样操作。2.1 安装依赖[rootredis-node1 ~]# dnf install make gcc initscripts -y2.2 源码编译安装[rootredis-node1 ~]# wget https://download.redis.io/releases/redis-7.4.8.tar.gz[rootredis-node1 ~]# tar zxf redis-7.4.8.tar.gz[rootredis-node1 ~]# cd redis-7.4.8/[rootredis-node1 redis-7.4.8]# make make install2.3 用脚本生成服务install_server.shRedis 自带utils/install_server.sh可以一键生成 systemd 可管理的服务。systemd环境下脚本默认会退出需要先把它的 systemd 检测注释掉[rootredis-node1 redis-7.4.8]# cd utils/[rootredis-node1 utils]# vim install_server.sh# 把下面这段 systemd 检测注释掉否则脚本直接 exit#_pid_1_exe$(readlink -f /proc/1/exe)#if [ ${_pid_1_exe##*/} systemd ]#then# echo This systems seems to use systemd.# ...#fi[rootredis-node1 utils]# ./install_server.sh交互提示一路回车用默认值关键配置如下Please select the redis port for this instance: [6379] Please select the redis config file name [/etc/redis/6379.conf] /etc/redis/redis.conf Please select the redis log file name [/var/log/redis_6379.log] Please select the data directory for this instance [/var/lib/redis/6379] Please select the redis executable path [/usr/local/bin/redis-server] ... Installation successful!2.4 放开监听并启动编辑配置文件关闭保护模式、允许所有网卡监听[rootredis-node1 utils]# vim /etc/redis/redis.conf# 约 89 行允许所有 IP 监听bind* -::*# 约 113 行关闭保护模式实验环境生产请配合密码/防火墙protected-mode no[rootredis-node1 utils]# systemctl daemon-reload[rootredis-node1 utils]# systemctl start redis_6379.service[rootredis-node1 utils]# systemctl status redis_6379.service2.5 验证端口监听[rootredis-node1 ~]# netstat -antlpe | grep redistcp00127.0.0.1:63790.0.0.0:* LISTEN... redis-server tcp00::1:6379 :::* LISTEN... redis-server看到6379端口处于LISTEN说明 Redis 已经跑起来了。node2、node3用同样的步骤安装即可。三、Redis 主从复制3.1为什么需要主从复制单节点 Redis 有两个痛点单点故障挂了就全完和读压力集中。主从复制让一个 Master 把数据同步给多个 Slave读写分离Master 负责写Slave 负责读分摊压力数据冗余Slave 是 Master 的备份复制方式首次是全量复制RDB 快照之后是增量复制命令流。注意默认 Slave 是只读的不能在从节点上写数据。3.2 实验搭建一主两从① 配置主节点node1[rootredis-node1 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no[rootredis-node1 ~]# systemctl restart redis_6379.service② 配置两个从节点node2、node3# 在 redis-node2 节点[rootredis-node2 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no replicaof172.25.254.106379# 指向主节点 IP 端口[rootredis-node2 ~]# systemctl restart redis_6379.service# 在 redis-node3 节点[rootredis-node3 ~]# vim /etc/redis/redis.conf#bind 127.0.0.1 -::1bind* -::* protected-mode no replicaof172.25.254.106379[rootredis-node3 ~]# systemctl restart redis_6379.service3.3 验证复制状态主节点查看node1[rootredis-node1 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:master connected_slaves:2 slave0:ip172.25.254.20,port6379,stateonline,offset391,lag0slave1:ip172.25.254.30,port6379,stateonline,offset391,lag1master_replid:e5f5cddc017ab0d5223213592d0482b832d3af77 master_repl_offset:391看到role:master且connected_slaves:2两个 slave 都是online说明主从建立成功。从节点查看node2[rootredis-node2 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:slave master_host:172.25.254.10 master_port:6379 master_link_status:up# 与主节点连接正常slave_read_only:1# 从节点只读3.4 测试数据同步 从节点只读在主节点写数据从节点立刻能读到# 主节点 node1 写入[rootredis-node1 ~]# redis-cli127.0.0.1:6379setname lee OK127.0.0.1:6379get namelee# 从节点 node2 / node3 读取[rootredis-node2 ~]# redis-cli127.0.0.1:6379get namelee尝试在从节点写入会被拒绝[rootredis-node3 ~]# redis-cli127.0.0.1:6379get namelee127.0.0.1:6379settest123(error)READONLY You cantwriteagainst areadonly replica.✅ 主从复制 读写分离验证通过。四、Redis 哨兵模式 Sentinel4.1主从的短板靠哨兵补主从复制解决了读压力和数据备份但Master 挂了没人自动顶上。哨兵Sentinel就是来干这活的——一组哨兵进程专门盯着 Master发现它真挂了自动把一个 Slave 提升为新 Master并让其他节点改认新主。几个关键概念监控Monitoring哨兵持续 ping 主从节点主观下线sdown某个哨兵自己觉得节点连不上了客观下线odown达到quorum个哨兵都认为下线才确认真挂了故障转移failover选举领头哨兵 → 选一个 Slave 提升 → 通知其余节点quorum认定主节点下线的票数实验中设为 2即至少 2 个哨兵同意。4.2 实验搭建哨兵① 主节点复制并编辑哨兵配置[rootredis-node1 ~]# cd redis-7.4.8/[rootredis-node1 redis-7.4.8]# cp -p sentinel.conf /etc/redis/[rootredis-node1 ~]# vim /etc/redis/sentinel.confprotected-mode no# 关闭保护模式port26379# 哨兵监听端口daemonize no# 前台运行方便看日志pidfile /var/run/redis-sentinel.pid loglevel notice sentinel monitor mymaster172.25.254.1063792# 监控 mymasterquorum2sentinel down-after-milliseconds mymaster10000# 10 秒连不上视为下线sentinel parallel-syncs mymaster1# 故障转移后同时同步新主的 slave 数sentinel failover-timeout mymaster180000# 故障切换超时 3 分钟⚠️ 原参考文档此处写的是172.25.254.100应为实际 master 的172.25.254.10本文已修正否则哨兵会监控一个不存在的地址。② 从节点也关闭保护模式[rootredis-node2 ~]# vim /etc/redis/redis.confprotected-mode no[rootredis-node2 ~]# systemctl restart redis_6379.service[rootredis-node3 ~]# vim /etc/redis/redis.confprotected-mode no[rootredis-node3 ~]# systemctl restart redis_6379.service③ 把哨兵配置发给两个从节点三台一起启动[rootredis-node1 ~]# scp /etc/redis/sentinel.conf root172.25.254.20:/etc/redis/[rootredis-node1 ~]# scp /etc/redis/sentinel.conf root172.25.254.30:/etc/redis/# 三台节点都执行[rootredis-node1 ~]# redis-sentinel /etc/redis/sentinel.conf启动后日志里能看到哨兵发现了 master 和两个 slave以及彼此# monitor master mymaster 172.25.254.10 6379 quorum 2* slave slave172.25.254.20:6379... mymaster172.25.254.106379* slave slave172.25.254.30:6379... mymaster172.25.254.106379* sentinel sentinel 28f2f3da...172.25.254.2026379 mymaster... * sentinel sentinel89568283...172.25.254.3026379 mymaster...4.3 实验测试故障切换① 干掉主节点[rootredis-node1 ~]# redis-cli127.0.0.1:6379SHUTDOWN not connected② 观察哨兵日志故障转移过程# sdown master mymaster 172.25.254.10 6379 # 主观下线# odown master mymaster 172.25.254.10 6379 #quorum 2/2 # 客观下线# try-failover master mymaster ...# vote-for-leader d0780e7f... 1 # 投票选领头哨兵# selected-slave slave 172.25.254.20:6379 ... # 选中 .20 提升# promoted-slave slave 172.25.254.20:6379 ... # 提升为 master# failover-end master mymaster 172.25.254.10 6379# switch-master mymaster 172.25.254.10 6379 172.25.254.20 6379 # 主切换到 .20③ 在 node3 上确认已认新主[rootredis-node3 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:slave master_host:172.25.254.20# 已经指向新主 .20master_port:6379 master_link_status:up④ 恢复原主节点node1[rootredis-node1 ~]# /etc/init.d/redis_6379 start原主重启后变成新主的从节点在 node2 上能看到[rootredis-node2 ~]# redis-cli127.0.0.1:6379info replication# Replicationrole:master connected_slaves:2 slave0:ip172.25.254.30,port6379,stateonline,... slave1:ip172.25.254.10,port6379,stateonline,...# 原主 .10 已成为从✅ 哨兵自动故障转移验证通过。五、Redis Cluster 集群5.1 理论集群解决了什么哨兵解决了主挂了自动切换但它只有一个 Master 写写能力和存储容量都有上限。Redis Cluster 是分布式方案数据分片把数据按slot CRC16(key) % 16384分到 16384 个哈希槽槽平均分配到多个 Master无中心化客户端连任意节点节点算槽后命中自己就处理否则返回MOVED重定向内置高可用每个 Master 配 SlaveMaster 宕机其 Slave 自动接管槽不需要哨兵在线扩缩容槽可以在节点间迁移集群不中断。5.2 实验环境6 台机器172.25.254.10 ~ 60其中.10/.20/.30为 Master.40/.50/.60为对应 Slave。5.3 配置集群节点6 台节点都执行以下配置先设主从认证、开启 cluster[rootredis-node1 ~]# vim /etc/redis/6379.confmasterauth123456# 集群主从认证密码cluster-enabledyes# 开启 cluster 功能cluster-config-file nodes-6379.conf# 集群配置文件cluster-node-timeout15000# 节点超时ms[rootredis-node1 ~]# /etc/init.d/redis_6379 stop[rootredis-node1 ~]# /etc/init.d/redis_6379 start# 首次搭建先清掉旧数据已有数据时必须[rootredis-node1 ~]# redis-cli127.0.0.1:6379flushall127.0.0.1:6379CLUSTER RESET HARD5.4 创建集群一条命令拉起 3 主 3 从--cluster-replicas 1表示每个 Master 配 1 个 Slave[rootredis-node1 ~]# redis-cli --cluster create \172.25.254.10:6379172.25.254.20:6379172.25.254.30:6379\172.25.254.40:6379172.25.254.50:6379172.25.254.60:6379\--cluster-replicas1输出关键片段自动分配槽位和主从Master[0] - Slots 0 - 5460 Master[1] - Slots 5461 - 10922 Master[2] - Slots 10923 - 16383 Adding replica 172.25.254.50:6379 to 172.25.254.10:6379 Adding replica 172.25.254.60:6379 to 172.25.254.20:6379 Adding replica 172.25.254.40:6379 to 172.25.254.30:6379 Can I set the above configuration? (type yes to accept): yes Nodes configuration updated [OK] All nodes agree about slots configuration.5.5 验证集群状态# 集群信息总览[rootredis-node1 ~]# redis-cli --cluster info 172.25.254.10:6379172.25.254.10:6379 -0keys|5461slots|1slaves.172.25.254.30:6379 -0keys|5461slots|1slaves.172.25.254.20:6379 -0keys|5462slots|1slaves.[OK]0keysin3masters.# 集群自身状态[rootredis-node1 ~]# redis-cli cluster infocluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_known_nodes:6 cluster_size:3# 健康检查[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379[OK]All16384slots covered.cluster_state:ok且All 16384 slots covered说明集群健康。拓扑如下5.6集群扩容加一主一从业务增长要加机器集群支持在线扩容。① 加入新主节点 .70[rootredis-node1 ~]# redis-cli --cluster add-node 172.25.254.70:6379 172.25.254.10:6379[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379172.25.254.70:6379 -0keys|0slots|0slaves.# 新主还没槽② 迁移槽给新主reshard 4096 个[rootredis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379How many slotsdoyou want to move(from1to16384)?4096What is the receivingnodeID? dfabfe07170ac9b5d20a5a7a70c836877bd64504# .70 的 IDPlease enter all thesourcenodeIDs. Sourcenode#1: all # 从所有现有 master 取槽Sourcenode#2: doneReady to move4096slots.迁移后.70分到 4096 个槽从三个老 master 各取一部分M: dfabfe07170ac9b5d20a5a7a70c836877bd64504 172.25.254.70:6379 slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master③ 给新主挂从节点 .80[rootredis-node1 ~]# redis-cli --cluster add-node 172.25.254.80:6379 172.25.254.10:6379 \--cluster-slave --cluster-master-id dfabfe07170ac9b5d20a5a7a70c836877bd64504扩容后变成4 主 4 从槽自动均摊到每主 4096 个。5.7集群缩容删一主一从① 把 .70 的槽迁回 .10[rootredis-node1 ~]# redis-cli --cluster reshard 172.25.254.10:6379How many slotsdoyou want to move(from1to16384)?4096What is the receivingnodeID? 8db833f3c3bc6b8f93e87111f13f56d366f833a0# .10 的 IDSourcenode#1: dfabfe07170ac9b5d20a5a7a70c836877bd64504 # .70 的 IDSourcenode#2: done② 删除节点先删从 .80再删主 .70[rootredis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 1176ee294e6b5071ca57e93374d04ac22028daedSending CLUSTER FORGET messages to the cluster...[rootredis-node1 ~]# redis-cli --cluster del-node 172.25.254.10:6379 dfabfe07170ac9b5d20a5a7a70c836877bd64504[rootredis-node1 ~]# redis-cli --cluster check 172.25.254.10:6379[OK]All16384slots covered.缩容完成恢复为 3 主 3 从。⚠️ 删除主节点前必须先把它的槽全部迁走否则会丢数据。六、三种高可用方案对比小结方案写能力存储上限自动故障转移是否需要哨兵适用场景主从复制单 Master单节点❌ 手动否读多写少、要备份哨兵 Sentinel单 Master单节点✅ 自动是高可用、写量不大Cluster 集群多 Master横向扩展✅ 自动否内置大数据量、高并发写七、总结Redis 是什么基于内存的 KV 数据库快、支持持久化、数据类型丰富主从复制一主多从做读写分离和数据备份但 Master 挂了要人手动顶哨兵模式哨兵自动监控 故障转移解决主从的单点问题但仍只有一个 Master 写Cluster 集群数据分 16384 槽、多 Master 分片既能横向扩容又能自动故障转移是大规模场景的终极方案持久化RDB AOF 都开重启优先 AOFRDB 做备份。