大致流程:主库将变更写binlog日志,然后从库连接到主库之后,从库有一个IO线程,将主库的binlog日志拷贝到自己本地,写入一个中继日志 relay日志中。接着从库中有一个SQL线程会从中继日志读取binlog,然后执行binlog日志中的内容,也就是在自己本地再次执行一遍SQL,这样就可以保证自己跟主库的数据是一样的。
如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,这时候从库成为了主库,那么有些数据可能就丢失了。
开启半同步复制 semi-sync,用来解决主库数据丢失问题;
这个所谓半同步复制,semi-sync复制
,指的就是主库写入binlog日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的relay log之后
,接着会返回一个ack
给主库,主库接收到至少一个从库的ack之后才会认为写操作完成了。
如果过程出现失败
,那么我们的客户端就可以进行重试了
;
为什么称之为半同步?因为在从库收到数据并且进入replay log里的时候我们就返回ack了,并没有一直到落库才返回ack,这个过程呢其实只进行了一半;至于为什么不进行全复制,直到从库数据也落盘之后才进行确定这就是效率问题了。
主从延迟对于读写分离的涉及影响比较大
这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的
,也就是说主库上并行的操作,在从库上会串行执行
。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行SQL的特点,在高并发场景下,主库大量的写,那么从库的数据一个个的读,那么就会导致从库同步一定会比主库慢一些,是有延时的
。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。(主库并发写的量级越高,从库积压的同步数据越多,延迟越高)
我们可以用show status
看看Seconds_Behind_Master
参数,你可以看到从库复制主库的数据落后了几ms,但是这个也不是完全准确,可以看Seconds_Behind_Master的
对于解决主从延迟,解决方案可以从以下方面考虑
多个sql线程,并行读取relay log中不同库的日志
,然后并行重放不同库的日志,这是库级别的并行
,如果单库的并发很高的话也不行,但是打开肯定比不打开好。分库
,大多数情况主从延迟是因为主库的写并发太高,从库同步不过来,如果我们分库之后每个库压力就小多了,主从延迟可以低到1ms或者0.1ms这样忽略不计的程度。代码层面避免改后就查
:最好不要有先DDL就立即要DQL到这条数据的这种操作(比如先插入一条数据,在查出来这条数据,再更新这条数据,这里就可能存在插入成功后,从库延迟,我们从从库查出来的id为null,然后更新时候再按id更新这条数据时候就是where id =null 就会出现问题)直连主库
:如果必须有上述3
的这种写完就读
的操作,我们必须设置他这里查询的时候就要直连主库,从主库查数据
。当然这里可能就会失去了读写分离的意义了。