Redis进阶篇05 — 复制技术(二)Redis主从复制

主从复制

同 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
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇