为了进一步提高Redis的并发能力,我们需要搭建主从集群,实现读写分离。
主服务器:可以进行读写操作,并将写操作同步给从服务器。
从服务器:只能进行读操作,接收主服务器同步的写操作命令,并且执行该操作。
谁是主节点,谁是从节点
我们可以使用replicaif命令形成主服务器和从服务器之间的关系
例如服务器B执行:replicaif A的ip地址 A的Redis端口号
A是master,B是slave
全量同步
主从第一次连接时,会执行全量同步,将master节点的所有信息拷贝给slave节点
具体流程如下:
第一阶段:协商同步
- slave执行replicaof请求连接,向master发送同步请求。
- master判断是否为第一次同步,若是,将master的所有数据信息(也就是replid和offset这些)返回给slave。
第二阶段:发送数据
- master执行bgsave生成RDB快照。
- 向slave发送RBD文件。
- slave清空本地数据,加载RDB快照。
在此期间master会把新的写操作命令放到replication buffer缓冲区中,等下一阶段同步给slave。
第三阶段:同步新数据
- master将replication buffer中 新的写操作命令发送给slave。
- slave执行新命令。
命令传播
在主从服务器完成同步后,双方会建立一个TCP连接,主服务器的写操作命令通过这个连接传播给从服务器,从服务器执行新的写操作命令实现主从同步。
增量复制
如果主从服务器突然断开导致数据不一致,但从服务器中还是有主服务器的部分数据,我们就没必要再全量同步,而是使用增量同步只更新主从中有差异的数据。
第一阶段:协商同步
- slave重启后向master发送同步请求,发送replid和offset给master。
- master得知offset不是-1后就知道不是第一次同步,所以发送continue给slave。
第二阶段:更新数据
- 在repl_baklog(repl_baklog记录了Redis的命令日志和slave和master的offset)中将offset后面的写操作命令发送给slave。
- slave执行命令。
一些问题
master如何判断slave是第一次连接:
slave发送请求时携带replication ID (服务器唯一id,同一个数据集的话id一样)和offset(偏移量),slave如果是第一次发起同步的话发送的是自己的replid和offset,master检查到replid跟自己不一样就知道是全量复制。然后master就会把自己的replid和offset发给slave,让slave的replid跟master一样了。
master如何知道slave是需要增量复制:
如果slave之前已经全量同步过master的数据了,那么slave的偏移量offset不为-1,在发送请求时master看到slave的offset不为-1后,就判断这次需要的是增量复制。
什么情况下不能增量复制:
增量复制的命令日志存放在repl_baklog中,repl_baklog是一个环形的数组,保存了master的offset和slave的offset,当master的offset超过了slave的offset时,说明此时一些未同步的写操作命令已经丢失了,所以增量复制就会导致数据不一致。
优化手段
-
适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
-
限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力