ithuang
ithuang
发布于 2025-10-12 / 2 阅读
0

非关系型数据库 Redis 进阶

非关系型数据库 Redis 进阶

一、Redis 哨兵

之前主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。

这不是一种推荐的方式,更多时候,我们优先考虑**哨兵(Sentinel, [ˈsentɪnl], 森特尼尔)**模式。

1. 什么是哨兵

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

非关系型数据库 Redis 进阶1.png

2. 哨兵的作用

这里的哨兵有两个作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

非关系型数据库 Redis 进阶2.png

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)通知客户端(透明化)

  1. 哨兵集群通过 发布订阅模式(Pub/Sub) 广播主节点变更信息,所有连接的客户端(如应用程序)收到通知后,自动将请求路由到 新主节点,对业务代码无感知(故障切换对客户端透明)。

3. 部署实战

环境准备

配置3个哨兵和1主2从的Redis服务器来演示这个过程。

服务类型是否是主服务器IP地址端口备注
Redis 1是192.168.88.1016379
Redis 2否192.168.88.1026379
Redis 3否192.168.88.1036379
Sentinel 1-192.168.88.10126379同 Redis 1
Sentinel 2-192.168.88.10226379同 Redis 2
Sentinel 3-192.168.88.10326379同 Redis 3

特别注意:使用Redis哨兵模式,最少需要3个节点(一主多从结构),这样至少能部署3 个哨兵进程,从而保证共同投票选出新的主节点。

Redis 哨兵模式的核心功能是监控主从节点状态,并在主节点故障时自动完成**故障切换(Failover),**这一过程依赖多个哨兵节点的协同投票。

非关系型数据库 Redis 进阶3.png

一主两从配置

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 进阶4.png

安装成功后,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>

测试主节点写入,从节点复制

非关系型数据库 Redis 进阶5.png

我们如果需要设置读写分离,只需要在 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

非关系型数据库 Redis 进阶6.png

非关系型数据库 Redis 进阶7.png

[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

非关系型数据库 Redis 进阶8.png

6.5. 验证测试

在所有的机器上校验密码

# grep 全局检索 .conf 后缀文件
grep -n 'redis666' /usr/local/redis/conf/*.conf

非关系型数据库 Redis 进阶9.png

为主节点和从节点配置密码

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 进阶10.png

在任意一个哨兵节点上,执行

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 实例在监控这个主节点。

总结:

这个 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

非关系型数据库 Redis 进阶11.png

非关系型数据库 Redis 进阶12.png

按 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 进阶13.png

查看状态,发现已经发生故障转移,另外一台机器升级为主节点

redis-cli -p 26379 info sentinel

非关系型数据库 Redis 进阶14.png

非关系型数据库 Redis 进阶15.png

非关系型数据库 Redis 进阶16.png

一旦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.cn192.168.80.11
redis02.itcast.cn192.168.80.12
redis03.itcast.cn192.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地址角色
1redis01.itcast.cn192.168.80.11redis7001
2redis01.itcast.cn192.168.80.11redis7002
3redis02.itcast.cn192.168.80.12redis7003
4redis02.itcast.cn192.168.80.12redis7004
5redis03.itcast.cn192.168.80.13redis7005
6redis03.itcast.cn192.168.80.13redis7006

改主机名

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

非关系型数据库 Redis 进阶17.png

启动与连接集群实例

[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个哈希槽分片 + 去中心化架构

  • 特点:

    • 数据分片存储,支持海量数据
    • 自动槽分配和重定向
    • 故障转移速度快(秒级)
    • 支持水平扩展

二、适用场景选择

选择哨兵模式当:

  • 数据量不大(单节点能承载)
  • 读多写少,读压力可通过从节点分担
  • 追求部署简单,维护成本低
  • 对写性能要求不高(单点写)

选择集群模式当:

  • 数据量超过单机内存
  • 读写压力都很大
  • 需要水平扩展能力
  • 对高可用性要求极高

三、关键配置要点

共同点:

  1. 密码安全:主从、哨兵、集群都需要配置密码
  2. 网络配置:关闭防火墙/配置白名单,节点间互通
  3. 系统优化:调整 vm.overcommit_memory=1
  4. 后台运行:设置 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

故障排查:

  1. 检查节点间网络连通性
  2. 查看日志文件定位问题
  3. 使用 redis-cli --cluster check 诊断集群健康度,它会自动连接所有节点,检查:
  • 所有节点是否可达
  • 所有 16384 个槽是否都有节点负责且状态正常
  • 主从对应关系是否合理
  • 集群配置是否一致

六、总结建议

维度哨兵模式集群模式
数据量适合中小数据量适合大数据量
扩展性垂直扩展(升级硬件)水平扩展(增加节点)
复杂度配置简单,易维护配置复杂,维护成本高
性能单点写入,读可扩展多节点并行写入
故障切换10-30秒,有短暂不可用秒级切换,影响范围小

实践建议:

  • 从简单开始:数据量不大时先用哨兵模式
  • 规划先行:集群模式需要提前设计节点和分片策略
  • 测试验证:生产环境前充分测试故障场景
  • **了解场景:**Redis高级应用场景
  • 监控到位:配置完善的监控告警体系

Redis的高可用方案选择取决于具体的业务场景、数据规模和运维能力。正确选择并合理配置,才能充分发挥Redis的性能优势,确保业务稳定运行。