非关系型数据库 Redis 进阶
一、Redis 哨兵
之前主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。
这不是一种推荐的方式,更多时候,我们优先考虑**哨兵(Sentinel, [ˈsentɪnl], 森特尼尔)**模式。
1. 什么是哨兵
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

2. 哨兵的作用
这里的哨兵有两个作用
- 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

FailOver
“FailOver” 的中文标准译法是 “故障转移”,是 IT 领域(尤其是高可用架构)的核心术语。
“Fail”(故障)+ “Over”(转移),当主设备或服务 “故障” 时,业务 “转移” 到备用设备服务。是高可用性(High Availability, HA)中的核心技术。
- 故障切换流程
1)主观下线(Subjective Down, SDOWN)
哨兵 1 定期检测主节点(如心跳超时、无响应),发现主节点不可用,但 仅代表哨兵 1 的主观判断(可能因网络问题误判),此时进入 主观下线状态。
2)客观下线(Objective Down, ODOWN)
其他哨兵(如哨兵 2、哨兵 3)也检测到主节点不可用,且 达到预设的投票阈值(如多数哨兵同意) 时,哨兵集群通过内部投票确认主节点 确实故障(客观下线)。
3)选举 Leader 哨兵
多个哨兵通过投票机制选出一个 Leader 哨兵(负责执行故障切换操作),其他哨兵仅参与决策,不直接操作。
4)执行 Failover(故障切换)
Leader 哨兵主导以下操作:
- 从所有从节点中 选择一个最优从节点(如数据最完整、延迟最低的节点)提升为 新主节点。
- 将其他从节点重新配置为 同步新主节点(通过 SLAVEOF命令)。
- 若原主节点恢复,将其降级为 新主节点的从节点。
5)通知客户端(透明化)
- 哨兵集群通过 发布订阅模式(Pub/Sub) 广播主节点变更信息,所有连接的客户端(如应用程序)收到通知后,自动将请求路由到 新主节点,对业务代码无感知(故障切换对客户端透明)。
3. 部署实战
环境准备
配置3个哨兵和1主2从的Redis服务器来演示这个过程。
| 服务类型 | 是否是主服务器 | IP地址 | 端口 | 备注 |
|---|---|---|---|---|
| Redis 1 | 是 | 192.168.88.101 | 6379 | |
| Redis 2 | 否 | 192.168.88.102 | 6379 | |
| Redis 3 | 否 | 192.168.88.103 | 6379 | |
| Sentinel 1 | - | 192.168.88.101 | 26379 | 同 Redis 1 |
| Sentinel 2 | - | 192.168.88.102 | 26379 | 同 Redis 2 |
| Sentinel 3 | - | 192.168.88.103 | 26379 | 同 Redis 3 |
特别注意:使用Redis哨兵模式,最少需要3个节点(一主多从结构),这样至少能部署3 个哨兵进程,从而保证共同投票选出新的主节点。
Redis 哨兵模式的核心功能是监控主从节点状态,并在主节点故障时自动完成**故障切换(Failover),**这一过程依赖多个哨兵节点的协同投票。

一主两从配置
CentOS Stream 9 阿里源
cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
三台 Linux 都安装 Redis
第一步:找到对应的安装包资源,使用wget命令下载,这里安装的7.4.0版本。
安装包资源地址:https://download.redis.io/releases/
第二步:上传或者下载Redis到Linux系统中
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
第三步:配置=>编译=>安装
tar -zxvf redis-7.4.0.tar.gz
cd redis-7.4.0
yum install epel-release -y
yum install make gcc jemalloc jemalloc-devel -y
make
make PREFIX=/usr/local/redis install
第四步:配置环境变量
echo 'PATH=$PATH:/usr/local/redis/bin/' >> /etc/profile && source /etc/profile
查看版本
redis-cli -v

安装成功后,Redis 的可执行文件将被安装到 /usr/local/redis
4. 优化 Linux 系统配置
过量使用内存设置为1
vm.overcommit_memory 的 3 种模式
0(默认)内核根据启发式算法决定是否允许超分配“看情况给,不一定准”
1允许内存超分配,不做任何限制想分就分,不管你有没有这么多内存
2严格限制,不允许超分配非常安全,但可能导致程序申请内存失败
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
#配置好后执行以下命令让配置生效
sysctl -p
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config &> /dev/null
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
modprobe bridge
echo 1 > /proc/sys/net/ipv4/ip_forward
echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf
sysctl -p
5. 配置 Redis 一主两从
修改 Redis 配置
mkdir -p /usr/local/redis/conf
cp /root/redis-7.4.0/redis.conf /usr/local/redis/conf/
修改配置
vim /usr/local/redis/conf/redis.conf
88: bind 127.0.0.1 -::1 --> bind 0.0.0.0
310: daemonize no --> daemonize yes
过量使用内存设置为1
vm.overcommit_memory 的 3 种模式
0(默认)内核根据启发式算法决定是否允许超分配“看情况给,不一定准”
1允许内存超分配,不做任何限制,想分就分,不管你有没有这么多内存
2严格限制,不允许超分配非常安全,但可能导致程序申请内存失败
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
配置好后执行以下命令让配置生效
sysctl -p
启动Redis
启动
redis-server /usr/local/redis/conf/redis.conf
查看服务进程
ps aux | grep redis
ps -ef | grep redis
netstat -pantul|grep 6379
配置redis.service
cat >/etc/systemd/system/redis.service<<EOF
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
重启Redis服务
pkill redis-server
systemctl daemon-reload
systemctl start redis
systemctl enable redis
systemctl status redis --no-pager
5.1. 配置 Master
master主节点配置:
创建conf目录,复制redis.conf配置文件
mkdir -p /usr/local/redis/conf
cp redis.conf /usr/local/redis/conf/
修改redis.conf配置文件
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/redis.conf
创建日志目录
mkdir -p /usr/local/redis/logs/
vim /usr/local/redis/conf/redis.conf
关键参数如下:
bind 0.0.0.0 # 允许所有IP连接
protected-mode no # 关闭redis安全保护机制,允许主从、哨兵、集群中各节点之间的相互访问,没有安全限制
port 6379 # 服务端口
daemonize yes # 允许后台运行
requirepass redis666 # 从服务器连接需要使用密码
logfile "/usr/local/redis/logs/redis.log" # 日志存储目录与名称
replica-read-only no # 可写
[root@server1 ~]# mkdir -p /usr/local/redis/logs/
[root@server1 ~]# vim /usr/local/redis/conf/redis.conf
[root@server1 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
requirepass redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server1 ~]#
重启Redis服务
在master上执行以下命令
systemctl restart redis
systemctl status redis --no-pager
5.2. 配置 Slave
和上面配置 master 一样,我们需要修改端口号和 pid 文件,在修改完之后,我们有两种方法配置从服务。
① 在配置文件中配置从服务
################################# REPLICATION #################################
# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# +------------------+ +---------------+
# | Master | ---> | Replica |
# | (receive writes) | | (exact copy) |
# +------------------+ +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
# stop accepting writes if it appears to be not connected with at least
# a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
# master if the replication link is lost for a relatively small amount of
# time. You may want to configure the replication backlog size (see the next
# sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
# network partition replicas automatically try to reconnect to masters
# and resynchronize with them.
#
# replicaof <masterip> <masterport>
replicaof 192.168.88.101 6379
我们可以在配置文件中直接修改 slaveof 属性,我们直接配置主服务器的IP地址和端口号,如果这里主服务器有配置密码。
可以通过配置 masterauth 来设置链接密码:
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
# masterauth <master-password>
masterauth redis666
整体配置如下:
创建conf目录,复制redis.conf配置文件
mkdir -p /usr/local/redis/conf
cp redis.conf /usr/local/redis/conf/
修改redis.conf配置文件
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/redis.conf
创建日志目录
mkdir -p /usr/local/redis/logs/
vim /usr/local/redis/conf/redis.conf
关键参数如下:
bind 0.0.0.0 # 允许所有IP连接
protected-mode no # 关闭安全保护
port 6379 # 服务端口
daemonize yes # 允许后台运行
masterauth redis666 # 连接主节点时需要使用的主节点密码
logfile "/usr/local/redis/logs/redis.log"
主从配置:设置master redis信息
replicaof 192.168.80.11 6379 # redis5/6/7 版本
第一台slave
[root@server2 ~]# cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
[root@server2 ~]# ls /usr/local/redis/conf/
redis.conf redis.conf.bak
[root@server2 ~]# sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/redis.conf
[root@server2 ~]# mkdir -p /usr/local/redis/logs/
[root@server2 ~]# vim /usr/local/redis/conf/redis.conf
[root@server2 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
masterauth redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.80.11 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server2 ~]#
第二台slave
[root@server3 ~]# cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
[root@server3 ~]# sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/redis.conf
[root@server3 ~]# mkdir -p /usr/local/redis/logs/
[root@server3 ~]# vim /usr/local/redis/conf/redis.conf
[root@server3 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
masterauth redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.80.11 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server3 ~]#
重启Redis服务
分别在slave1和slave2上执行以下命令
systemctl restart redis
systemctl status redis --no-pager
5.3. 验证测试
优化Linux系统
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config &> /dev/null
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
使用info命令,查看一下主从状态:
redis-cli
auth redis666 # 主库要执行
info replication
[root@server1 ~]# redis-cli
127.0.0.1:6379> auth redis666
OK
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.80.12,port=6379,state=online,offset=70,lag=1
slave1:ip=192.168.80.13,port=6379,state=online,offset=70,lag=1
master_failover_state:no-failover
master_replid:b091935ba26b4b361db24d6f63f8be38ee41d7c9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
127.0.0.1:6379>
[root@server2 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.80.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_read_repl_offset:154
slave_repl_offset:154
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:b091935ba26b4b361db24d6f63f8be38ee41d7c9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:154
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:140
127.0.0.1:6379>
[root@server3 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.80.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:196
slave_repl_offset:196
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:b091935ba26b4b361db24d6f63f8be38ee41d7c9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:196
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:182
127.0.0.1:6379>
测试主节点写入,从节点复制

我们如果需要设置读写分离,只需要在 slave 服务器中设置:
replica-read-only yes
这个配置不需要在主节点设置,只需要在副本节点(replica) 的配置中设置。
主节点(master)的核心作用是 “读写都允许”。
replica-read-only yes
6. 配置 Sentinel 哨兵
6.1. 配置 Sentinel
在 sentinel.conf 配置文件中,可以找到 port,这里是用来设置 sentinel 的端口;一般情况下,至少需要三个哨兵对 redis 进行监控。
三台Linux都要进行以下配置
cp /usr/local/src/redis-7.4.0/sentinel.conf /usr/local/redis/conf/
# 从Redis源码包里找到sentinel.conf再复制到指定配置文件目录
mkdir -p /usr/local/redis/logs # 如果执行过了,这一步可以省略
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/sentinel.conf # 去掉#号开头和空行
vim /usr/local/redis/conf/sentinel.conf
protected-mode no
port 26379
daemonize yes
logfile "/usr/local/redis/logs/sentinel.log"
[root@server1 ~]# cp /usr/local/src/redis-7.4.0/sentinel.conf /usr/local/redis/conf/
[root@server1 ~]# sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/sentinel.conf
[root@server1 ~]# vim /usr/local/redis/conf/sentinel.conf
[root@server1 ~]# cat /usr/local/redis/conf/sentinel.conf
protected-mode no
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid
loglevel notice
logfile "/usr/local/redis/logs/sentinel.log"
dir /tmp
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
acllog-max-len 128
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
SENTINEL resolve-hostnames no
SENTINEL announce-hostnames no
SENTINEL master-reboot-down-after-period mymaster 0
[root@server1 ~]#
另外两台Linux的sentinel.conf配置一样
三台Linux的redis.conf都要改成replica-read-only no
sed -i 's/replica-read-only yes/replica-read-only no/' /usr/local/redis/conf/redis.conf
grep replica-read-only /usr/local/redis/conf/redis.conf
systemctl restart redis
systemctl status redis --no-pager


[root@server1 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
requirepass redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server1 ~]#
[root@server2 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
masterauth redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.80.11 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server2 ~]#
[root@server3 ~]# cat /usr/local/redis/conf/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
masterauth redis666
pidfile /var/run/redis_6379.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
replicaof 192.168.80.11 6379
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@server3 ~]#
6.2. 配置 Master 的 IP 和端口
在三个哨兵上,都要配置:
https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/
cp /usr/local/redis/conf/sentinel.conf /usr/local/redis/conf/sentinel.conf.bak
sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/sentinel.conf # 如果优化过了,这一步可以省略
vim /usr/local/redis/conf/sentinel.conf
注意:把默认的 sentinel monitor mymaster 127.0.0.1 6379 2 这行配置删掉!
... 省略部分配置
sentinel monitor mymaster 192.168.88.101 6379 2
sentinel auth-pass mymaster redis666 # 对应 redis.conf 中的 requirepass
...
注:2权值/阈值,代表至少需要2个哨兵确认才能客观下线。
原理:首先某个哨兵发现master主节点无法连接(无法响应),则会标记为主观下线,如果超过2台哨兵确认master节点故障,则标记为客观下线,并触发故障转移。
----------------------------------------------
高可用:在一个集群中(最少2台及以上节点),某个节点出现故障,集群依然可以对外提供相关服务(可用)
故障转移:failover,当主节点宕机,从节点升级为主节点
高可用往往包含健康检查以及故障转移等特性
[root@server1 ~]# cp /usr/local/redis/conf/sentinel.conf /usr/local/redis/conf/sentinel.conf.bak
[root@server1 ~]# vim /usr/local/redis/conf/sentinel.conf
[root@server1 ~]# cat /usr/local/redis/conf/sentinel.conf
protected-mode no
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid
loglevel notice
logfile "/usr/local/redis/logs/sentinel.log"
dir /tmp
sentinel monitor mymaster 192.168.80.11 6379 2
sentinel auth-pass mymaster redis666
sentinel down-after-milliseconds mymaster 30000
acllog-max-len 128
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
SENTINEL resolve-hostnames no
SENTINEL announce-hostnames no
SENTINEL master-reboot-down-after-period mymaster 0
[root@server1 ~]#
[root@server2 ~]# cp /usr/local/redis/conf/sentinel.conf /usr/local/redis/conf/sentinel.conf.bak
[root@server2 ~]# vim /usr/local/redis/conf/sentinel.conf
[root@server2 ~]# cat /usr/local/redis/conf/sentinel.conf protected-mode no
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid
loglevel notice
logfile "/usr/local/redis/logs/sentinel.log"
dir /tmp
sentinel monitor mymaster 192.168.80.11 6379 2
sentinel auth-pass mymaster redis666
sentinel down-after-milliseconds mymaster 30000
acllog-max-len 128
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
SENTINEL resolve-hostnames no
SENTINEL announce-hostnames no
SENTINEL master-reboot-down-after-period mymaster 0
[root@server2 ~]#
[root@server3 ~]# cp /usr/local/redis/conf/sentinel.conf /usr/local/redis/conf/sentinel.conf.bak
[root@server3 ~]# vim /usr/local/redis/conf/sentinel.conf
[root@server3 ~]# cat /usr/local/redis/conf/sentinel.conf
protected-mode no
port 26379
daemonize yes
pidfile /var/run/redis-sentinel.pid
loglevel notice
logfile "/usr/local/redis/logs/sentinel.log"
dir /tmp
sentinel monitor mymaster 192.168.80.11 6379 2
sentinel auth-pass mymaster redis666
sentinel down-after-milliseconds mymaster 30000
acllog-max-len 128
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
SENTINEL resolve-hostnames no
SENTINEL announce-hostnames no
SENTINEL master-reboot-down-after-period mymaster 0
[root@server3 ~]#
6.3. 启动所有的 Sentinel
在三台机器上都执行
# 启动Sentinel
[root@redis ~]# /usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf
# 查看进程
[root@redis ~]# ps -ef | grep redis
或者
[root@redis ~]# ps -aux | grep redis
[root@redis ~]# ps aux|grep sentinel
# 杀掉进程
[root@redis ~]# kill -9 PID
或者
[root@redis ~]# pkill redis-sentinel
6.4. 配置哨兵 systemd 服务
先停止手动起来的哨兵服务,不然后面端口冲突
# 在所有Linux服务器上执行以下命令
/usr/local/redis/bin/redis-cli -p 26379 shutdown
netstat -pantul|grep 26379
再配置哨兵systemd服务
# 在所有Linux服务器上执行以下命令
cat >/etc/systemd/system/redis-sentinel.service<<EOF
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf
ExecStop=/usr/local/redis/bin/redis-cli -p 26379 shutdown
ExecReload=/usr/local/redis/bin/redis-cli -p 26379 shutdown && /usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf
PrivateTmp=true
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl start redis-sentinel
systemctl enable redis-sentinel
systemctl status redis-sentinel --no-pager

6.5. 验证测试
在所有的机器上校验密码
# grep 全局检索 .conf 后缀文件
grep -n 'redis666' /usr/local/redis/conf/*.conf

为主节点和从节点配置密码
vim /usr/local/redis/conf/redis.conf
masterauth redis666 # redis.conf
requirepass redis666 # redis.conf
vim /usr/local/redis/conf/sentinel.conf
sentinel auth-pass mymaster redis666 # sentinel.conf
systemctl restart redis
systemctl restart redis-sentinel
systemctl status redis --no-pager
systemctl status redis-sentinel --no-pager

在任意一个哨兵节点上,执行
redis-cli -p 26379
info sentinel
[root@server1 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.80.11:6379,slaves=2,sentinels=3
127.0.0.1:26379>
[root@server2 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.80.11:6379,slaves=2,sentinels=3
127.0.0.1:26379>
[root@server3 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.80.11:6379,slaves=2,sentinels=3
127.0.0.1:26379>
redis-cli -p 26379 连接的是 Redis Sentinel 服务端口,运行 info sentinel 命令后,输出的内容提供了当前 Redis Sentinel 集群的状态信息。我们可以逐行解释每个字段的含义:
输出解释:
\1. sentinel_masters:1
- 含义:当前 Sentinel 监控的 Redis 主节点数量为 1。此时,
sentinel_masters的值为 1 表示 Sentinel 监控着一个 Redis 主节点。
\2. sentinel_tilt:0
- 含义:
sentinel_tilt表示 Sentinel 是否处于 "倾斜" 状态,即处于故障转移或其它需要手动干预的异常状态。0 表示当前没有处于倾斜状态,系统运行正常。
\3. sentinel_tilt_since_seconds:-1
- 含义:如果 Sentinel 处于倾斜状态,此项会显示 Sentinel 进入倾斜状态的时间(以秒为单位)。-1 表示当前并没有发生倾斜状态。
\4. sentinel_running_scripts:0
- 含义:当前是否有 Sentinel 脚本正在运行,值为 0 表示没有脚本在运行。
\5. sentinel_scripts_queue_length:0
- 含义:当前 Sentinel 脚本队列的长度,这个值通常与脚本的执行相关,值为 0 表示当前没有脚本排队。
\6. sentinel_simulate_failure_flags:0
- 含义:表示是否模拟了故障发生的标志,如果值为 0,表示没有故障模拟。如果该值为 1,则表示当前模拟了故障情形。
\7. master0:name=mymaster,status=ok,address=192.168.80.11:6379,slaves=2,sentinels=3
-
含义:
-
- name=mymaster:表示这个主节点的名称是
mymaster,这是你在 Sentinel 配置中定义的主节点名称。 - status=ok:表示主节点的当前状态是 "ok",即主节点运行正常。
- address=192.168.80.11:6379:表示这个 Redis 主节点的 IP 地址和端口是
192.168.80.11:6379。 - slaves=2:表示该主节点有 2 个从节点。
- sentinels=3:表示当前有 3 个 Sentinel 实例在监控这个主节点。
- name=mymaster:表示这个主节点的名称是
总结:
这个 Redis Sentinel 集群的当前状态是:
- 有 1 个主节点被监控,主节点名称为
mymaster。 - 主节点的状态正常,IP 地址为
192.168.88.101:6379。 - 有 2 个从节点和 3 个 Sentinel 节点在监控主节点。
- Sentinel 集群本身没有发生故障状态,系统正常运行。
这些信息是了解当前 Sentinel 集群健康状态的重要依据;如果主节点发生故障,Sentinel 会自动执行故障转移过程,将一个从节点提升为新的主节点。
在三台Linux机器上,互相测试哨兵通信
# 都安装 telnet
dnf install -y telnet
# 互相 telnet 26379
telnet 192.168.80.11 26379
telnet 192.168.80.12 26379
telnet 192.168.80.13 26379


按 Ctrl + ] 退出到 telnet> 模式,然后 \q 退出来。
至此,哨兵通信验证成功,集群验证成功!
7. 故障模拟
7.1. 手动关闭 master 服务
观察所有节点的哨兵日志
tail -50f /usr/local/redis/logs/sentinel.log
在 master 节点上,手动关闭 Master Redis
# 手动停止
redis-cli -p 6379
auth redis666
shutdown
# 如果以上操作没有正常停止redis服务,请按照以下操作进行:
systemctl stop redis
[root@server1 ~]# redis-cli
127.0.0.1:6379> auth redis666
OK
127.0.0.1:6379> shutdown
not connected>
[root@server1 ~]# systemctl status redis
○ redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disabl>
Active: inactive (dead) since Mon 2026-05-18 22:26:13 CST; 10s ago
Duration: 10min 57.743s
Process: 11129 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis>
Main PID: 11131 (code=exited, status=0/SUCCESS)
CPU: 3.087s
5月 18 22:15:16 server1 systemd[1]: Starting redis-server...
5月 18 22:15:16 server1 systemd[1]: Started redis-server.
5月 18 22:26:13 server1 systemd[1]: redis.service: Deactivated successfully.
5月 18 22:26:13 server1 systemd[1]: redis.service: Consumed 3.087s CPU time.
[root@server1 ~]#
sentinel 在监听 master 确实是断线了之后,将会开始计算权值,然后重新分配主服务器。

查看状态,发现已经发生故障转移,另外一台机器升级为主节点
redis-cli -p 26379 info sentinel



一旦failover发生时,系统会自动调整2个文件,redis.conf更改主节点信息,sentinel.conf最末端会写入一些选举等信息。
7.2. 重连 master 后的角色定位
可能有同学会疑惑:当原主节点(Master)故障恢复后,能否重新夺回“老大”身份,继续主导集群?
答案很明确:不能!
同理,在 Redis 主从架构中:
原主节点恢复后,会以“从节点(Slave/Replica)”的身份加入集群,自动连接当前的主节点(即故障期间接管的新主节点),并同步其最新数据。
它不会主动挑战新主节点的地位,也不会尝试夺回原有的主节点角色。
原因倒很简单 —— 不想再折腾
Redis 的高可用机制(如哨兵或集群模式)会通过 选举和一致性判断 确保集群的稳定。新主节点已承担了数据同步和请求处理的职责,若原主节点随意“复位”,可能导致数据冲突或同步混乱。
[root@server1 ~]# systemctl restart redis
[root@server1 ~]# systemctl status redis
● redis.service - redis-server
Loaded: loaded (/etc/systemd/system/redis.service; enabled; preset: disabl>
Active: active (running) since Mon 2026-05-18 22:31:49 CST; 13s ago
Process: 15910 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis>
Main PID: 15911 (redis-server)
Tasks: 6 (limit: 22926)
Memory: 7.5M
CPU: 59ms
CGroup: /system.slice/redis.service
└─15911 "/usr/local/redis/bin/redis-server 0.0.0.0:6379"
5月 18 22:31:49 server1 systemd[1]: Starting redis-server...
5月 18 22:31:49 server1 systemd[1]: Started redis-server.
[root@server1 ~]#
[root@server1 ~]# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.80.12:6379,slaves=2,sentinels=3
127.0.0.1:26379>
[root@server1 ~]# redis-cli
127.0.0.1:6379> auth redis666
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:192.168.80.12
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:275063
slave_repl_offset:275063
slave_priority:100
slave_read_only:0
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:0bd2b53b0860f44585b692ec112e51e3284b3b68
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:275063
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:250339
repl_backlog_histlen:24725
127.0.0.1:6379>
[root@server1 ~]#
二、Redis 集群
目标:掌握 Redis 集群配置 + 区分 Redis 哨兵与集群区别
相同点:都是基于主从模式
哨兵:针对主从高可用架构,发现 master 主节点故障,哨兵实现自动切换(10-30s)=> 1主1从或1主多从
集群:针对主从高可用架构,发现 master 主节点故障,不需要切换;因为在整个集群中,多主多从,某个节点出现故障,不影响整个集群使用,所以响应速度特别快。
1. 什么是 Redis 集群
2018年十月 Redis 发布了稳定版本的 5.0 版本,推出了各种新特性,其中一点是放弃 Ruby 的集群方式,改为使用 C 语言编写的 redis-cli 的方式,使集群的构建方式复杂度大大降低。
关于集群的更新可以在 Redis5 的版本说明中看到,如下:
The cluster manager was ported from Ruby (redis-trib.rb) to C code inside redis-cli. check redis-cli --cluster help for more info.
可以查看Redis官网查看集群搭建方式,连接如下
https://redis.io/topics/cluster-tutorial
注:实际运维工作中,大概需要3台机器,每台机器2个节点。详细规划主从关系,尽量不要把一组主从放在同一台服务器中。
Redis01 Redis02 Redis03
1主 1从
2主 2从
3主 3从
Redis 集群原理
Redis 集群采用去中心化架构,通过哈希槽分片将数据分散到多个节点。整个集群共有 16384 个槽,每个键根据 CRC16 哈希算法分配到特定槽中,不同节点负责不同范围的槽。客户端访问时,如果键不在当前节点,节点会返回重定向信息引导客户端访问正确节点。
集群中每个主节点都有对应的从节点,主节点负责读写,从节点复制数据并在主节点故障时自动接替,实现高可用。节点间通过 Gossip 协议相互通信,维护集群状态。这种设计使 Redis 集群能够水平扩展、自动故障转移,并保持高性能。
2. Linux服务器环境概览
系统信息
- 操作系统: CentOS Stream release 9
- 主机用途: Redis集群环境
主机详细配置
| 主机名称 | IP地址 |
|---|---|
| redis01.itcast.cn | 192.168.80.11 |
| redis02.itcast.cn | 192.168.80.12 |
| redis03.itcast.cn | 192.168.80.13 |
网络环境
- 网段:
192.168.80.0/24 - 可用IP范围:
192.168.80.11-192.168.80.13
主机名配置(每台主机分别执行)
hostnamectl set-hostname redis01.itcast.cn && bash
hostnamectl set-hostname redis02.itcast.cn && bash
hostnamectl set-hostname redis03.itcast.cn && bash
主机名解析配置
在每台主机的 /etc/hosts 文件中添加:
cat >/etc/hosts<<EOF
192.168.80.11 redis01 redis01.itcast.cn
192.168.80.12 redis02 redis02.itcast.cn
192.168.80.13 redis03 redis03.itcast.cn
EOF
3. 下载 Redis 源码并编译安装
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
tar xvf redis-7.4.0.tar.gz
cd redis-7.4.0
yum install epel-release -y
yum install make gcc jemalloc jemalloc-devel -y
make
make install PREFIX=/usr/local/redis
echo 'PATH=$PATH:/usr/local/redis/bin/' >> /etc/profile && source /etc/profile
redis-cli -v
mkdir -p /usr/local/redis/conf
cp /root/redis-7.4.0/redis.conf /usr/local/redis/conf/
sed -i '/^\s*#/d; /^$/d' /usr/local/redis/conf/redis.conf
vim /usr/local/redis/conf/redis.conf
bind 127.0.0.1 -::1 --> bind 0.0.0.0
protected-mode yes --> protected-mode no
daemonize no --> daemonize yes
logfile "/usr/local/redis/logs/redis.log"
#过量使用内存设置为1
vm.overcommit_memory 的 3 种模式
0(默认)内核根据启发式算法决定是否允许超分配“看情况给,不一定准”
1允许内存超分配,不做任何限制想分就分,不管你有没有这么多内存
2严格限制,不允许超分配非常安全,但可能导致程序申请内存失败
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sysctl -p
redis-server /usr/local/redis/conf/redis.conf
ps aux|grep redis
redis-cli
info
# redis-cli shutdown
4. Redis 集群配置(单节点,了解即可)
4.1. 创建配置文件
注:6个配置文件不能在同一个目录,此处我们定义如下:
mkdir -p /redis/conf/700{1..6}
/redis/conf/7001/redis.conf
/redis/conf/7002/redis.conf
/redis/conf/7003/redis.conf
/redis/conf/7004/redis.conf
/redis/conf/7005/redis.conf
/redis/conf/7006/redis.conf
4.2. 配置文件内容
port 7001 #端口
cluster-enabled yes #启用集群模式
cluster-config-file nodes_7001.conf
cluster-node-timeout 5000 #超时时间
appendonly yes
daemonize yes #后台运行
protected-mode no #非保护模式
pidfile /var/run/redis_7001.pid
注:其中 port 和 pidfile 需要随着文件夹的不同递增,一键配合脚本
#!/bin/bash
for i in $(seq 7001 7006)
do
cat > /redis/conf/$i/redis.conf <<EOF
port $i
cluster-enabled yes
cluster-config-file nodes_$i.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
protected-mode no
pidfile /var/run/redis_$i.pid
EOF
done
4.3. 启动节点
#!/bin/bash
for i in $(seq 7001 7006)
do
/usr/local/redis/bin/redis-server /redis/conf/$i/redis.conf
done
4.4. 启动集群
/usr/local/redis/bin/redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1
至此,Reids7 集群搭建完成。
测试:
/usr/local/redis/bin/redis-cli -c -p 7001
注:一定要添加-c选项,否则redis-cli默认启动是不以集群方式启动
4.5. 关闭集群
方法一:
/usr/local/redis/bin/redis-cli -p 7001 shutdown
/usr/local/redis/bin/redis-cli -p 7002 shutdown
/usr/local/redis/bin/redis-cli -p 7003 shutdown
/usr/local/redis/bin/redis-cli -p 7004 shutdown
/usr/local/redis/bin/redis-cli -p 7005 shutdown
/usr/local/redis/bin/redis-cli -p 7006 shutdown
方法二:
echo 7001 7002 7003 7004 7005 7006 | xargs -n1 -I{} /usr/local/redis/bin/redis-cli -p {} shutdown
-n :表示每次执行命令时传递的参数个数
-n1:表示每次只传递 1 个参数 给后续命令
-I :用于指定一个占位符(通常用 {}),后续命令中可以通过占位符引用输入参数
示例: 输入数据为 1 2 3 4,执行 echo 命令:
echo "1 2 3 4" | xargs -n1 echo "Number:"
Number: 1
Number: 2
Number: 3
Number: 4
不加 -n1 时,默认所有参数一次性传递:
echo "1 2 3 4" | xargs echo "Numbers:"
Numbers: 1 2 3 4
5. Redis 集群配置(多节点,重点)
主机名解析配置
在每台主机的 /etc/hosts 文件中添加:
cat >/etc/hosts<<EOF
192.168.80.11 redis01 redis01.itcast.cn
192.168.80.12 redis02 redis02.itcast.cn
192.168.80.13 redis03 redis03.itcast.cn
EOF
5.1. Redis 集群实现
第一步:环境规划(3主3从,对外提供服务的一共是3个节点)
前提:Redis集群往往在搭建环境时必须要提前设计,而且Redis集群要求,在创建集群之前,不能有任何数据!
systemctl restart redis
systemctl status redis
redis-cli
flushall
| 编号 | 主机名称 | IP地址 | 角色 |
|---|---|---|---|
| 1 | redis01.itcast.cn | 192.168.80.11 | redis7001 |
| 2 | redis01.itcast.cn | 192.168.80.11 | redis7002 |
| 3 | redis02.itcast.cn | 192.168.80.12 | redis7003 |
| 4 | redis02.itcast.cn | 192.168.80.12 | redis7004 |
| 5 | redis03.itcast.cn | 192.168.80.13 | redis7005 |
| 6 | redis03.itcast.cn | 192.168.80.13 | redis7006 |
改主机名
hostnamectl set-hostname redis01.itcast.cn && bash
hostnamectl set-hostname redis02.itcast.cn && bash
hostnamectl set-hostname redis03.itcast.cn && bash
第一步:在/usr/local/redis/conf目录中创建redis7001.conf...redis7006.conf
redis01 => redis7001.conf
redis01 => redis7002.conf
redis02 => redis7003.conf
redis02 => redis7004.conf
redis03 => redis7005.conf
redis03 => redis7006.conf
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7001.conf # redis01
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7002.conf # redis01
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7001.conf # redis01
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7002.conf # redis01
cat /usr/local/redis/conf/redis7001.conf # redis01
cat /usr/local/redis/conf/redis7002.conf # redis01
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7003.conf # redis02
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7004.conf # redis02
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7003.conf # redis02
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7004.conf # redis02
cat /usr/local/redis/conf/redis7003.conf # redis02
cat /usr/local/redis/conf/redis7004.conf # redis02
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7005.conf # redis03
cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis7006.conf # redis03
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7005.conf # redis03
sed -i '/^\s*#/d; /^\s*$/d' /usr/local/redis/conf/redis7006.conf # redis03
cat /usr/local/redis/conf/redis7005.conf # redis03
cat /usr/local/redis/conf/redis7006.conf # redis03
第二步:把Redis01、Redis02、Redis03机器上的所有Redis全部停止,删除或移除所有默认配置文件redis.conf
systemctl stop redis # 注意:一定要执行这个停止Redis服务的操作!
systemctl disable redis
ps aux|grep redis
rm -rf /usr/local/redis/conf/redis.conf
或者
mv /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak
节点配置:
vim /usr/local/redis/conf/redis7001.conf
bind 0.0.0.0
protected-mode no
port 7001
cluster-enabled yes
cluster-config-file nodes_7001.conf
cluster-node-timeout 5000
daemonize yes
pidfile /var/run/redis_7001.pid
logfile "/usr/local/redis/logs/redis.log"
appendonly yes
[root@redis01 ~]# vim /usr/local/redis/conf/redis7001.conf
[root@redis01 ~]# cat /usr/local/redis/conf/redis7001.conf
bind 0.0.0.0
protected-mode no
port 7001
cluster-enabled yes
cluster-config-file nodes_7001.conf
cluster-node-timeout 5000
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
pidfile /var/run/redis_7001.pid
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
locale-collate ""
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
set-max-listpack-entries 128
set-max-listpack-value 64
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
[root@redis01 ~]#
vim /usr/local/redis/conf/redis7002.conf
bind 0.0.0.0
protected-mode no
port 7002
cluster-enabled yes
cluster-config-file nodes_7002.conf
cluster-node-timeout 5000
daemonize yes
pidfile /var/run/redis_7002.pid
logfile "/usr/local/redis/logs/redis.log"
appendonly yes
vim /usr/local/redis/conf/redis7003.conf
bind 0.0.0.0
protected-mode no
port 7003
cluster-enabled yes
cluster-config-file nodes_7003.conf
cluster-node-timeout 5000
daemonize yes
pidfile /var/run/redis_7003.pid
logfile "/usr/local/redis/logs/redis.log"
appendonly yes
参考以上配置,准备7004 ~ 7006
注意更改:port、cluster-config-file、pidfile
快速配置(参考)
cp /usr/local/redis/conf/redis7001.conf /usr/local/redis/conf/redis7002.conf
vim /usr/local/redis/conf/redis7002.conf
:%s/7001/7002/g
scp /usr/local/redis/conf/redis7001.conf root@redis02:/usr/local/redis/conf/redis7003.conf
scp /usr/local/redis/conf/redis7001.conf root@redis02:/usr/local/redis/conf/redis7004.conf
vim /usr/local/redis/conf/redis7003.conf
:%s/7001/7003/g
vim /usr/local/redis/conf/redis7004.conf
:%s/7001/7004/g
scp /usr/local/redis/conf/redis7001.conf root@redis03:/usr/local/redis/conf/redis7005.conf
scp /usr/local/redis/conf/redis7001.conf root@redis03:/usr/local/redis/conf/redis7006.conf
vim /usr/local/redis/conf/redis7005.conf
:%s/7001/7005/g
vim /usr/local/redis/conf/redis7006.conf
:%s/7001/7006/g
第三步:配置完成后,启动Reids6个节点
redis-server /usr/local/redis/conf/redis7001.conf # redis01
redis-server /usr/local/redis/conf/redis7002.conf # redis01
redis-server /usr/local/redis/conf/redis7003.conf # redis02
redis-server /usr/local/redis/conf/redis7004.conf # redis02
redis-server /usr/local/redis/conf/redis7005.conf # redis03
redis-server /usr/local/redis/conf/redis7006.conf # redis03
ps aux|grep redis

启动与连接集群实例
[root@redis01 ~]# systemctl stop redis
[root@redis01 ~]# rm -rf /usr/local/redis/conf/redis.conf
[root@redis01 ~]# redis-server /usr/local/redis/conf/redis7001.conf
55571:C 02 Dec 2025 15:14:52.409 # WARNING: Changing databases number from 16 to 1 since we are in cluster mode
[root@redis01 ~]# ps aux|grep redis
root 55572 0.3 0.6 133064 11884 ? Ssl 15:14 0:00 redis-server 0.0.0.0:7001 [cluster]
root 55633 0.0 0.1 6416 2304 pts/0 S+ 15:15 0:00 grep --color=auto redis
[root@redis01 ~]# redis-cli # 这个连接会失败
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
[root@redis01 ~]# redis-cli -p 7001 -c # Redis集群连接方式
127.0.0.1:7001> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:bcd9c41eeaf51331
redis_mode:cluster
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:55572
process_supervised:no
run_id:df54cb08fe95da500b034a9dde57c3e58e62129c
tcp_port:7001
server_time_usec:1764659857777724
[root@redis03 ~]# redis-cli -h 192.168.88.101 -p 7001 -c
192.168.88.101:7001> info
# Server
redis_version:7.4.0
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:bcd9c41eeaf51331
redis_mode:cluster
os:Linux 5.14.0-511.el9.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:55572
process_supervised:no
run_id:df54cb08fe95da500b034a9dde57c3e58e62129c
tcp_port:7001
server_time_usec:1764662637012510
第四步:创建集群(集群最少需要3个主节点)
Redis01 Redis02 Redis03
1主 1从
2主 2从
3主 3从
建议在所有Linux服务器上执行优化系统的命令:
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
modprobe bridge
echo 1 > /proc/sys/net/ipv4/ip_forward
# echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf
sysctl -p
以下命令只需在其中一台Linux服务器上(如 redis01)执行:
redis-cli --cluster create ①主节点 ②主节点 ③主节点 ①从节点 ②从节点 ③从节点
redis-cli --cluster create \
192.168.80.11:7001 \
192.168.80.12:7003 \
192.168.80.13:7005 \
192.168.80.11:7002 \
192.168.80.12:7004 \
192.168.8.13:7006 \
--cluster-replicas 1
redis-cli --cluster create \
192.168.80.11:7001 \ # 主节点1 (redis01)
192.168.80.12:7003 \ # 主节点2 (redis02)
192.168.80.13:7005 \ # 主节点3 (redis03)
192.168.80.11:7002 \ # 从节点1 (redis01)
192.168.80.12:7004 \ # 从节点2 (redis02)
192.168.80.13:7006 \ # 从节点3 (redis03)
--cluster-replicas 1
参数说明:
--cluster create 创建集群,后面跟Redis IP及端口号
--cluster-replicas 1 每个主节点默认都有1个从节点
常见问题:Redis集群要求Redis中不能有数据,包括appendonlydir、dump.rdb、nodes_700x.conf
解决方案:哪个节点报错,就清除哪个节点(以7001为例)
ps -ef | grep redis-server
找到7001对应的进程
kill -9 进程号
rm -rf appendonlydir
rm -rf dump.rdb
rm -rf node_7001.conf
清除完成后,重启Redis
redis-server /usr/local/redis/conf/redis7001.conf
5.2. 测试集群
redis-cli -c -h 主节点IP地址 -p 7001
选项说明:
-c代表以集群的方式进行连接
查看集群状态
cluster info
节点详情与主从关系
cluster nodes
槽位分布详情
cluster slots
当前节点的角色与复制状态
role或info replication
5.3. 关闭集群
以下命令在任意一个节点执行都可以
redis-cli -c -h 192.168.88.101 -p 7001 shutdown # redis01
redis-cli -c -h 192.168.88.101 -p 7002 shutdown # redis01
redis-cli -c -h 192.168.88.102 -p 7003 shutdown # redis02
redis-cli -c -h 192.168.88.102 -p 7004 shutdown # redis02
redis-cli -c -h 192.168.88.103 -p 7005 shutdown # redis03
redis-cli -c -h 192.168.88.103 -p 7006 shutdown # redis03
ps aux|grep redis
5.4. 启动集群
启动步骤非常简单,只需要把每台服务器的各个节点依次启动即可。
redis-server /usr/local/redis/conf/redis7001.conf # redis01
redis-server /usr/local/redis/conf/redis7002.conf # redis01
redis-server /usr/local/redis/conf/redis7003.conf # redis02
redis-server /usr/local/redis/conf/redis7004.conf # redis02
redis-server /usr/local/redis/conf/redis7005.conf # redis03
redis-server /usr/local/redis/conf/redis7006.conf # redis03
ps aux|grep redis
6. Redis 集群核心技术点
6.1. 16384个哈希槽
哈希槽就是 Redis 集群的数据分区单位
简单理解:
- Redis 集群把整个数据空间分成 16384 个固定的小格子(每个格子就是一个哈希槽)
- 每个键通过计算
CRC16(key) % 16384得到一个 0-16383 的数字,决定它进入哪个格子 - 集群中的每个主节点负责管理一部分格子(比如节点A管0-5000号格子,节点B管5001-10000号格子...)
类比理解:
想象一个大型图书馆:
- 16384 个书柜 = 哈希槽
- 每本书(键)根据书名计算放到哪个书柜
- 每个图书管理员(节点)负责管理几个书柜
- 读者要找书时,先算书在哪个书柜,然后找负责那个书柜的管理员
为什么是16384?
- 足够多:确保数据能均匀分布到各个节点
- 不太多:节点间同步槽分配信息时占用合理带宽
- 用 14 位二进制就能表示(2^14=16384)
关键点:客户端访问时,节点会快速算出键在哪个槽,如果这个槽不由自己管理,就告诉客户端“去找XXX节点”。
Redis 集群采用去中心化设计,所有节点地位平等,相互连接并同步集群状态。客户端连接任一节点即可访问整个集群的数据。
集群使用 16384 个哈希槽 进行数据分片。每个键通过 CRC16(key) % 16384 计算所属槽位,集群将槽位分配给各主节点管理。
例如三主集群中:
- 节点A管理槽 0-5460
- 节点B管理槽 5461-10922
- 节点C管理槽 10923-16383
当客户端操作键时,节点会计算键的槽位:
- 若槽位归自己管理,直接执行命令
- 否则返回重定向信息,引导客户端访问正确节点
每个主节点可配置从节点,主节点负责写,数据同步到从节点。主节点故障时,对应从节点自动接替,保证高可用。
集群要求至少**3 个主节点****,**且存活主节点数必须超过半数,否则集群将停止服务。
例如:
- 3 主 3 从:正常
- 1 主 3 从:主节点故障后无法选举新主,集群失效
需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。
3主 3从 = 正常
1主 3从 = 1 < (1+3)/2 = 2 = 集群失效
简单理解:Redis 集群就是一个大仓库,这个仓库中为了方便数据存储,拆分为16384 slot哈希槽。
因为写只和 master 主节点相关,所以16384要被3个 master 拆分
这段不是实际代码,而是示意图,Redis 自动平均分配槽。
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
为什么要分槽?写入一条记录如name:itheima,写入到哪个槽中?
答:分槽目的是为了实现数据最大程度使用,也可以避免数据写入混乱。
写入一条记录如name:itheima,写入到哪个槽中?
在Redis设计过程中,引入了一个crc16函数,用于针对key求解,结果返回一个数字 => crc16(name) = 5000
具体数据写入到哪里 => 哈希求余 => crc16(name) % 3 = 5000 % 3 = 1666(存放槽位置)
6.2. 扩展:添加新节点
第一步:添加新的主节点
redis-cli --cluster add-node 192.168.88.114:7007 192.168.88.101:7001
第二步:修复未完成的槽迁移(若存在)
# 修复 192.168.88.102:7003 的槽 5798
redis-cli -h 192.168.88.102 -p 7003 cluster setslot 5798 stable
# 修复 192.168.88.102:7004 的槽 741 和 3680
redis-cli -h 192.168.88.102 -p 7004 cluster setslot 741 stable
redis-cli -h 192.168.88.102 -p 7004 cluster setslot 3680 stable
第三步:迁移槽到新主节点(自动平衡)
redis-cli --cluster rebalance 192.168.88.101:7001 --cluster-threshold 1
Redis 7 的 rebalance 命令更智能,可能减少人工干预。
第四步:添加从节点 192.168.88.114:7008
# 获取新主节点 ID
NODE_ID_7007=$(redis-cli -h 192.168.88.114 -p 7007 cluster nodes | grep myself | awk '{print $1}')
# 添加从节点并绑定到主节点
redis-cli --cluster add-node 192.168.88.114:7008 192.168.88.101:7001 \
--cluster-slave \
--cluster-master-id $NODE_ID_7007
第五步:验证集群状态
redis-cli --cluster check 192.168.88.101:7001
三、Redis 高级应用场景
1. 分布式锁
- 解决多服务并发访问共享资源问题
- 基于
SETNX或 Redlock 算法实现 - 应用:秒杀库存控制、任务调度防重复执行
2. 消息队列
- 异步任务处理和解耦系统组件
- 使用 List 的
LPUSH/BRPOP或 Stream 类型 - 应用:订单处理、日志收集、邮件发送队列
3. 实时排行榜
- 游戏积分榜、电商销量榜、热搜榜
- 使用 Sorted Set 的
ZADD/ZRANGE操作 - 支持实时更新和多种排名查询
4. 会话共享
- 分布式系统中的用户会话存储
- 替代传统 session 实现无状态服务
- 应用:微服务架构、集群部署的登录状态管理
5. 计数器与限流
- 接口访问频率限制、用户操作次数统计
- 使用
INCR原子操作和过期时间 - 应用:API 限流、短信验证码发送限制
6. 地理位置服务
- 附近的人、附近商家、地理位置围栏
- 使用 GEO 类型的
GEOADD/GEORADIUS命令 - 应用:社交应用、外卖/打车平台、门店搜索
这 6 个场景覆盖了 Redis 在分布式系统、实时应用和业务系统中最核心的高级用法。
总结
一、两种核心模式对比
哨兵模式
核心功能:主从自动故障转移(10-30秒完成切换)
-
架构:1主多从 + 多个哨兵进程
-
原理:哨兵监控主节点,故障时自动选举新主
-
特点:
-
- 解决人工切换主从的痛点
- 配置相对简单
- 数据全量复制,适合中小规模
- 写性能受单主节点限制
集群模式
核心功能:分布式数据存储 + 自动故障转移
-
架构:多主多从(至少3主3从)
-
原理:16384个哈希槽分片 + 去中心化架构
-
特点:
-
- 数据分片存储,支持海量数据
- 自动槽分配和重定向
- 故障转移速度快(秒级)
- 支持水平扩展
二、适用场景选择
选择哨兵模式当:
- 数据量不大(单节点能承载)
- 读多写少,读压力可通过从节点分担
- 追求部署简单,维护成本低
- 对写性能要求不高(单点写)
选择集群模式当:
- 数据量超过单机内存
- 读写压力都很大
- 需要水平扩展能力
- 对高可用性要求极高
三、关键配置要点
共同点:
- 密码安全:主从、哨兵、集群都需要配置密码
- 网络配置:关闭防火墙/配置白名单,节点间互通
- 系统优化:调整
vm.overcommit_memory=1 - 后台运行:设置
daemonize yes
差异点:
# 哨兵关键配置
sentinel monitor mymaster 主IP 主端口 2
sentinel auth-pass mymaster 密码
# 集群关键配置
cluster-enabled yes
cluster-config-file nodes_端口.conf
cluster-node-timeout 5000
四、故障恢复流程
哨兵模式:
主节点故障 → 哨兵检测 → 选举新主 → 从节点切换 → 客户端重连
(10-30秒) (对客户端透明)
集群模式:
主节点故障 → 从节点自动接替 → 槽重新分配
(秒级完成,不影响其他节点)
五、运维注意事项
数据安全:
- 集群创建前确保无残留数据(清除
appendonlydir、dump.rdb、nodes_*.conf) - 定期备份配置和数据
网络要求:
- 所有节点间端口互通(Redis端口 + 集群总线端口=Redis端口+10000)
- 避免跨机房网络延迟
监控指标:
# 哨兵监控
info sentinel
sentinel masters
# 集群监控
cluster info
cluster nodes
cluster slots
role
故障排查:
- 检查节点间网络连通性
- 查看日志文件定位问题
- 使用
redis-cli --cluster check诊断集群健康度,它会自动连接所有节点,检查:
- 所有节点是否可达
- 所有 16384 个槽是否都有节点负责且状态正常
- 主从对应关系是否合理
- 集群配置是否一致
六、总结建议
| 维度 | 哨兵模式 | 集群模式 |
|---|---|---|
| 数据量 | 适合中小数据量 | 适合大数据量 |
| 扩展性 | 垂直扩展(升级硬件) | 水平扩展(增加节点) |
| 复杂度 | 配置简单,易维护 | 配置复杂,维护成本高 |
| 性能 | 单点写入,读可扩展 | 多节点并行写入 |
| 故障切换 | 10-30秒,有短暂不可用 | 秒级切换,影响范围小 |
实践建议:
- 从简单开始:数据量不大时先用哨兵模式
- 规划先行:集群模式需要提前设计节点和分片策略
- 测试验证:生产环境前充分测试故障场景
- **了解场景:**Redis高级应用场景
- 监控到位:配置完善的监控告警体系
Redis的高可用方案选择取决于具体的业务场景、数据规模和运维能力。正确选择并合理配置,才能充分发挥Redis的性能优势,确保业务稳定运行。