Redis主从复制
洪笳淏 Lv4

Redis主从复制

概念

  主从复制,是指将一台Redis服务器上的数据,复制到其他的Redis服务器上。前者称为主节点(Master),后者称为从节点(Slave)。数据的复制是单向的,只能从主节点到从节点。Master以写为主,Slave以读为主。

avatar

主从复制,读写分离,80%的情况都是读操作,可以减缓服务器的压力。

  默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。主从复制的作用主要包括:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式;
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余;
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量;
  • 高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

  一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:

  • 从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
  • 从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256GB,也不能将所有的内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20GB

  对于电商网站上的商品,一般都是一次上传,无数次浏览的,也就是“多读少写”。

环境配置(单机上模拟,多机同理)

只配置从库,不用配置主库。

查看当前库的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0 # 没有从机
master_failover_state:no-failover
master_replid:05fce2cd1d05bab4c0c503cb7ef7c5c4c1b445e0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

  将redis的配置文件复制若干次(要配置的从节点个数):

avatar

然后修改每个配置文件中的项目如下:

1
2
3
4
port 6380  # 端口号要改成从服务的节点
pidfile /var/run/redis_6380.pid # pid file也要改成对应的名字
logfile "6380.log" # 日志文件名也要对应
dbfilename dump6380.rdb # rdb文件命名也要修改

然后分别启动主从服务:

1
2
3
redis-server redis-config/redis79.conf
redis-server redis-config/redis80.conf
redis-server redis-config/redis81.conf

查看进程:

1
2
3
4
5
ps -ef | grep redis
501 76856 1 0 12:08上午 ?? 0:00.15 redis-server 127.0.0.1:6379
501 76963 1 0 12:09上午 ?? 0:00.09 redis-server 127.0.0.1:6380
501 77118 1 0 12:09上午 ?? 0:00.02 redis-server 127.0.0.1:6381
501 77166 73157 0 12:09上午 ttys004 0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox redis

一主二从

  默认情况下,redis服务都是主机,一般情况下只需要配置从机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## port 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:35cf0a87f4009c0db73dc38088333e56c6ae4ebd
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
## 6380
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:89cbbf9896b1e99c65b6ce88e7d67af16bbb49f6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
## 6381
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:e0f2e6d24e37f5ce033a886d647c641b10289329
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

  若将6379端口上的服务设为主机,6380、6381端口上的服务为从机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# slaveof [host] [port]

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK

127.0.0.1:6380> info replication
# Replication
role:slave # 角色转变为从机
master_host:127.0.0.1 # 主机地址
master_port:6379 # 主机端口
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:84
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:494f98ba6749c752bb7ff2fb6e47f7c89c5712b8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK

127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:364
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:494f98ba6749c752bb7ff2fb6e47f7c89c5712b8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:364
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:351
repl_backlog_histlen:14

  再查看一下主机(6379)上的主从信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=392,lag=1 # 从机信息
slave1:ip=127.0.0.1,port=6381,state=online,offset=392,lag=1
master_failover_state:no-failover
master_replid:494f98ba6749c752bb7ff2fb6e47f7c89c5712b8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:392
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:392

  真实的主从配置应该在配置文件中配置,这样才是永久的,在redis客户端中通过命令来配置只是暂时的。

在配置文件中:

1
2
################################# REPLICATION #################################
# replicaof <masterip> <masterport> # 在此处配置主机的地址和端口

  在一主二从的配置方式中,主机可以写,从机不能写只能读。主机中的所有信息和数据,都会自动被从机保存。

1
2
3
4
5
6
7
8
9
10
11
### 主机
127.0.0.1:6379> set k1 v1
OK

### 从机1
127.0.0.1:6380> keys *
1) "k1"

### 从机2
127.0.0.1:6381> keys *
1) "k1"

  若尝试在从机中写入:

1
2
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.

  默认情况下,主机断开连接,从机依旧是连接到主机的,但是没有写操作了。当主机重新连回来时,从机依旧可以重新开始接收主机写入的数据。

  如果是使用命令行配置的主从,若主机断开连接,重新连回来仍然是其他从机的主机;若某一个从机断开连接,再连回来就不再是从机了,在其断开连接后主机写入的数据就无法同步了。但只要重新将其设置为原来主机的丛机,马上就会写入主机的全部数据。

复制原理

Slave启动成功连接到master后会发送一个sync同步命令。Master接收到命令,启动后台的存盘进程,同时收集所有接受到的用于修改数据集命令,在后台进程执行完毕之后,Master将传送整个数据文件到Slave,并完成一次完全同步。Slave服务在接收集到数据文件数据后,将其存盘并加载到内存中。Master继续将新的所有收集到的修改命令一次传给Slave,完成同步。但是只要重新连接Master,一次完全同步(全量复制)将被自动执行。

  • 全量复制:Slave在接收到数据文件数据后,将其存盘并加载到内存中
  • 增量复制:继续将新的所有收集到的修改命令一次传给Slave

层层链路

  另一种主从节点的配置方式如下图所示,1号服务既作为0号服务的从节点,也作为2号服务的主节点,打印看它的主从信息。

avater

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:99242
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:494f98ba6749c752bb7ff2fb6e47f7c89c5712b8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:99242
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:99242

  它的身份(role)还是作为从节点,所以是无法写入信息的。此时再向0号节点(Master)写入,1号、2号均能读取0号节点的值。这种形式也能完成主从复制。

  如果此时Master断开,这时候能不能剩下的从节点选出一个作为Master吗?此时需要手动将其中一个从节点设置为主节点,使用slaveof no one让某个Slave变成Master,再其他节点手动连接到这个节点上(变来就以该节点作为Master的从节点不需要设置):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6380> slaveof no one
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=100321,lag=1
master_failover_state:no-failover
master_replid:7f67d870c3fd771f6427ea40516d4e8bdd26ab20
master_replid2:494f98ba6749c752bb7ff2fb6e47f7c89c5712b8
master_repl_offset:100321
second_repl_offset:100308
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:100321

  若原来的Master连回来之后,是不能够再自动将其作为主节点的。它已经被谋朝篡位了!!!!

哨兵模式

  这是一种自动选取Master的模式。主从切换技术的方法是:当主机服务宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。这是一种不推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵模式)架构来解决这个问题。

  谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库切换为主库。哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控多个Redis实例。

avatar

  哨兵有两个作用:

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

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

avatar

  假设主服务器宕机,哨兵1监测到这个结果,系统不会马上进行failover过程,仅仅是哨兵1主观认为主服务器不可用,这个现象称为主观下线,当其他的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover(故障转移)操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的主服务器实现切换主机,这个过程称为客观下线

测试

  采用一主二从的方式。

  1. 配置哨兵配置文件sentinel.conf
1
2
# sentinel monitor 被监控的名称 host port 1
sentinel monitor myredis 127.0.0.1 6379 1

后面这个数字1,代表主机挂了,Slave投票让谁接替称为主机,票数最多的,就会成为主机。

  1. 启动哨兵
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
hongjiahao@Mac  /usr/local/bin  redis-sentinel redis-config/sentinel/sentinel.conf
6546:X 12 Nov 2021 00:57:31.378 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
6546:X 12 Nov 2021 00:57:31.378 # Redis version=6.2.3, bits=64, commit=00000000, modified=0, pid=6546, just started
6546:X 12 Nov 2021 00:57:31.378 # Configuration loaded
6546:X 12 Nov 2021 00:57:31.379 * Increased maximum number of open files to 10032 (it was originally set to 256).
6546:X 12 Nov 2021 00:57:31.379 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.3 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 6546
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

6546:X 12 Nov 2021 00:57:31.382 # Sentinel ID is 4a00c3f869d1b542c0ae2f9c6c26ff69c0ebb5bc
6546:X 12 Nov 2021 00:57:31.382 # +monitor master myredis 127.0.0.1 6379 quorum 1
6546:X 12 Nov 2021 00:57:31.384 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
6546:X 12 Nov 2021 00:57:31.385 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
  1. 主机6379宕机,此时就会从从机中选择一个服务作为新的Master

avater

  此时主机变成6380,若原主机6379重新连上,只能成为新Master的从机

优点

1、哨兵集群,基于主从复制,所有的主从配置优点全有;

2、主从节点可以切换,鼓掌可以转移,系统的可用性会更好;

3、哨兵模式就是主从模式的升级,手动到自动,更加健壮。

缺点:

1、Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦;

2、实现哨兵模式的配置其实很麻烦,里面有很多选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 哨兵sentinel监控的redis主节点的ip port
# master-name 可以自己命名主节点名字。只能由字母A-Z、数字0-9、三个字符“.-_”组成
# quorum 配置多少个sentinel哨兵统一认为master主节点失联,呢么这是客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor myredis 127.0.0.1 6380 1

# Generated by CONFIG REWRITE
protected-mode no

# 哨兵sentinel实例的运行端口 默认26379。 如果有哨兵集群,还需要配置每个哨兵的端口
port 26379
user default on nopass ~* &* +@all

# 当在Redis实例中开启了requirepass foobared 授权密码,这样所有连接Redis实例的客户端都需要提供密码
# 设置哨兵sentinel连接主从的密码,注意必须主从设置一样的验证码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass myredis ********

# 指定多少毫秒之后,主节点没有应答哨兵sentinel。此时哨兵主观认为主节点下线,默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds muredis 30000

# 指定了在发生failover主从切换时每次最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长。
# 但如果这个数字越大,就意味着越多的slave因为replication而不可用
# 可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs myredis 1

# 通知脚本
# sentinel notification-script <master-name> <script-path>
sentinel notification-script myredis /var/redis/notify.sh

# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关客户端master地址已经发生改变的信息
# 以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script myredis /var/redis/reconfig.sh

# 哨兵sentinel的工作目录
dir "/usr/local/bin"

sentinel myid 4a00c3f869d1b542c0ae2f9c6c26ff69c0ebb5bc
sentinel config-epoch myredis 1
sentinel leader-epoch myredis 1
sentinel current-epoch 1
sentinel known-replica myredis 127.0.0.1 6379
sentinel known-replica myredis 127.0.0.1 6381
  • Post title:Redis主从复制
  • Post author:洪笳淏
  • Create time:2021-11-09 23:21:00
  • Post link:https://jiahaohong1997.github.io/2021/11/09/Redis主从复制/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments