最近和一个读者聊天,弟弟很郁闷,公司的Redis宕机了,线上业务受到影响,老板很生气,弟弟担心会不会被辞退!出于好奇,问小弟Redis主节点挂了,还有备用机。它将如何影响业务?小弟说他们的系统架构只部署了Redis单实例。节点挂掉,数据丢失。好了,既然提到了备份,那么今天,我们就来说说Redis的主从同步。首先,什么是主从?Master-slave也叫主从集群,部署了多个Redis实例,如下图所示:其中,每个实例都有自己专属的职责:主库:负责接收从库的读操作和写操作:定时同步主库数据,对外提供读操作。好奇的宝宝们可能会问,为什么奴隶库不能写呢?考虑到数据合并的复杂性,如果一个key多次更新,每次操作都在不同的实例中进行,为了保证数据的全局一致性,需要加全局锁。确保基于最新数据的集群范围的序列化操作和更新的成本仍然很高。以降低系统复杂度,节约成本。主从同步架构方案一般是写在主库上,从库上读。分工明确,责任单一。可能有同学会提到RedisCluster模式,这是另外一种设计方案。水平分割法中通过CRC16(key)算法将数据分割成若干个instance。每个实例只读写自己负责的slot中的数据,从而分担集群的压力。这是另一种玩法,本期不再深入探讨。为了保证数据不丢失,Redis提供了两种数据同步方式:RDB、全量数据同步AOF、增量数据同步、回放日志,两者有什么区别?什么时候使用关系数据库?什么时候使用AOF?接下来,我们将逐步展开分析。建立主从关系首先启动两个redis实例,IP地址分别为192.168.0.1和192.168.0.2。一开始,他们之间没有任何关系。我们通过终端命令登录192.168.0.2机器,执行命令:replicaof192.168.0.16379此时,192.168.0.2实例成为192.168.0.1的从库。主从实例关联完成后,接下来就是进入数据同步环节。主从同步主从库数据同步分为三步:第一步:从库(192.1768.0.2)向主库(192.168.0.1)发送psync命令,参数有两个(主库的runID库和同步进度偏移量)。第一次建立连接时,从库不知道主库的runID,所以会设置为?。offset=-1,表示第一份。注意:每个Redis实例在初始启动时,会自动生成一个随机ID来标识当前实例。主库收到psync请求后,会响应FULLRESYNC,带两个参数(主库的runID和同步进度偏移量)。说明:FULLRESYNC表示使用完整拷贝。第二步:主库fork子进程,执行bgsave命令,生成RDB文件;主库将RDB文件发送给从库;收到从库的响应后,会先清空当前数据库,再加载RDB文件。注意:主库生成RDB文件时,主线程处于阻塞状态,不对外提供服务。RDB文件一旦生成,在数据同步过程中不受影响,主库可以对外提供服务。随后的写命令数据将存储在复制缓冲区中。Step3:主库向从库发送增量写入命令,从库以投影方式执行这些命令,从而实现主从同步。至此,主从的核心逻辑就基本讲完了。但是在生产环境中,通常是一主多从。每个从库在初始同步的时候,主库都要生成一个RDB文件,这显然是非常昂贵的。解决办法是什么?一主多从,主库解压当有多个从节点时,主库压力明显增加,体现在两个方面:从库同步主库时,需要fork子进程。有多少从节点需要fork多少个子进程,每个子进程都要生成RDB。导致主库系统压力过大。生成的RDB需要同步到从库,占用网络带宽。基于以上困境,演化出一种新的模式,即“主-从-从”模式。具体玩法如下:虽然有四个从库,但是只有192.168.0.2和192.168.0.3两个实例,大大减轻了主库的压力。一切都不是一成不变的,网络传输存在很大的风险。突然断网怎么办?两种方式:完全同步和增量同步。全量同步就是同步RDB文件,那么增量同步是如何实现的呢?这里引入了一个buffer,repl_backlog_buffer,它是一个循环设计,增量命令首先存放在这个buffer中。主存储库有一个生产偏移量,称为master_repl_offset。从库中有一个pull偏移量,称为slave_repl_offset。一般情况下,master_repl_offset和slave_repl_offset的大小接近,也就是说主从库之间的数据几乎是同步的。每次同步数据时,从库向主库发送psync命令,同时向主库发送自己的slave_repl_offset,主库根据这个偏移位置向从库发送增量数据。这个很容易理解。万无一失吗?因为环形结构,如果主库的生产速度远快于从库的拉取速度,就会出现环路现象。为什么要用戒指?主要目的是回收空间。市场上的行车记录仪和监控设备大多采用循环叠加存储。如果空间已满,最旧的数据将被覆盖。虽然可能会丢失一些数据,但它具有成本效益。回到上面的问题,被困了怎么办?如上图所示,从库的psync命令请求偏移量为4,但是master节点已经产生了15,之前的1、2、3、4、5都被Overwritten了。这就傻眼了,需要同步的数据被覆盖了,麻烦大了。。。解决办法有两种:①增大repl_backlog_buffer缓冲区的大小,由repl_backlog_size参数控制。缓冲区空间大小=主库写入速度*OpSize-从库拉取速度*OpSize。这是我们可以主观控制的。比如担心大促造成流量高峰,可以将这个值增加2倍、3倍、4倍。您可以根据自己的业务情况自由设置。②另一种方式是Redis本身提供的解决方案,此时会触发全量复制,这与第一次建立主从关系来同步数据是一样的。通过全卷的方式,一次弥补主从之间的大数据缺口。主节点宕机了怎么办如果只是传统意义上的主从模式,主节点宕机了,切换一般都是手动完成的。效率是不言而喻的,尤其是在线生产系统,根本无法接受这种方案。这时候就需要引入sentinel机制,可以实现主从库的自动切换,有效解决failover。整个过程分为三个阶段:MonitoringMasterelectionNotificationmonitoring:sentinel进程会周期性的向所有的主库和从库发送PING命令,检测机器是否处于服务状态。如果在设定时间内没有收到回复,则判定为离线。当然,也有可能因为网络抖动而误判。如何避免?引入sentinel集群,多个sentinel实例一起判断,减少误判率。判断标准是如果有n个哨兵实例,至少有n/2+1个判断是一致的,那么就可以得出结论。选主:主要看各个节点的打分。评分规则分为从库优先级、从库拷贝进度、从库ID号。只要有一轮,就会选举得分最高的一个从库为主库:从库的优先级主要是考虑不同的机器可能配置不同。配置高的机器优先级高,由slave-priority配置决定。从库拷贝的进度主要取决于slave_repl_offset的值。值越大,同步的数据越多,得分越高。从库ID号。每个Redis实例启动时,都会生成一个ID。在优先级和复制进度相同的情况下,ID号最小的从库得分最高,将被选为新的主库。通知:将选举后的新主库发送给所有节点,让所有从库执行replicaof命令,与master建立主从关系,同步数据复制。另外,最新的主库信息会同步到客户端。作者:汤姆哥前阿里P7技术专家编辑:陶家龙来源:转载自公众号微科技(ID:weiguanjishu)
