02-Redis 部署与高可用:容器化、主从复制与哨兵
📝 笔记摘要:Redis 的容器化部署、主从复制与哨兵切换
Redis 装起来不难,难的是装对。这篇按「装在哪、怎么装、怎么确认装好了、怎么让它不挂」四步走:容器部署、Windows 上的选择、压测看指标、主从复制和哨兵自动切换。
Redis 系列 共 4 篇,这是第 2 篇
01 Redis 核心 数据结构、持久化与内存治理
02-Redis 部署与高可用 容器化部署、主从复制、哨兵切换 ← 本篇
03 Spring Boot 整合 Redis 连接配置、序列化、工具类
04 Redis 缓存实战 穿透击穿雪崩、双写一致、分布式锁
这篇的结构
1. 装 Redis 的四条路
2. Docker 部署:配置和数据都要挂出来
3. 客户端连不上时,按这个顺序查
4. 压测:redis-benchmark 的结果怎么读
5. 日常运维命令
6. 主从复制
7. 哨兵模式
8. 发布订阅
9. 客户端怎么知道主节点换了
1. 装 Redis 的四条路
Redis 官方只支持类 Unix 系统。Windows 上没有官方版本,这是个必须先接受的前提。
这篇只讲怎么把它跑起来、跑稳。各数据类型怎么用、持久化怎么选、内存怎么管,在 Redis 核心 那篇。
Docker Linux 上的首选,环境干净、升级方便、配置和数据都能挂出来。下面第 2 节展开
Windows 本地 三条路,见下面的展开
源码编译make && make install,需要能装依赖,适合要改源码的场景
云托管 阿里云 Redis、AWS ElastiCache,省掉运维但多一层账单和网络延迟
Windows 上的三条路,各有各的问题:
微软官方移植版 仓库在
microsoftarchive/redis,最后一个版本是 3.0.504,停在 2016 年 7 月,仓库已归档不再维护。它缺 Redis 6 的 ACL、Redis 7 的内存管理,而且 2016 年之后修掉的一堆安全漏洞它都没有。不建议用
Memurai 微软那个项目停掉之后接手的是 Janea Systems,2024 年 10 月被 Redis 官方指定为 Windows 兼容性合作伙伴。免费版是 Developer Edition,条款明确禁止用于生产环境;生产要用 Enterprise 版。API 兼容 Redis 7.x
WSL2 装的是原生 Linux 版 Redis,版本最新、和生产环境完全一致,代价是要配一层子系统
Docker Desktop 和 Linux 上完全一样,最省心
提示:只要机器能跑 Docker,Windows 上也直接用 Docker,不用绕 WSL2 和 Memurai。绕的那些路存在的唯一原因是「当年 Docker 装不动」。
2. Docker 部署:配置和数据都要挂出来
用官方镜像跑,先把目录和配置文件准备好:
# 宿主机上建目录,配置和数据分开放
mkdir -p /data/redis/data
# 把准备好的 redis.conf 放到 /data/redis/redis.conf
# 最少要改这几项:
# dir /data
# appendonly yes
# requirepass <你的密码>
启动:
docker run -d \
--name redis \
--restart unless-stopped \
-p 6379:6379 \
-v /data/redis/redis.conf:/etc/redis/redis.conf \
-v /data/redis/data:/data \
redis:8.10 redis-server /etc/redis/redis.conf
两个 -v 缺一不可 第一个挂配置文件,第二个挂数据目录。漏了第二个,容器一删数据就没了
配置文件路径必须显式指定 官方镜像的默认配置在/usr/local/etc/redis/redis.conf,你挂到/etc/redis/redis.conf就得在命令行末尾写上这个路径,否则 Redis 读的是镜像自带的默认配置,你的密码、持久化设置全没生效
改了配置要重启容器 Redis 不支持热加载配置。改完redis.conf必须docker restart redis
--restart unless-stopped 让容器跟着 Docker 服务一起起,也能在宿主机重启后自动拉起来
确认跑起来了:
# 进容器敲 ping
docker exec -it redis redis-cli -a <你的密码> ping
# PONG
# 看日志
docker logs --tail 50 redis
# 看端口映射
docker port redis
宿主机上没装 redis-cli 时,直接用容器里那份:
# 写个包装脚本放进 PATH,省得每次敲一长串
echo '@echo off' > redis-cli.bat
echo 'docker exec -it redis redis-cli -a <你的密码> %*' >> redis-cli.bat
需要连别的 Redis 实例时,把容器名换成对应的容器名或直接用 redis-cli -h 主机 -p 端口。
3. 客户端连不上时,按这个顺序查
图形化客户端是排查问题时最顺手的工具。常见的是 Another Redis Desktop Manager、RedisInsight 这类。

连不上的时候按这个顺序排查,别一上来就改配置:
① 服务活着吗
docker exec -it redis redis-cli ping,回 PONG 说明服务本身没问题
② 端口通吗docker port redis确认映射到了宿主机 6379,再从宿主机telnet 127.0.0.1 6379试
③ 密码对吗 设了requirepass或 ACL 之后,客户端必须填密码,填错的表现和连不上一样
④ bind 监听的是哪个地址 容器里的bind 127.0.0.1只在容器网络内可访问,宿主机端口映射过来也连不上。容器场景要改成bind 0.0.0.0
⑤ protected-mode 它是保护开关,配了密码才能在bind 0.0.0.0的情况下放行外部连接
⑥ 防火墙和安全组 云主机还要看安全组有没有放行 6379
提示:不要为了连上图形化工具就把
protected-mode改成no,更不要把bind那一行删光。那等于把一个没有认证的 Redis 敞在网上,是 Redis 未授权访问漏洞最经典的成因。容器场景下正确的组合是:bind 0.0.0.0+protected-mode yes+ 一定设密码 + 防火墙只放行来源地址。
4. 压测:redis-benchmark 的结果怎么读
Redis 自带压测工具,在容器里就能跑:
docker exec -it redis redis-benchmark -n 100000 -c 50 -q
-n 每个测试项的请求数,默认 100000
-c 并发客户端数,默认 50
-d 数据集大小,单位字节,默认3(字节),测真实场景要调大
-t 只跑指定测试项,默认*(全跑)
-q 安静模式,只输出关键指标
-r 用--csv输出,方便丢进表格工具
-P 每个请求的 pipeline 深度,默认 1
输出长这样:
SET: 100000 requests completed in 1.16 seconds, 86206.90 requests per second
requests per second 这是核心指标
p50 / p95 / p99 延迟分位。非-q模式会打出来,p99 比平均值更能说明尾部延迟
latency average 平均值,容易被大量快请求拉低,别只看它
提示:压测数字只在同一台机器、同一网络、同一并发数之间有可比性。「每秒十万次」这种数字换个环境就完全不是那回事了,拿它当容量规划依据会算错。压测的价值是和线上同一个规格的机器做对比,看改配置前后掉了多少。
提示:压测默认把所有 key 塞进第 0 个数据库,跑完记得清掉。用
-n 2可以指定用第 2 个库,别在生产实例上随手压。
5. 日常运维命令
切库
SELECT 3,默认 16 个库,编号 0 到 15
看当前库多大DBSIZE
看某个键的类型和过期TYPE key、TTL key(返回 -1 表示永不过期,-2 表示键不存在)
看键SCAN 0 COUNT 100,不要用KEYS *
清当前库FLUSHDB
清全部FLUSHALL
看服务信息INFO,分段看INFO memory、INFO replication、INFO stats
看慢查询SLOWLOG GET 10
提示:
FLUSHDB和FLUSHALL在生产上是没有确认、没有撤销的。Redis 没有类似DROP TABLE的二次确认。它们执行起来是 O(1) 的「打个标记」,但后台真正释放内存要花时间,期间新写的 key 又会触发新的释放动作——大实例上这一下能卡住整个服务。在生产实例上执行之前,先确认一下自己在哪个库:SELECT 0回车,看到提示符变成0>再说。
6. 主从复制
主从复制是数据流:主节点把写命令流推给从节点。一个主可以挂多个从,写全走主,读可以分到从。

起三个实例,把两个从节点指到主节点:
# 主节点
docker run -d --name redis-master -p 6379:6379 \
-v /data/redis-master/redis.conf:/etc/redis/redis.conf \
-v /data/redis-master/data:/data \
redis:8.10 redis-server /etc/redis/redis.conf --appendonly no
# 从节点 1,配置文件里端口改成 6380
docker run -d --name redis-slave1 -p 6380:6380 \
-v /data/redis-slave1/redis.conf:/etc/redis/redis.conf \
-v /data/redis-slave1/data:/data \
redis:8.10 redis-server /etc/redis/redis.conf --appendonly no
# 从节点 2,端口 6381
docker run -d --name redis-slave2 -p 6381:6381 \
-v /data/redis-slave2/redis.conf:/etc/redis/redis.conf \
-v /data/redis-slave2/data:/data \
redis:8.10 redis-server /etc/redis/redis.conf --appendonly no
在从节点里执行 REPLICAOF 认主:
# 查主节点的容器 IP
docker inspect redis-master | grep IPAddress
# 在从节点上认主
docker exec -it redis-slave1 redis-cli REPLICAOF 172.17.0.2 6379
# 查看复制状态:role 是 master 还是 slave
docker exec -it redis-slave1 redis-cli INFO replication
REPLICAOF 不是 SLAVEOF
SLAVEOF在 Redis 7.0 已经被彻底删除。老教程和写死的运维脚本里那条命令现在会直接报未知命令。主节点挂掉、脚本要执行故障切换的时候才发现这一点,正好赶上最需要它的时候
解除主从REPLICAOF NO ONE,把从节点提成独立的主
密码认证 主节点设了密码,从节点必须配masterauth <主节点密码>,否则连不上,报错是NOAUTH Authentication required
复制是异步的 主节点写完立刻返回,从节点可能还没收到。这时候去从节点读,会读到旧值。读己之写要读主节点
主从关系建起来后能干什么:数据冗余、故障恢复、读扩展。要注意的是它不解决写扩展,写永远只有一个节点扛。
7. 哨兵模式
主从解决了「主挂了数据还在」,但没说「主挂了谁来当新的主」。哨兵补的就是这一块:多个哨兵互相盯着主节点,达成法定多数后把一个从节点提升为新的主。
mkdir -p /data/redis-sentinel1/sentinel/log
# /data/redis-sentinel1/sentinel/sentinel.conf
port 26379
dir "/var/log/sentinel"
logfile "/var/log/sentinel/sentinel1.log"
sentinel monitor mymaster 172.17.0.2 6379 1
sentinel auth-pass mymaster <主节点密码>
monitor 的最后一个数字是法定人数 这里是 1,表示一个哨兵觉得主节点挂了就可以发起故障转移。生产上一般是 2,配合三个哨兵使用
哨兵节点必须是奇数且至少三个 偶数在网络分区时会出现票数平票,谁也不敢动主节点,故障转移卡死
bind 要写 0.0.0.0 哨兵之间要互相通信,只监听回环地址的话换主的时候找不到其他哨兵
哨兵需要读写配置文件 它会把新主节点的信息写回 sentinel.conf,目录权限不对会导致「换主之后重新加载配置失败」
启动哨兵:
chmod -R 777 /data/redis-sentinel1
docker run -d --name sentinel1 \
-v /data/redis-sentinel1/sentinel:/conf:z \
-v /data/redis-sentinel1/sentinel/log:/var/log/sentinel \
-p 26379:26379 \
redis:8.10 redis-sentinel /conf/sentinel.conf
提示:
/conf:z末尾那个:z不能省。它让这个挂载变成共享挂载——哨兵把新主节点写回sentinel.conf时,宿主机上的文件会同步更新。少了它,宿主机上的配置文件还是旧的,容器重启后会加载回旧配置,下次换主时又是一次故障。这个坑很隐蔽:第一次换主看起来成功,第二次就不灵了。
启动顺序有讲究:先主节点,再从节点,最后哨兵。反过来的话哨兵启动瞬间判定主节点不可达,会触发一次不必要的故障转移。
验证:把主节点停掉,看哨兵有没有把某个从节点提升上来。
docker stop redis-master
docker exec -it sentinel1 redis-cli SENTINEL get-master-addr-by-name mymaster
8. 发布订阅
最简单的消息通道,一端订阅频道,一端往频道里发消息:
# 订阅端
docker exec -it redis redis-cli SUBSCRIBE channel1
# 发布端
docker exec -it redis redis-cli PUBLISH channel1 "hello"
SUBSCRIBE 订阅频道,可以同时订阅多个
PSUBSCRIBE 按模式订阅,比如PSUBSCRIBE news.*
PUBLISH 发布,返回收到消息的订阅者数量
UNSUBSCRIBE 退订
提示:发布订阅不存消息。订阅者不在线的时候发的消息直接丢了,没有积压、没有重投、没有确认。它能做「配置变更广播」「服务上下线通知」这类能丢的场景,不能当业务消息队列用。要可靠投递、带持久化和确认机制,用 RabbitMQ 那样的正经消息中间件。
另外 Redis 7.0 给 Pub/Sub 加了分片能力,同一个频道的消息可以分到不同分片上,吞吐不再受单线程限制。
9. 客户端怎么知道主节点换了
哨兵把从节点提升成新主之后,客户端并不知道——它手里的连接还指着老主节点。除非客户端接了哨兵。
Java 侧的做法是配一个哨兵模式的连接工厂,让客户端订阅哨兵的通知,主节点一变就自动重连并切到新主。具体配置见 Spring Boot 整合 Redis。
不用 Java 的话,客户端要能拿到新的主节点地址,最简单的办法是问哨兵:
redis-cli -h 哨兵地址 -p 26379 SENTINEL get-master-addr-by-name mymaster
提示:哨兵不是集群。它不负责分片,数据仍然只存在主节点和它的从节点上,哨兵只管「主节点挂了换谁当主」这一件事。真要水平分片得用 Redis Cluster,那是另一套东西——槽位分配、节点间总线、
MOVED重定向都是另一堆规则。
💡 补充:容器部署时从节点认主用的那个 IP 是 Docker bridge 网段的地址(172.17.0.x),换一个 Docker 网络或者用了自定义网桥,这个地址会变。生产上用固定网络加 --network-alias 给容器起名字,从节点就能直接用主机名认主,不用每次 docker inspect 去查 IP。
🔥 一句话总结:Redis 部署的坑集中在三处——配置文件没挂进去、数据目录没挂出来、protected-mode 被为了图方便关掉;高可用的路径是「一主两从 + 三个哨兵 + 客户端接哨兵」,主从靠 REPLICAOF(SLAVEOF 在 Redis 7.0 已被删除)。
