主从复制、读写分离的方式
读写分离指的是什么?
主库既可以负责读操作和写操作,而从库只能进行读操作。由主库将数据同步到从库中。
为什么需要采用读写分离的方式?
如果写操作可以分发到从库上,那么数据同步就是一个很大的问题。比如对一个key进行了三次修改,这三次修改分别是在1号机,2号机,3号机上。那么这三台redis机器中的数据都是不一致的,究竟用谁的进行同步,是个很大的问题。如果要这么设计,就必须得为每一个key的修改设置一个时间,按照时间节点判断谁是最后修改的key,这样显然会增加很多负担。
还有1个问题,在数据没有同步之前,究竟按谁的数据来进行读取呢?因为3台机器上的数据都不一致,这也是个问题。
主从复制的执行阶段:
①首先从库和主库建立连接,发送psync命令,表示要同步主库的数据。
②从库先清空当前的数据(主要是为了保证从库的数据和主库是一致的),第一次同步时,进行的全量复制。主库会执行bgsave的命令,在后台子进程中生成RDB文件,然后将RDB文件发送给从库。
③由于主库没有堵塞,任然可以执行命令。所以主库任然会更新key和增加key,为了不影响数据同步,主库会专门开辟一个缓冲区来写入同步期间接收到的写命令。当RDB文件同步完成后,主库会将数据同步期间接收到的命令发送给从库,从库会执行数据同步期间接收到的数据更改命令。这样就保证了主库与从库之间的数据一致性。
主从复制带来的问题:
虽然主从复制减轻了主库的压力,但是如果从库很多。比如有1个主库,5个从库。
那么主库就要将RDB文件发送给5个从库,这是非常大的压力,会很大程度上占用网络带宽资源。
并且从库很多,主库会经常fork子进程,使用bgsave命令生成RDB文件fork子进程会拷贝父进程的页表,这是非常消耗性能的操作,而且RDB文件是磁盘IO,也是非常影响性能的。
解决的方案:
可以选用"主-从-从"架构模式,将一部分从库的同步请求发送到从库中,用从库中的数据进行同步。
如果主从库之间的网络断开连接,从库重启后,该怎么进行数据同步呢?
在最早期,如果主从库之间断连了,从库重新登录后,将会采取全量复制的模式。非常影响性能。
后来,主库会将断连后所有的写入命令写进replacation buffer中,同时将这些操作命令写入repl_backlog_buffer这个缓冲区。
repl_backlog_buffer:是一个环形缓冲区,主库会记录自己写入的位置,从库会记录自己读取的位置。这个缓冲区只要有从库存在,就会存在!!!!并不是断开连接后才存在,在进行数据同步时,首先将命令发送给从库,然后将这些命令在repl_backlog_buffer中缓存起来。
所以,在从库断开连接重启后,只需要将从库偏移量到主库偏移量这一段之间的命令重新写入就可以完成增量同步了。
但是会有风险:因为这是一个环形缓冲区,如果主库写入的速度非常快,远远超过了从库读入的速度。那么主库的写入就会覆盖当前的数据,导致从库没有办法完成数据的同步,这样就导致了主从库之间数据不一致的问题了!如果从库读入的速度很慢,当前读入位置已经被覆盖掉了,此时会进行全量复制。
解决方案:将repl_backlog_buffer的大小设置大一点,尽量留下比较大的空间,这样就能降低一些主库写入过快,从库跟不上,导致数据不一致的风险。