redis主从结点的必要性,一般来说我们为了防止redis主结点宕机没法立即恢复数据都会对单节点redis做主从结构,另外我们做主从结构也可以做读写分离,提高其吞吐量
读写分离提高吞吐量,单机5W并发能力情况下,则该主从结构可以达到5w写,20w读
但是用redis主从结构我们就要明白redis主从结构数据同步的原理了。
为了让redis支持数据的弱一致性即最终一致性,我们不需要保证master和slave的数据是同步的,但是过了一段时间,他们的数据是最终同步
slave node内部有个定时任务
,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接(关于连接ip,slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始,master host和ip是从哪儿来的,redis.conf里面的slaveof配置的)ping
命令给master node口令/密码认证
,如果master设置了口令(密码) requirepass
,那么salve node必须发送master auth的口令过去进行认证Salve主动
发送sync
命令到MasterSYNC
命令后,会异步开一个线程
开始执行BGSAVE
命令生成RDB文件
并使用缓冲区
记录此后执行
的所有写命令;(默认:如果rdb复制时间超过60秒(repl-timeout
),那么slave node就会认为复制失败,可以适当调节大
这个参数,对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s)BGSAVE执行完后
,向所有从服务器发送快照文件
,并在发送期间继续记录被执行的写命令;保存到磁盘
上,然后加载
文件到内存
恢复数据快照到Salve的Redis上
(client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败)Salve完成数据快照的恢复后
,Master将这期间缓冲区收集的写命令发送给Salve进行回放 BGREWRITEAOF
,重写AOF 后续Master收集到的写命令
都会通过之前建立的连接
,增量
发送给salve端Redis全量同步后,新数据同步
到从结点的方式,或者全量同步中断
后进行主从数据同步的方式都为增量复制
backlog中获取部分丢失的数据
,发送给slave node,默认backlog就是1MBslave发送的psync中的offse
t来从backlog中获取数据的offset
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master
,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
master node有一个backlog,默认是1MB大小
master node给slave node 复制数据时
,也会将数据在backlog中同步写一份
backlog
主要是用于全量复制中断后
的增量复制,引用:backlog
backlog
和 offset
的断点续传
从redis 2.8
开始,就支持主从复制的断点续传
,如果主从复制过程中,网络连接断掉了
,那么可以接着上次复制的地方,继续复制
下去,而不是从头开始复制一份 ,master node
会在内存
维护一个backlog
,master和slave都会保存一个replica offset
还有一个master id
,offset就是保存在backlog中的
。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制.
但是如果没有找到对应的offset,那么就会执行一次resynchronization
master直接在内存中创建rdb
,然后发送给slave
,不会在自己本地落地磁盘了
开启方式
repl-diskless-sync no //设置开启关闭,默认关闭
repl-diskless-synd-delay 5 //设置等待时间等待一定时长再开始复制,因为最好一次复制中更多结点的同步机会。如果等到更多slave重新连接过来可以一次复制同步更多结点,减少生成rdb的次数。
info server
,可以看到master run id
每个Redis服务器都会有一个表明自己身份的ID,这就是run id . 在主从复制时候如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分
, run id不同就做全量复制.
为什么说主从复制时候这里根据host+ip定位master node,是不靠谱的?因为有的时候我们发现master结点数据错误要恢复到20小时之前的数据,那么这个时候run id变了,数据变了,但是其host和ip是没变的,如果我们还拿着之前的offset进行同步肯定会出现问题,所以即使host和ip没变,当run id变化的时候,我们就要知道数据已经变了,我们就要进行全量复制了。 如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
Redis采用了乐观复制的策略
,也就是在一定程度内容忍主从数据库的内容不一致
,但是保持主从数据库数据的最终一致性
。上面第六点也说了,Redis在主从复制的过程中,本身就是异步的,在主从数据库执行完客户端请求后会立即将结果返回给客户端,并异步的将命令同步给从数据库,但是这里并不会等待从数据库完全同步之后,再返回客户端。 这一特性虽然保证了主从复制期间性能不受影响,但是也会产生一个数据不一致的时间窗口,如果在这个时间窗口期间网络突然断开连接,就会导致两者数据不一致。
如果不在配置文件中添加其他策略,那就默认会采用这种方式,乐观二字也就体现在这里。 当然了,上面这种方式并不是绝对的
,只要牺牲
一点性能
,还是可以避免
上述问题。在配置文件中:
代表
至少N台从服务器完成复制,才允许主服务器可写入,否则会返回错误。
min-slaves-to-write
3 #允许从服务器断开连接的时间(单位s) min-slaves-max-lag 10