主从复制
同 MySQL 一样,为了满足 HA (高可用)特性和容灾备份机制,Redis 也同样支持复制技术。主从同步(主从复制)是基于复制技术实现高可用的其中一个,后面的哨兵(sentinel)和集群(cluster)也是基于复制技术演化而来。
我们常说的主(master)和从(slave)在 MySQL 中是:
- source(早先版本称为 master)
- replica(早先版本称为 slave)
在 Redis 这里的名称会有些不太一样,它们被称为:
- master
- replica
为了和官方的术语保持一致,后面我都会使用 master 和 replica 来说明。同 MySQL 的主从复制一样,Redis 的主从复制也是使用的 异步复制 。有关更多的详细信息,参阅官方文档—— https://redis.io/docs/management/replication/
有关 Redis 的主从复制,你需要知道的:
- 主从复制中,Redis 使用的是 异步复制;
- 一个 master 可以有多个 replica;
- 除了可以将所有的 replica 连接到一个 master 之外,replica 与 replica 之间也是可以采用一种叫做级联式的结构进行连接,此时所有的 sub-replica 将接受与 replica 相同的数据流;
- Redis 的复制是非阻塞式的。这意味着,当一个或多个 replica 执行初始化同步或部分再同步时,master 可以继续处理查询。
- 权限相关。当您的 master 设置了 requirepass 参数的值,那么 replica 需要配置 masterauth 来校验密码,以允许 replica 的访问请求能够到达 master
- 一旦 master 和 replica 连接成功,则 master 可以读写,但 replica 只能读。
- 正常启动时的顺序——先启动 master,再启动 replica。正常关闭时的顺序——先关闭 replica,最后关闭 master。
相关的 Redis 命令
info replication
– 查看有关 master/replica 的信息replicaof
– 动态更改 replica 的复制设置,临时生效。比如 Redis 已经充当了 replica 角色,使用replicaof no one
将关闭复制并同时转换为 master 角色;正常情况下,你可以指定命令的 host port 参数,使当前的 Redis 服务器变更为 replica 角色
基础信息列表
我这里以部署一主两从为例,相关的信息如下表所示:
OS | 环境 | 主机名 | Redis 版本 | IP | 时间同步程序 |
---|---|---|---|---|---|
RL 8.9 | 全新安装 | Master | 7.2.3(源代码) | 192.168.100.3/24 | chrony |
RL 8.9 | 全新安装 | Replica1 | 7.2.3(源代码) | 10.1.1.3/24 | chrony |
RL 8.9 | 全新安装 | Replica2 | 7.2.3(源代码) | 10.1.1.4/24 | chrony |
配置 Master(192.168.100.3/24)
配置时间同步程序
Shell > vim /etc/chrony.conf
server ntp1.tencent.com iburst
server ntp2.tencent.com iburst
server ntp3.tencent.com iburst
server ntp4.tencent.com iburst
...
Shell > systemctl restart chronyd.service
执行 Redis 相关操作
# 下载并解压到指定目录
Shell > wget https://github.com/redis/redis/archive/7.2.3.tar.gz
Shell > tar -zvxf redis-7.2.3.tar.gz -C /usr/local/src/
# 启用相关的存储库并安装相关的依赖包
Shell > dnf config-manager --set-enabled powertools && dnf -y install epel-release
Shell > dnf -y install jemalloc-devel make gcc-c++ python3
Shell > mkdir -p /usr/local/redis/
# 开始编译安装
Shell > cd /usr/local/src/redis-7.2.3/ && make && make PREFIX=/usr/local/redis/ install
# 创建配置文件所在的目录,创建持久化所需要的目录、创建所需要的日志目录
Shell > mkdir /usr/local/redis/config/ && mkdir /usr/local/redis/DB/ && mkdir /usr/local/redis/logs/
## 复制配置文件到目录中
Shell > cp -p /usr/local/src/redis-7.2.3/redis.conf /usr/local/redis/config/
# 一些基本的配置修改工作,这些配置参数代表的含义你应该很清楚了
## 开启的是混合持久化
Shell > vim /usr/local/redis/config/redis.conf
...
bind 192.168.100.3
...
protected-mode no
...
daemonize yes
...
pidfile /var/run/master_6379.pid
...
loglevel notice
logfile /usr/local/redis/logs/master-redis.log
...
dbfilename master-dump.rdb
...
dir /usr/local/redis/DB/
...
requirepass MyPassword
...
rename-command flushall ""
rename-command flushdb ""
...
appendonly yes
appendfilename "master-appendonly.aof"
appenddirname "master-appendonlydir"
...
aof-use-rdb-preamble yes
...
配置完成后,尝试启动:
Shell > /usr/local/redis/bin/redis-server /usr/local/redis/config/redis.conf
Shell > ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:(("chronyd",pid=2012,fd=5))
udp UNCONN 0 0 [::1]:323 [::]:* users:(("chronyd",pid=2012,fd=6))
tcp LISTEN 0 511 192.168.100.3:6379 0.0.0.0:* users:(("redis-server",pid=28866,fd=6))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=734,fd=3))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=734,fd=4))
Shell > tail -n 10 /usr/local/redis/logs/redis.log
1460:C 09 Dec 2023 23:29:49.490 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1460:C 09 Dec 2023 23:29:49.490 * Redis version=7.2.3, bits=64, commit=00000000, modified=0, pid=1460, just started
1460:C 09 Dec 2023 23:29:49.490 * Configuration loaded
1460:M 09 Dec 2023 23:29:49.490 * Increased maximum number of open files to 10032 (it was originally set to 1024).
1460:M 09 Dec 2023 23:29:49.490 * monotonic clock: POSIX clock_gettime
1460:M 09 Dec 2023 23:29:49.491 * Running mode=standalone, port=6379.
1460:M 09 Dec 2023 23:29:49.492 * Server initialized
1460:M 09 Dec 2023 23:29:49.493 * Creating AOF base file master-appendonly.aof.1.base.rdb on server start
1460:M 09 Dec 2023 23:29:49.494 * Creating AOF incr file master-appendonly.aof.1.incr.aof on server start
1460:M 09 Dec 2023 23:29:49.494 * Ready to accept connections tcp
到这里,我们的 Master 配置成功。
配置 Replica1(10.1.1.3/24)
配置时间同步程序
Shell > vim /etc/chrony.conf
server ntp1.tencent.com iburst
server ntp2.tencent.com iburst
server ntp3.tencent.com iburst
server ntp4.tencent.com iburst
...
Shell > systemctl restart chronyd.service
执行 Redis 相关操作
# 下载并解压到指定目录
Shell > wget https://github.com/redis/redis/archive/7.2.3.tar.gz
Shell > tar -zvxf redis-7.2.3.tar.gz -C /usr/local/src/
# 启用相关的存储库并安装相关的依赖包
Shell > dnf config-manager --set-enabled powertools && dnf -y install epel-release
Shell > dnf -y install jemalloc-devel make gcc-c++ python3
Shell > mkdir -p /usr/local/redis/
# 开始编译安装
Shell > cd /usr/local/src/redis-7.2.3/ && make && make PREFIX=/usr/local/redis/ install
# 创建配置文件所在的目录,创建持久化所需要的目录、创建所需要的日志目录
Shell > mkdir /usr/local/redis/config/ && mkdir /usr/local/redis/DB/ && mkdir /usr/local/redis/logs/
## 复制配置文件到目录中
Shell > cp -p /usr/local/src/redis-7.2.3/redis.conf /usr/local/redis/config/
# 基本的配置工作
Shell > vim /usr/local/redis/config/redis.conf
...
bind 10.1.1.3
...
protected-mode no
...
daemonize yes
...
pidfile /var/run/replica1_6379.pid
...
loglevel notice
logfile /usr/local/redis/logs/replica1-redis.log
...
dbfilename replica1-dump.rdb
...
dir /usr/local/redis/DB/
...
replicaof 192.168.100.3 6379 ← 指定 master 的ip和端口
...
masterauth MyPassword ← 指定 master 的认证密码
...
requirepass Replica1Password
...
rename-command flushall ""
rename-command flushdb ""
...
appendonly yes
appendfilename "replica1-appendonly.aof"
appenddirname "replica1-appendonlydir"
...
aof-use-rdb-preamble yes
...
尝试启动并查看日志:
Shell > /usr/local/redis/bin/redis-server /usr/local/redis/config/redis.conf
Shell > ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:(("chronyd",pid=719,fd=5))
udp UNCONN 0 0 [::1]:323 [::]:* users:(("chronyd",pid=719,fd=6))
tcp LISTEN 0 511 10.1.1.3:6379 0.0.0.0:* users:(("redis-server",pid=9856,fd=6))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=734,fd=3))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=734,fd=4))
# 查看日志,有如下的文本提示即表示复制成功
Shell > cat /usr/local/redis/logs/replica1-redis.log
...
9856:S 09 Dec 2023 23:54:32.624 * Connecting to MASTER 192.168.100.3:6379
9856:S 09 Dec 2023 23:54:32.624 * MASTER <-> REPLICA sync started
...
9856:S 09 Dec 2023 23:54:37.083 * MASTER <-> REPLICA sync: Finished with success
...
9856:S 09 Dec 2023 23:54:37.155 * Background AOF rewrite finished successfully
此时的 Replica1 配置完成
配置 Replica2(10.1.1.4/24)
配置时间同步程序
Shell > vim /etc/chrony.conf
server ntp1.tencent.com iburst
server ntp2.tencent.com iburst
server ntp3.tencent.com iburst
server ntp4.tencent.com iburst
...
Shell > systemctl restart chronyd.service
执行 Redis 相关操作
# 下载并解压到指定目录
Shell > wget https://github.com/redis/redis/archive/7.2.3.tar.gz
Shell > tar -zvxf redis-7.2.3.tar.gz -C /usr/local/src/
# 启用相关的存储库并安装相关的依赖包
Shell > dnf config-manager --set-enabled powertools && dnf -y install epel-release
Shell > dnf -y install jemalloc-devel make gcc-c++ python3
Shell > mkdir -p /usr/local/redis/
# 开始编译安装
Shell > cd /usr/local/src/redis-7.2.3/ && make && make PREFIX=/usr/local/redis/ install
# 创建配置文件所在的目录,创建持久化所需要的目录、创建所需要的日志目录
Shell > mkdir /usr/local/redis/config/ && mkdir /usr/local/redis/DB/ && mkdir /usr/local/redis/logs/
## 复制配置文件到目录中
Shell > cp -p /usr/local/src/redis-7.2.3/redis.conf /usr/local/redis/config/
# 基本的配置修改工作
Shell > vim /usr/local/redis/config/redis.conf
...
bind 10.1.1.4
...
protected-mode no
...
daemonize yes
...
pidfile /var/run/replica2_6379.pid
...
loglevel notice
logfile /usr/local/redis/logs/replica2-redis.log
...
dbfilename replica2-dump.rdb
...
dir /usr/local/redis/DB/
...
replicaof 192.168.100.3 6379 ← 指定 master 的ip和端口
...
masterauth MyPassword ← 指定 master 的认证密码
...
requirepass Replica2Password
...
rename-command flushall ""
rename-command flushdb ""
...
appendonly yes
appendfilename "replica2-appendonly.aof"
appenddirname "replica2-appendonlydir"
...
aof-use-rdb-preamble yes
...
尝试启动并查看日志:
Shell > /usr/local/redis/bin/redis-server /usr/local/redis/config/redis.conf
Shell > ss -tulnp
# 查看日志,有如下的文本提示即表示复制成功
Shell > cat /usr/local/redis/logs/replica2-redis.log
...
9957:S 10 Dec 2023 00:22:14.317 * MASTER <-> REPLICA sync started
9957:S 10 Dec 2023 00:22:14.318 * Non blocking connect for SYNC fired the event.
...
9957:S 10 Dec 2023 00:22:19.114 * MASTER <-> REPLICA sync: Finished with success
...
9957:S 10 Dec 2023 00:22:19.149 * Background AOF rewrite terminated with success
此时的 Replica2 配置完成
排错
您可以从这几个方面来查阅错误:
- 查阅 master 的 Redis 日志;查阅 replica 的 Redis 日志
- 使用相关的 Redis 命令
- 网络
- 防火墙配置
- SeLinux
对于 master 角色,info repolication
命令的正常的输出内容如下:
192.168.100.3:6379> info replication
# Replication
role:master ← 所扮演的角色为 master
connected_slaves:2 ← 拥有 2 个 replica
slave0:ip=10.1.1.3,port=6379,state=online,offset=126,lag=1 ← replica 的信息以及状态
slave1:ip=10.1.1.4,port=6379,state=online,offset=126,lag=0 ← replica 的信息以及状态
master_failover_state:no-failover
master_replid:46cd664c523fd4b3e8bb9aeb628d8be45951d12f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:126
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:126
对于 replica 角色,info repolication
命令的正常的输出内容如下:
10.1.1.3:6379> info replication
# Replication
role:slave ← 所扮演的角色为 slave
master_host:192.168.100.3
master_port:6379
master_link_status:up ← 与 master 的连接状态为 up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_read_repl_offset:336
slave_repl_offset:336
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:46cd664c523fd4b3e8bb9aeb628d8be45951d12f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:322
Q&A
Q:建立了主从关系后,master 真的可以读写吗?replica 只能读吗?
是的。
Shell(Master)> /usr/local/redis/bin/redis-cli -h 192.168.100.3 -p 6379 -a MyPassword
192.168.100.3:6379> set product redis
OK
Shell(Replica1)> /usr/local/redis/bin/redis-cli -h 10.1.1.3 -p 6379 -a "Replica1Password"
10.1.1.3:6379> keys *
1) "product"
10.1.1.3:6379> get product
"redis"
10.1.1.3:6379> set version 7
(error) READONLY You can't write against a read only replica.
Q:当其中一个 replica 因不可抗拒的因素宕机了,在宕机后, master 写入的数据会因为 replica 恢复后重新同步吗?
是的。
# 假设 Replica1 的 Redis 宕机了
Shell(Replica1)> killall redis-server
# 在 Replica1 宕机之后,Master 执行的命令
192.168.100.3:6379> set name PC
OK
# 重新恢复 Replica1 的 Redis
Shell(Replica1)> /usr/local/redis/bin/redis-server /usr/local/redis/config/redis.conf
Shell(Replica1)> /usr/local/redis/bin/redis-cli -h 10.1.1.3 -p 6379 -a "Replica1Password"
10.1.1.3:6379> keys *
1) "product"
2) "name"
Q:当 master 的 Redis 宕机了,会出现什么情况?
各个 replica 会继续等待 master 的恢复。
# 假设 Master 的 Redis 宕机了
Shell(Master) > killall redis-server
# 在 Replica1 上查看复制有关的信息
10.1.1.3:6379> info replication
# Replication
role:slave ← 扮演角色未发生变化
master_host:192.168.100.3
master_port:6379
master_link_status:down ← 主从连接的状态变更为 down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_read_repl_offset:2079
slave_repl_offset:2079
master_link_down_since_seconds:11
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:46cd664c523fd4b3e8bb9aeb628d8be45951d12f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:2079
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1688
repl_backlog_histlen:392
版权声明:「自由转载-保持署名-非商业性使用-禁止演绎 3.0 国际」(CC BY-NC-ND 3.0)
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论