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

主从复制,读写分离,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
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的配置文件复制若干次(要配置的从节点个数):

然后修改每个配置文件中的项目如下:
1 2 3 4
| port 6380 pidfile /var/run/redis_6380.pid logfile "6380.log" dbfilename dump6380.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
| 127.0.0.1:6379> info 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
| 127.0.0.1:6380> info 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
| 127.0.0.1:6381> info 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
|
127.0.0.1:6380> slaveof 127.0.0.1 6379 OK
127.0.0.1:6380> info 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
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
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 3 4 5 6 7 8 9 10 11
| 127.0.0.1:6379> set k1 v1 OK
127.0.0.1:6380> keys * 1) "k1"
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号服务的主节点,打印看它的主从信息。

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
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
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实例。

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

假设主服务器宕机,哨兵1监测到这个结果,系统不会马上进行failover过程,仅仅是哨兵1主观认为主服务器不可用,这个现象称为主观下线,当其他的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover(故障转移)操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的主服务器实现切换主机,这个过程称为客观下线。
测试
采用一主二从的方式。
- 配置哨兵配置文件
sentinel.conf
1 2
| sentinel monitor myredis 127.0.0.1 6379 1
|
后面这个数字1,代表主机挂了,Slave投票让谁接替称为主机,票数最多的,就会成为主机。
- 启动哨兵
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 6546:X 12 Nov 2021 00:57:31.378 6546:X 12 Nov 2021 00:57:31.378 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 6546:X 12 Nov 2021 00:57:31.382 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
|
- 主机6379宕机,此时就会从从机中选择一个服务作为新的Master

此时主机变成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 monitor myredis 127.0.0.1 6380 1
protected-mode no
port 26379 user default on nopass ~* &* +@all
sentinel auth-pass myredis ********
sentinel down-after-milliseconds muredis 30000
sentinel parallel-syncs myredis 1
sentinel notification-script myredis /var/redis/notify.sh
sentinel client-reconfig-script myredis /var/redis/reconfig.sh
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
|