一、概念
主从复制,是指将一台Redis服务器上的数据,复制到其他的redis服务器。前者称为主节点,后者称为从节点。(Master/Slave) 数据的复制是单向的,只能从主节点到从节点。主节点以写为主,从节点以读为主。
默认情况下,每台redis服务器都是主节点。一个主节点可以有多个从节点,但一个从节点只能有一个主节点
二、集群搭建
1. copy 配置文件
cp redis.conf 6379redis.conf
cp redis.conf 6380redis.conf
cp redis.conf 6381redis.conf
2. 在每个conf文件修改如下配置
//表示指定Redis以守护进程的方式启动
daemonize yes
//表示当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/redis/run/redis_6379.pid 文件里面
pidfile /var/run/redis_6379.pid
//配置端口 port
port 6379
//配置log 文件名字
logfile "6379.log"
//配置rdb文件名
dbfilename dump_6379.rdb
3. 开启服务器
redis-server 6379redis.conf
redis-server 6380redis.conf
redis-server 6381redis.conf
使用ps -ef | grep redis 查看服务是否开启
4. 建立主从关系
可以使用info replication来查看服务器信息
值得注意的是:刚开启的服务器都是主节点,我们需要对其进行主动配置
使用:slaveof [hostname] [port]
类似的设置服务器6381
得到主节点6379:
这种配置在服务重启后将不存在,如果想要永久保存,可以使用conf文件配置的方式来进行配置文件
slaveof [host] [port]
三、主从复制的过程
1. 完整的主从复制
-
同步:将从服务器当前的状态,更新为主服务器当前的状态,也就是使用主服务器中存储的数据,替换掉从服务器的数据;
- slave 服务启动,slave 会建立和 master 的连接,发送 sync 命令。
- master 执行bgsavae 指令 fork()一个子进程去生成Redis当前状态的一个快照,在这个过程中,新到达主服务器的写指令将会被记录在缓冲区。
- 主服务器执行完BGSAVE后,将快照文件发送给从服务器,在发送的过程中,如果还有新的写指令到达,也会继续记录在缓冲区;从服务器接收到主服务器发来的快照文件后,将丢弃自己内存中的数据,开始加载快照文件中记录的数据,加载完成后,就可以处理接收到的请求了。
- 主服务器在发送完快照文件后,开始将缓冲区中记录的写指令也同步到从服务器;从服务器接收到主服务器发来的指令,便依次执行这些指令,执行完后,就与主服务器的状态一致了
-
命令传播:主服务器执行每一次修改操作后,都需要告知从服务器,让从服务器执行相同的操作,以保证一致性
主服务器每次执行写操作,都会将这个写指令发送给从服务器,从服务器接收到后,也执行这个写指令,这样就能让主服务器和从服务器持续的保持一致。
2. 部分的主从复制
假设一台从服务器已经与主服务器完成了同步,进入了命令传播阶段,但是由于某些原因,主从服务器之间的网络连接断开了,从服务器在一段时间后,重新连接上了主服务器。按理来说,从服务器和主服务器断开连接的这段时间,没有同步对主服务器的写操作,此时它们已经不一致了,那么从服务器需要重新执行一次主从复制,这又是一次非常耗时的操作。而Redis2.8之后,提供了一种优化机制,若在上面的情况发生时,如果满足某些条件(具体条件之后叙述),可以不进行一次完整的主从复制,而是只同步断开连接的这段时间里,没有同步的操作,这就是部分重同步
Redis2.8之后,提供了一个新的指令来实现部分重同步,这个指令就是PSYNC。从2.8开始,实现主从复制使用的就不是SYNC了,而是PSYNC,它可以算是SYNC的升级版本。PSYNC支持两种模式:
- 完整重同步:如果Redis判断当前从服务器需要与主服务器重新进行一次完整的主从复制,则PSYNC指令将执行与SYNC指令完全一样的操作,上面已经描述过了,这里就不重复叙述了;
-
部分重同步
若从服务器与主服务器断线重连后,满足某些条件,则不进行完整重同步,而是只同步断线过程中,没有同步的部分;
部分重同步的实现原理
- 服务器的运行id;
- 主服务器的复制积压缓冲区;
- 主从服务器的复制偏移量;
1)服务器的运行 id
每一台服务器都会被分配一个运行id,用来标识服务器的身份。从服务器在与一台主服务器连接后,会记录主服务器的id。从服务器与主服务器断开后,可能会重新连接一台主服务器,但是并不一定就是原来的那一台。当从服务器连接到一台主服务器后,会向主服务器发送自己记录的主服务器id,主服务器判断这是不是自己,如果是,表明从服务器之前连接的就是自己,则有可能可以使用部分重同步机制,否则,将重新进行一次完整同步。
2)主服务器的复制积压缓冲区
首先,复制积压缓冲区是一个固定长度,先进先出的队列,默认 1MB。主服务器在接收到用户发来的写指令时,不仅仅会将写指令发送给从服务器进行同步,同时还会将这个指令放入到复制积压缓冲区中,目的是在从服务器没有成功接收到的时候能够重传。复制缓冲区的结构大致如下:
可以看到,对于复制积压缓冲区中的每一个字节,都有一个对应的偏移量。如果当前缓冲区已经满了,但是又有新的指令需要放入其中,则会将最先放入其中的指令移除,腾出足够空间后,将新指令放入(先入先出),所以,缓冲区中能够存储的指令是有限的。
3)主从服务器的复制偏移量
主服务器和从服务器会分别维护自己的复制偏移量,主服务器每发送出一个字节,主服务器偏移量就+1,而从服务器每完成一个字节的同步,从服务器偏移量就+1。
什么情况下会触发部分重同步呢?
若从服务器与主服务器断开连接,并重新连接到同一个主服务器后,会将自己记录的复制偏移量发送给主服务器,主服务器判断这个偏移量之后的所有字节,是否还在复制缓冲区中,如果在,则表明可以进行部分重同步,将复制缓冲区中,这个偏移量之后的所有字节发送给从服务器;若不完全包含,则表明从服务器需要同步的数据,有一部分无法在缓冲区中找到,此时就需要进行一次完整同步。