前言

上节我们讲到RDBAOF的末尾有提到,这两种方式都是在同一台机器上进行读写操作,如果在高并发下对于服务器将是很大考验,所以一般都是实现读写分离,Master主机专门负责写,Slave负责读,并建议将让Slave实现RDB持久化,而通过让Master实现AOF持久化,这么一来就减少了同一台机器的压力,变相的提升了系统的性能。
因此本节会重点介绍Redis的Master/Slave主从复制,并结合案例和图形详细的进行讲解~



文章目录

  • 前言
  • 什么是Master/Slave主从复制
  • 主从分离

  • 关于主从复制实验的几个小问题
  • 薪火相传
  • 反客为主
  • 复制的原理
  • 哨兵模式
  • 什么是哨兵模式
  • 使用哨兵模式模拟从机上位



什么是Master/Slave主从复制

Master/Slave主从复制,说白了就是一主多从,主子就是皇上,从就是仆人,皇帝地下的臣子千千万,后宫佳丽三千!甚是羡慕… 咳咳。皇上的任务是啥?就是每天下达各种指令,让底下的仆人们去做,仆人是不能修改皇帝的奏折吧?Master/Slave主从复制亦是如此,Master只管写,Slave只管读就完事儿了。

通过这种方式解决了单台主机读并发量过大,进而演变为系统崩溃,以及单机版的Redis 挂掉之后无人顶替的情况。

如果我们又要求高并发又要求安全 ,就要通过主从模式来处理。因此在redis 3.0以后,官方发布了集群方案帮我们解决这些问题。以下是官网对于集群方案的说明。

redis 多master 配置 redis的master_redis


官网所介绍的复制的概念,也就是我们所说的主从复制,简单来说,就是主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。

使用主从复制的主要作用有两点:读写分离容灾恢复
从字面意思上也很好理解,读写分离就是我们刚才提到的,Master专门负责写入数据(一般是添加、修改、删除等操作),而Slave专门负责读取数据。
所谓容灾恢复,就是当灾难发生,比如说当机器出现宕机、停电等一些无法预知的问题发生时,通过我们上节学到的Redis持久化方案,来实现数据的恢复。


主从分离

那说了这么多,咱们直接来实操一下好了,通过栗子演示,大家应该会更容易去理解主从复制。

第一步:拷贝多个redis.conf文件
首先在/usr/local/路径下创建文件夹master-slave并拷贝多个redis.conf文件到该目录下,分别取名为redis6379.conf redis6379.conf redis6379.conf,在文件后加上的四位数字分别代表这三个Redis稍后被启动时所使用的port端口号。

#创建master-slave文件夹,并拷贝多个redis.conf文件到该目录下
[root@localhost local]# cd /usr/local/
[root@localhost local]# mkdir master-slave
[root@localhost local]# cd master-slave/
[root@localhost master-slave]# cp /root/myredis/redis.conf ./redis6379.conf
[root@localhost master-slave]# cp /root/myredis/redis.conf ./redis6380.conf
[root@localhost master-slave]# cp /root/myredis/redis.conf ./redis6381.conf
#编辑这三个conf文件
[root@localhost master-slave]# vim redis6379.conf 
[root@localhost master-slave]# vim redis6380.conf 
[root@localhost master-slave]# vim redis6381.conf

第二步:修改redis.conf文件
首先让三个文件都开启daemonize yes,代表这几个Redis都是在后台运行

################################# GENERAL #####################################

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes

接着分别修改三个redis.conf文件的Pid文件名字

pidfile /var/run/redis_6379.pid
pidfile /var/run/redis_6380.pid
pidfile /var/run/redis_6381.pid

然后指定相应的port运行端口

port 6379
port 6380
port 6381

分别指定Log文件名称

logfile "redis6379.log
logfile "redis6380.log
logfile "redis6381.log

最后再分别指定各个文件的dump.rdb名字

dbfilename "dump6379.rdb"
dbfilename "dump6380.rdb"
dbfilename "dump6381.rdb"

第三步:演示一主二仆

接下来咱们使用刚刚写好的配置文件,分别启动这三个Redis,我现在的想法是将redis6379作为主机,redis6380redis6381作为从机,因为条件有限,所以这三台机器都在一台电脑上… 实际情况肯定是运行在不同的主机上的,大家凑合凑合。

redis 多master 配置 redis的master_主从复制_02

redis 多master 配置 redis的master_redis 多master 配置_03


redis 多master 配置 redis的master_Redis_04


启动完成之后,我们可以使用info replication指令查看当前运行的Redis的细节,通过以下信息不难看出,目前三台PC都是master,也就是说默认启动Redis之后,当前PC会自动成为master,我这里做了一个小实验,在redis6379主机中执行set name marco,让后尝试在另外两台主机获取name的值。很显然,是失败的…

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:b7804f0084e7cde40e146c67b23099b14bd4dd8f
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
127.0.0.1:6379> set name marco
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_replid:b429378ea42f464e34535addf544bdf7be1968eb
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
127.0.0.1:6380> get name
(nil)
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_replid:abcdcb5b9fe5da6ac27dfb9adb2070d475635329
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
127.0.0.1:6381> get name
(nil)

那怎么让另外两台主机成为redis6379的从机呢?
这就要使用到下面的slaveof关键字了,注意我们秉承的原则是配主不配从,就是说只有在需要变成从机的PC下执行以下命令,才会使其成为slave。

127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK

执行以上命令之后我们再来使用info replication查看细节,发现端口为6379的主机依然是master,但是connected_slaves的值变为1了?

redis 多master 配置 redis的master_Redis_05


接着我们再来看6381端口的主机,发现它的角色已经从master转变为slave!

redis 多master 配置 redis的master_主从复制_06


此时我们在6381端口的PC下执行获取name的命令,发现主从机之间已经能够完成通信了!并且成功的获取到值!

127.0.0.1:6381> get name
"marco"
关于主从复制实验的几个小问题

问题一:从机是否可以执行写操作?
这个问题的答案在 Marco’s Java【Redis入门(二) 之 Redis的配置文件详解】 中已经提到过了,不知道大家对redis.conf中下面这个配置还有没有映像。默认的值是yes,由此可见我们的slave是不能执行写操作的。

slave-read-only:配置Redis的Slave实例是否接受写操作,即Slave是否为只读Redis。默认值为yes,因此一般的从机都是只读的,而不能执行任何写的操作,后面我们会详细讲到。

实验结果也证实如此,一旦调用写操作,就会抛出(error) READONLY You can't write against a read only slave异常警告!

127.0.0.1:6381> set name marco
(error) READONLY You can't write against a read only slave.

问题二:主机shutdown后情况如何?从机是上位还是原地待命?
主机挂了之后,是没有消息通知到从机的,因此从机会在原地待命。但是主机宕掉了,我们不能再手动的再去配置吧?特别如果大半夜的,主机宕了,难道要连夜爬起来去该配置吗?很显然这是不科学的… 说什么都不可能让我离开被窝…

因此Redis给我们提供了两种解决方案,一种是我们接下来要讲到的哨兵模式 (不知道为什么一看到这个就想到LOL中的哨兵之殇…) ,其次呢,就是Redis集群,关于集群的知识后面一节会讲到。

问题三:其中一台从机down后情况如何?依照原有它能跟上大部队吗?
我们来测试下,先将从机退出,然后再连接。发现是可以获取 “大部队” 中的值的,这个信息很重要,画个重点,大家也可以思考一下,为何从机再次连上之后,还可以获取 “大部队” 之前的数据,后面分析原理时会解疑。

127.0.0.1:6381> quit
[root@localhost bin]# ./redis-cli -p 6381 shutdown
[root@localhost bin]# ./redis-server /usr/local/master-slave/redis6381.conf
[root@localhost bin]# ./redis-cli -p 6381
127.0.0.1:6381> get name
"marco"

薪火相传

啥是薪火相传?说白了不就是传宗接代吗,讲的这么清新脱俗… 哈哈,没错,其实就跟咱们古代的皇帝一样,皇帝传王位给皇子,皇子当上皇上了,又将王位传给下一代,那么在Redis中,这个皇位就是Master,谁拿到Master头衔,谁就是 “皇上” !

结合Redis中的场景该怎么理解呢?这么做又有什么好处呢?

通俗讲就是上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他Slaves的连接和同步请求,那么该Slave作为了链条中下一个的Master,可以有效减轻Master的写压力。

redis 多master 配置 redis的master_redis 多master 配置_07


如下使用Slaveof 新主库IP 新主库端口方式就可以更改Master,并且可以获取到Master里边所有的数据。比方说此时我让port=6381的redis成为port=6380的的slave,那此时port=6380就有slave和master两种角色了,这个数据分别体现在role:slaveconnected_slaves:1上,role:slave表示它相对于port=6379的主机仍是从机,connected_slaves:1则表示在它的底下还有从机。

127.0.0.1:6381> SLAVEOF 127.0.0.1 6380
OK
127.0.0.1:6381> get name
"marco"

需要注意的是,如果中途变更转向,会清除之前的数据,重新建立拷贝最新的


反客为主

当然 “奴隶” 也有反抗的那一天,想要翻身当 “爸爸” 在程序里只需要一个命令SLAVEOF no one就可以了,但是现实生活中可没那么容易,除非你有很多很多的money,比如说我就可以亲切的称呼马云爸爸!

咳咳… 反客为主其实就是使当前数据库停止与其他数据库的同步,转成主数据库,操作如下。可以看出当一台主机反客为主之后,会回归到当时被创建的最原始状态。

127.0.0.1:6381> SLAVEOF no one
OK
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:0
master_replid:f0ffd97e331c4ccd1e98ef58ca972fb185a8198a
master_replid2:31c29b4d685f120ac4ab432e499e140d6055d1ee
master_repl_offset:70534
second_repl_offset:69980
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:226
repl_backlog_histlen:70309

复制的原理

结合上一节讲到的内容,此时我们再看下面这张图,因该很容易就能懂了。

redis 多master 配置 redis的master_主从复制_08


当Slave启动成功连接到Master之后会发送一个sync同步命令,Master接到命令后会启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,Master将传送整个数据文件(appendonly.aop)到Slave,以完成一次完全同步,Slave则专门负责读取数据,并每隔15min将数据通过RDB的方式备份一次。

主从复制方式又分为全量复制增量复制
全量复制:Slave在接收到Master传递过来的数据库文件数据之后,将其全部存盘并加载到内存中。

增量复制:意思就是,Master会继续收集所修改命令,并将新的收集到的所有修改命令依次传给Slave,完成同步,但是只要是重新连接master,一次完全同步(全量复制)将被自动执行。

主从复制的方式有优点,当然也是有缺点的,由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。所以后面我们会讲到Redis Cluster集群的方式替代它。


哨兵模式

关于哨兵模式,刚刚咱们已经提到过,哨兵模式主要就是为了解决当主机宕机之后,谁来顶替主机位置并成为新的主机的问题。

什么是哨兵模式

简单来说就是反客为主的自动版,能够后台监控主机是否故障,如果故障了,哨兵就会第一时间拿到消息。还是拿皇上举例子,假如皇帝驾崩了,那么皇帝身边的太监总管肯定会拿到第一首消息,然后根据皇帝遗言决定谁是下一任接班人,那么哨兵就等同于太监总管的角色了…
不过在我们这个民主的社会是不容许有这样的世袭制度滴,因此哨兵会根据投票数自动将从库转换为主库,被选举上的从机上位之后称为主机之后,拥有了主机所有的权力和数据,其他从机的master会自动更换。

注意:一组 sentinel 能同时监控多个 Master

使用哨兵模式模拟从机上位

第一步:新建sentinel.conf文件
在自定义的/myredis目录下新建sentinel.conf文件,注意名字绝不能错了!

[root@localhost master-slave]# cd /usr/local/master-slave/
[root@localhost master-slave]# mkdir sentinel.conf
[root@localhost master-slave]# vim sentinel.conf 
[root@localhost master-slave]# cat sentinel.conf 
sentinel monitor host6379  127.0.0.1 6379 1

第二步:配置哨兵,填写内容
使用vim sentinel.conf打开配置文件添加配置内容,格式为sentinel monitor 被监控主机名字(自己起名字) ip地址 端口号 1,最后一个数字不要漏掉了,它表示主机挂掉后让salve投票,根据最终投票选举的结果决定谁来接替成为主机。

sentinel monitor host6379  127.0.0.1 6379 1

第三步:启动哨兵
执行以下命令启动哨兵

[root@localhost master-slave]# /usr/local/redis/bin/redis-sentinel sentinel.conf

启动成功之后会出现以下界面

redis 多master 配置 redis的master_Redis_09


假如我们执行以下命令,模拟主机宕机

127.0.0.1:6379> quit
[root@localhost bin]# ./redis-cli shutdown

此刻哨兵会实时监控咱们的主机状态,如果原有的master挂了,会立即更新,并执行我们上面提到的投票选举的操作。

redis 多master 配置 redis的master_redis 多master 配置_10


此时我们再查看port=6380port=6381会发现port=6380的PC已经选举成为master,成功上位!port=6381的主机上位失败就只能继续做奴隶了…

redis 多master 配置 redis的master_redis 多master 配置_11


redis 多master 配置 redis的master_主从复制_12