在了解 Redis 的主从复制之前,让我们先来理解一下现代分布式系统的理论基石——CAP 原理。
一、CAP 原理
CAP 原理就好比分布式领域的牛顿定律,它是分布式存储的理论基石。自打 CAP 的论文发表之后,分布式存储中间件犹如雨后春笋般一个一个涌现出来。理解这个原理其实很简单,本节我们首先对这个原理进行一些简单的讲解。
网络分区:分布式系统的节点往往都是分布在不同的机器上进行网络隔离开的,这意味着必然会有网络断开的风险,这个网络断开的场景的专业词汇叫着「网络分区」
。
网络分区产生的问题: 在网络分区发生时,两个分布式节点之间无法进行通信,我们对一个节点进行的修改操作将无法同步到另外一个节点,所以数据的「一致性」将无法满足,因为两个分布式节点的数据不再保持一致。除非我们牺牲「可用性」,也就是暂停分布式节点服务,在网络分区发生时,不再提供修改数据的功能,直到网络状况完全恢复正常再继续对外提供服务。
一句话概括 CAP 原理就是——网络分区发生时,一致性和可用性两难全。
二、Redis主从同步
1、主从同步是什么能干嘛?
主从: 很多企业都没有使用到 Redis 的集群,但是至少都做了主从。有了主从,当 master 挂掉的时候,运维让从库过来接管,服务就可以继续,否则 master 需要经过数据恢复和重启的过程,这就可能会拖很长的时间,影响线上业务的持续服务。
数据同步: 主从复制也有人才称之为主从同步,其实两个说的是一个东西,主要是为了避免单节点Redis出现故障而导致服务无法使用,所以采用部署多个节点,虽然是多个节点,但是节点之间的数据是始终是保持同步(一样)的数据
,要新增key/value都新增kev/value,要删除都删除,可以理解为就是克隆!
主从同步主要有两个特点:
Redis满足CAP理论当中的AP
Redis能够保证最终一致性
Redis 同步支持主从同步
和从从同步
,从从同步功能是 Redis 后续版本增加的功能,为了减轻主库的同步负担。后面为了描述上的方便,统一理解为主从同步。
主redis挂掉以后情况会如何?从机是上位还是原地待命?
从挂掉后又恢复了,会继续从主同步数据么?
可以使用 info Replication
命令查看主从复制信息
2、Redis是如何实现数据同步的?
上面只是一个整体的大概流程,下面我们将对增量同步以及全量同步进行详细介绍!
2.1.增量同步
Redis 同步的是指令流
:
注意:因为内存的 buffer 是有限的,所以 Redis 主库不能将所有的指令都记录在内存 buffer 中。Redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。
如果因为网络状况不好,从节点在短时间内无法和主节点进行同步,那么当网络状况恢复时,Redis 的主节点中那些没有同步的指令在 buffer 中有可能已经被后续的指令覆盖掉了,从节点将无法直接通过指令流来进行同步,这个时候就需要用到更加复杂的同步机制 —— 快照同步。
2.2.快照同步
快照同步是一个非常耗费资源的操作:
在整个快照同步进行的过程中,主节点的复制 buffer 还在不停的往前移动,如果快照同步的时间过长或者复制 buffer 太小,都会导致同步期间的增量指令在复制 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有可能会陷入快照同步的死循环。
所以务必配置一个合适的复制 buffer 大小参数,避免快照复制的死循环。
当从节点刚刚加入到集群时,它必须先要进行一次快照同步,同步完成后再继续进行增量同步。
2.3.无盘复制
主节点在进行快照同步时,会进行很重的文件 IO 操作,特别是对于非 SSD 磁盘存储时,快照会对系统的负载产生较大影响。特别是当系统正在进行 AOF 的 fsync 操作时如果发生快照,fsync 将会被推迟执行,这就会严重影响主节点的服务效率。
所以从 Redis 2.8.18 版开始支持无盘复制。所谓无盘复制是指主服务器直接通过套接字将快照内容发送到从节点,生成快照是一个遍历的过程,主节点会一边遍历内存,一边将序列化的内容发送到从节点
,从节点还是跟之前一样,先将接收到的内容存储到磁盘文件中,再进行一次性加载。
2.4.通过Wait 指令保证强一致性
Redis 的复制是异步进行的,wait 指令可以让异步复制变身同步复制
,确保系统的强一致性 (不严格)。wait 指令是 Redis3.0 版本以后才出现的。
wait 提供两个参数,第一个参数是从库的数量 N,第二个参数是时间 t,以毫秒为单位
。它表示等待 wait 指令之前的所有写操作同步到 N 个从库 (也就是确保 N 个从库的同步没有滞后),最多等待时间 t。如果时间 t=0,表示无限等待直到 N 个从库同步完成达成一致。
假设此时出现了网络分区,wait 指令第二个参数时间 t=0,主从同步无法继续进行,wait 指令会永远阻塞,Redis 服务器将丧失可用性。
3、搭建Redis 1主2从
3.1.安装Redis
下面我们来配置1主2从的效果,现实中是需要3台机器的,为了方便,我们就在一台Linux机器上来演示,通过不同的端口来区分机器,3台机器的配置
(1)停止redis
假如linux当中安装的有redis,可以先全部停掉,停止所有的redis命令:
ps -ef | grep redis | awk -F" " '{print $2;}' | xargs kill -9
(2)下载redis,然后将redis上传到opt目录
如果没有安装wget请先安装:
(3)安装redis
要编译 Redis,首先是 tar解压,切换到根目录,然后运行make:
假如make install报如下异常,直接使用make install MALLOC=libc
安装过后你会在src目录中找到几个 Redis 二进制文件,包括:
3.2.创建1主2从配置文件
(1)创建配置文件
我们将三台机器的配置文件都放到/opt/redis-stable/config当中
mkdir /opt/redis-stable/config
cd /opt/redis-stable/config
cp /opt/redis-stable/redis.conf /opt/redis-stable/config/
(2)创建master的配置文件:redis-6379.conf
编辑为如下内容:
#redis.conf是redis原配置文件,内部包含了很多默认的配置,这里使用include将其引用,相当于把redis.conf内容直接贴进来了
include /opt/redis-stable/config/redis.conf
daemonize yes
bind 0.0.0.0
#配置密码
requirepass 123456
dir /opt/redis-stable/config/
logfile /opt/redis-stable/config/6379.log
#端口
port 6379
#rdb文件
dbfilename dump_6379.rdb
#pid文件
pidfile /var/run/redis_6379.pid
(3)创建slave1的配置文件:redis-6380.conf
内容如下,和上面master的类似,多了后面2行配置,主要是指定master的ip和端口以及认证密码。
include /opt/redis-stable/config/redis.conf
daemonize yes
bind 0.0.0.0
requirepass 123456
dir /opt/redis-stable/config/
port 6380
dbfilename dump_6380.rdb
pidfile /var/run/redis_6380.pid
logfile /opt/redis-stable/config/6380.log
#用来指定主机:slaveof 主机ip 端口
slaveof 192.168.0.108 6379
#主机的密码
masterauth 123456
(4)创建slave2的配置文件:redis-6381.conf
include /opt/redis-stable/config/redis.conf
daemonize yes
bind 0.0.0.0
requirepass 123456
dir /opt/redis-stable/config/
port 6381
dbfilename dump_6381.rdb
pidfile /var/run/redis_6381.pid
logfile /opt/redis-stable/config/6381.log
#用来指定主机:slaveof 主机ip 端口
slaveof 192.168.0.108 6379
#主机的密码
masterauth 123456
3.3.启动Redis
(1)关闭防火墙
假如不关闭防火墙,可能会出现windows无法连接我们刚刚在虚拟机安装的redis的情况
(2)启动redis
启动master
启动slave1
启动slave2
若启动有误,大家好好检查下配置,也可以看日志,3台机器启动会在 /opt/redis-stable/config 目录产生日志,如下
可以通过ps -ef|grep redis
查看启动的redis
(3)连接redis
/opt/redis-stable/src/redis-cli -h 127.0.0.1 -p 6379 -a 123456
查看主机信息:info Replication
查询从机slave1的信息
/opt/redis-stable/src/redis-cli -h 127.0.0.1 -p 6380 -a 123456
3.4.验证主从同步效果
在master上面执行下面2个命令
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set name ready
OK
127.0.0.1:6379> set age 30
OK
到slave1上执行下面命令,可以看出来数据已经同步过来了
[root@bogon config]# /opt/redis-stable/src/redis-cli -h 127.0.0.1 -p 6380 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6380> mget name age
1) "ready"
2) "30"
同样到slave2上也执行一下,效果如下,注意在从机当中是不允许执行新增修改命令的!
[root@bogon config]# /opt/redis-stable/src/redis-cli -h 127.0.0.1 -p 6381 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6381> mget name age
1) "ready"
2) "30"
127.0.0.1:6381> set aa aa
(error) READONLY You can't write against a read only replica.
3.5.通过命令配置主从关系
上面演示的就是一主二从,不过采用的都是配置文件的方式,实际上从机可以采用命令的方式配置,下面我们来演示一遍,大家看好了。
(1)将redis-6380.conf 和 redis-6381.conf的这两行配置给删掉
#用来指定主机:slaveof 主机ip 端口
slaveof 192.168.0.108 6379
#主机的密码
masterauth 123456
(2)启动三个redis
启动master
启动slave1
启动slave2
(3)分别登陆3台机器,查看各自主从信息
分别登陆对3个redis,然后用 info replication 命令看下3个的主从信息,如下:
(4)配置slave1为master的从库
config set masterauth 123456
slaveof 127.0.0.1 6379
info replication
(5)配置slave2为master的从库
(6)再来看看master的主从信息
注意:通过 slaveof 命令指定主从的方式,slave重启之后主从配置会失效,所以,重启后需要在slave上重新通过 slaveof 命令进行设置,这个不要忘记了。中途通过 slaveof 变更转向,本地的数据会被清除,会从新的master重新同步数据。
3.6.反客为主
当master挂掉之后,我们可以从slave中选择一个作为主机。比如我们想让slave1作为主机,那么可以在slave1上执行下面的命令就可以了。
slaveof no one
这里我通过ps-ef|grep redis
查询出来了6379主节点的进程,然后直接给强制kill
关闭了
此时slave1就变成主机了,然后再去其他slave上面执行 slaveof 命令将其挂在slave1上。
配置slave2为slave1的从库
config set masterauth 123456
slaveof 127.0.0.1 6380
info replication
假如过了一段时间master恢复了,如果还想让他当主,还得将所有redis重启一遍才能让他继续当主。
4、消息丢失
Redis 主从采用异步复制,意味着当主节点挂掉时,从节点可能没有收到全部的同步消息,这部分未同步的消息就丢失了。如果主从延迟特别大,那么丢失的数据就可能会特别多。Sentinel 无法保证消息完全不丢失,但是也尽可能保证消息少丢失。它有两个选项可以限制主从延迟过大。
min-slaves-to-write 1
min-slaves-max-lag 10
5、主从模式不足
主从模式并不完美,它也存在许多不足之处,下面做了简单地总结:
下面来介绍另外一种方式:哨兵模式,主挂掉之后,自动从slave中选举一个作为主机,自动实现故障转移。
版权声明:本文内容始发于CSDN>作者:怪 咖@,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
始发链接:https://blog.csdn.net/weixin_43888891/article/details/131039418
在此特别鸣谢原作者的创作。
此篇文章的所有版权归原作者所有,商业转载建议请联系原作者,非商业转载请注明出处.