本文章首发自本人公众号:壹枝花算不算浪漫,如若转载请标明来源!java
感兴趣的小伙伴可关注我的公众号:壹枝花算不算浪漫node
前面已经学习了Redis的持久化方式,接下来开始学习Redis主从架构的原理,来看看Redis如何利用主从架构来保证高并发的。redis
单机的redis通常QPS不会超过超过10万+,通常单机QPS都在几万左右,若是须要支撑高并发,咱们能够将Redis作成主从架构来支持读写分离。数据库
主从架构 -> 读写分离 -> 支撑10万+读QPS缓存
当启动一个slave node的时候,它会发送一个PSYNC命令给master node网络
若是这是salve node重复你给你链接master node,那么master node仅仅会复制给slave部分缺失的数据;不然若是是slave node第一次链接master node,那么会触发一次full resynchronization架构
开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的全部写命令缓存在内存中。并发
RDB文件生成完毕以后,master将这个RDB发送给slave,salve会先写入本地磁盘,而后再从本地磁盘加载到内存中。less
接着master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。异步
slave node若是跟master node有网络故障,断开了链接,会自动重连。
从redis 2.8以后,就支持主从复制的断点续传,若是主从复制过程当中,网络链接断掉了,那么能够接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node会在内存中建立一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。若是master和slave网络链接断掉了,slave会让master从上次的replica offseet开始继续复制
可是若是没有找到对应的offset,那么就会执行一次full resynchronization
master在内存中直接建立rdb,而后发送给slave,不会在本身的本地落地磁盘了
// 默认不使用diskless同步方式,能够改为yes
repl-diskless-sync yes
// 无磁盘diskless方式在进行数据传递以前会有一个时间的延迟,以便slave端可以进行到待传送的目标队列中,这个时间默认是5秒
repl-diskless-sync-delay 5
复制代码
slave不会过时key,只会等待master过时key。若是master过时了一个key,或者经过LRU淘汰了一个key,那么会模拟一条del命令发送个slave。
以上的执行流程如图:
具体流程以下:(如下内容参考自: blog.csdn.net/houjixin/ar…)
全备份过程当中,在slave启动时,会向其master发送一条SYNC消息,master收到slave的这条消息以后,将可能启动后台进程进行备份,备份完成以后就将备份的数据发送给slave,初始时的全同步机制是这样的:
上述函数调用过程以下图1所示:
Redis的正常部署中通常都是一个master用于写操做,若干个slave用于读操做,另外按期的数据备份操做也是单独选址一个slave完成,这样能够最大程度发挥出redis的性能。在部署完成,各master\slave程序启动以后,首先进行第一阶段初始化时的全同步操做,全同步操做完成以后,后续全部写操做都是在master上进行,全部读操做都是在slave上进行,所以用户的写操做须要及时扩散到全部的slave以便保持数据最大程度上的同步。Redis的master-slave进程在正常运行期间更新操做(包括写、删除、更改操做)的同步方式以下:
master接收到一条用户的操做后,将调用函数call函数来执行具体的操做函数(此过程可参考另外一文档《redis命令执行流程分析》),在该函数中首先经过proc执行操做函数,而后将判断操做是否须要扩散到各slave,若是须要则调用函数propagate()来完成此操做。
propagate()函数完成将一个操做记录到aof文件中或者扩散到其余slave中;在该函数中经过调用feedAppendOnlyFile()将操做记录到aof中,经过调用replicationFeedSlaves()将操做扩散到各slave中。
函数feedAppendOnlyFile()中主要保存操做到aof文件,在该函数中首先将操做转换成redis内部的协议格式,并以字符串的形式存储,而后将字符串存储的操做追加到aof文件后。
函数replicationFeedSlaves()主要将操做扩散到每个slave中;在该函数中将遍历本身下面挂的每个slave,以此对每一个slave进行以下两步的处理:将slave的数据库切换到本操做所对应的数据库(若是slave的数据库id与当前操做的数据id不一致时才进行此操做);将命令和参数按照redis的协议格式写入到slave的回复缓存中。写入切换数据库的命令时将调用addReply,写入命令和参数时将调用addReplyMultiBulkLen和addReplyBulk,函数addReplyMultiBulkLen和addReplyBulk最终也将调用函数addReply。
在函数addReply中将调用prepareClientToWrite()设置slave的socket写入事件处理函数sendReplyToClient(经过函数aeCreateFileEvent进行设置),这样一旦slave对应的socket发送缓存中有空间写入数据,即调用sendReplyToClient进行处理。
函数sendReplyToClient()的主要功能是将slave中要发送的数据经过socket发出去。
第一次slave链接master的时候,执行的是全量复制,这个过程当中有些细节的机制
master和slave都会维护一个offset
master会在自身不断累加offset,slave也会在自身不断累加offset。slave每秒都会上报本身的offset给master,同时master也会保存每一个slave的offset。
offset并非只用在全量复制中,主要是master和slave都要知道各自的数据offset,才能知道互相之间数据不一致的状况
backlog机制
master node有一个backlog,默认大小是1M,master node给slave node复制数据时,也会将数据backlog中同步写一份,backlog主要是用来作全量复制中断时候的增量复制
master run id
在redis中执行info server命令,能够看到master run id,若是根据host+ip定位master node,是不许确的,若是master node重启或者数据出现了变化,那么slave node应该根据不一样的run id区分,run id不一样就作全量复制。 若是须要不更改run id重启redis,可使用redis-cli debug reload命令
psync命令
从节点使用psync从master node进行复制,psync runid offset,master node会根据自身的状况返回响应信息,多是FULLRESYNC runid offset触发全量复制,多是CONTINUE触发增量复制
heatbeat机制
主从节点互相都会发送heartbeat信息,master默认每隔10秒发送一次heartbeat,slave node每隔1秒发送一个heartbeat