Redis学习二:Redis高并发之主从模式

申明

本文章首发自本人公众号:壹枝花算不算浪漫,如若转载请标明来源!java

感兴趣的小伙伴可关注我的公众号:壹枝花算不算浪漫node

22.jpg

前言

前面已经学习了Redis的持久化方式,接下来开始学习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
复制代码

过时key处理

slave不会过时key,只会等待master过时key。若是master过时了一个key,或者经过LRU淘汰了一个key,那么会模拟一条del命令发送个slave。

以上的执行流程如图:

image.jpg

复制的完整流程

  1. slave node在redis.conf中的slaveof配置master的host信息,slave node启动,仅仅是保存了master node信息,此时复制流程并未开始
  2. slave node内部有个定时任务,每秒检查是否有新的master node须要链接和复制,若是发现,就跟master node创建socket网络链接
  3. slave node发送ping的命令给master node
  4. 口令认证,若是master设置了requiresspass,那么slave node必须发送masterauth的口令过去认证
  5. master node第一次执行全量复制,将全部数据发送给slave node
  6. master node后续持续将写命令,异步复制给slave node

具体流程以下:(如下内容参考自: blog.csdn.net/houjixin/ar…)

全量复制

全备份过程当中,在slave启动时,会向其master发送一条SYNC消息,master收到slave的这条消息以后,将可能启动后台进程进行备份,备份完成以后就将备份的数据发送给slave,初始时的全同步机制是这样的:

  1. slave启动后向master发送同步指令SYNC,master接收到SYNC指令以后将调用该命令的处理函数syncCommand()进行同步处理;
  2. 在函数syncCommand中,将调用函数rdbSaveBackground启动一个备份进程用于数据同步,若是已经有一个备份进程在运行了,就不会再从新启动了。
  3. 备份进程将执行函数rdbSave()完成将redis的所有数据保存为rdb文件。
  4. 在redis的时间事件函数serverCron(redis的时间处理函数是指它会定时被redis进行操做的函数)中,将对备份后的数据进行处理,在serverCron函数中将会检查备份进程是否已经执行完毕,若是备份进程已经完成备份,则调用函数backgroundSaveDoneHandler完成后续处理。
  5. 在函数backgroundSaveDoneHandler中,首先更新master的各类状态,例如,备份成功仍是失败,备份的时间等等。而后调用函数updateSlavesWaitingBgsave,将备份的rdb数据发送给等待的slave。
  6. 在函数updateSlavesWaitingBgsave中,将遍历全部的等待这次备份的slave,将备份的rdb文件发送给每个slave。另外,这里并非当即就把数据发送过去,而是将为每一个等待的slave注册写事件,并注册写事件的响应函数sendBulkToSlave,即当slave对应的socket可以发送数据时就调用函数sendBulkToSlave(),实际发送rdb文件的操做都在函数sendBulkToSlave中完成。
  7. sendBulkToSlave函数将把备份的rdb文件发送给slave。

上述函数调用过程以下图1所示:

image.png

数据修改操做的同步

Redis的正常部署中通常都是一个master用于写操做,若干个slave用于读操做,另外按期的数据备份操做也是单独选址一个slave完成,这样能够最大程度发挥出redis的性能。在部署完成,各master\slave程序启动以后,首先进行第一阶段初始化时的全同步操做,全同步操做完成以后,后续全部写操做都是在master上进行,全部读操做都是在slave上进行,所以用户的写操做须要及时扩散到全部的slave以便保持数据最大程度上的同步。Redis的master-slave进程在正常运行期间更新操做(包括写、删除、更改操做)的同步方式以下:

  1. master接收到一条用户的操做后,将调用函数call函数来执行具体的操做函数(此过程可参考另外一文档《redis命令执行流程分析》),在该函数中首先经过proc执行操做函数,而后将判断操做是否须要扩散到各slave,若是须要则调用函数propagate()来完成此操做。

  2. propagate()函数完成将一个操做记录到aof文件中或者扩散到其余slave中;在该函数中经过调用feedAppendOnlyFile()将操做记录到aof中,经过调用replicationFeedSlaves()将操做扩散到各slave中。

  3. 函数feedAppendOnlyFile()中主要保存操做到aof文件,在该函数中首先将操做转换成redis内部的协议格式,并以字符串的形式存储,而后将字符串存储的操做追加到aof文件后。

  4. 函数replicationFeedSlaves()主要将操做扩散到每个slave中;在该函数中将遍历本身下面挂的每个slave,以此对每一个slave进行以下两步的处理:将slave的数据库切换到本操做所对应的数据库(若是slave的数据库id与当前操做的数据id不一致时才进行此操做);将命令和参数按照redis的协议格式写入到slave的回复缓存中。写入切换数据库的命令时将调用addReply,写入命令和参数时将调用addReplyMultiBulkLen和addReplyBulk,函数addReplyMultiBulkLen和addReplyBulk最终也将调用函数addReply。

  5. 在函数addReply中将调用prepareClientToWrite()设置slave的socket写入事件处理函数sendReplyToClient(经过函数aeCreateFileEvent进行设置),这样一旦slave对应的socket发送缓存中有空间写入数据,即调用sendReplyToClient进行处理。

  6. 函数sendReplyToClient()的主要功能是将slave中要发送的数据经过socket发出去。

image.png

数据同步相关核心机制

第一次slave链接master的时候,执行的是全量复制,这个过程当中有些细节的机制

  1. master和slave都会维护一个offset

    master会在自身不断累加offset,slave也会在自身不断累加offset。slave每秒都会上报本身的offset给master,同时master也会保存每一个slave的offset。

    offset并非只用在全量复制中,主要是master和slave都要知道各自的数据offset,才能知道互相之间数据不一致的状况

  2. backlog机制

    master node有一个backlog,默认大小是1M,master node给slave node复制数据时,也会将数据backlog中同步写一份,backlog主要是用来作全量复制中断时候的增量复制

  3. 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命令

  4. psync命令

    从节点使用psync从master node进行复制,psync runid offset,master node会根据自身的状况返回响应信息,多是FULLRESYNC runid offset触发全量复制,多是CONTINUE触发增量复制

  5. heatbeat机制

    主从节点互相都会发送heartbeat信息,master默认每隔10秒发送一次heartbeat,slave node每隔1秒发送一个heartbeat

相关文章
相关标签/搜索