背景

image.png

  1. 在如今高并发的大背景下,单机数据库已无法满足需求,因此很多公司采用集群部署模式,其中一主多从是最常见的架构,不仅实施简单还可以能实现高可用、读写分离(一个主库写多个从库读,因为读多写少),进而提升集群的并发能力。

主从架构带来好处的同时也带来一系列问题,比如主从延迟问题。

影响

  1. 本周出现线上报警,kafka消息发送失败。究其原因,发现是代码里没有根据刚插入的数据Id查询出数据库记录,导致生产者消息为空,广播数据失败。

那么问题来了,数据一定写入成功的情况下,偶现的主从延迟应该如何解决呢?

解决

1.强制读主库

  1. 好处:保证一定能读到数据且读到的数据是最新的。
  2. 坏处:只适应于并发量不大的场景,否则就失去了读写分离意义。
  3. 实现:查询开事物,自动读主库。

2.读数据时先sleep一下

  1. 好处:逻辑简单,易操作。
  2. 坏处:降低系统吞吐量。

3.发生主从延迟时自旋(推荐)

  1. 好处:针对偶现的主从延迟情况做处理。
  2. 实现:当从数据库读到数据为空时,for循环3次,每次等待0.5S,如果还没查出来则报警。

4.检查代码问题

  1. 如果是Kafka消费的场景可以考虑延时消费。
  2. 写入数据再读出来,这个过程不能放同一个事务里,否则永远读不到。
  3. 避免写入立即查询。写完库后把当前实体的数据带入后面流程,避免再次查库。

5.MySQL服务端本身的优化

  1. MySQL 5.6 版本后,提供了一种并行复制的方式,通过将 SQL 线程转换为多个 work 线程来进行重放,这样就解决了主从延迟的问题

趁着并行复制机制,如果面试官再深入问你一个问题:
主库突然宕机,此时恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,导致数据丢失,MYSQL如何处理这种情况?
答:MySQL有半同步复制机制,就是主库写入 binlog 日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到至少一个从库的 ack 之后才会认为写操作完成了。

  1. MYSQL本身采用半同步复制来解决主库数据丢失问题;并行复制来解决主从同步延时问题。

刨根问底

主从同步原理

image.png
两个关键log:

  • bin log(二进制日志文件)
  • relay log(中继日志文件)

两个关键线程:

  • I/O线程
  • SQL线程
    1. 主从架构配置完成后
    2. 从库自动生成I/O线程和SQL线程,用于接收主库binlog和处理relay log
    3. 从库的I/O线程请求主库binlog,主库开一个后台线程传输binglog
    4. 从库将接收到的binglog转换为relay log
    5. 从库的SQL线程解析relay logMysql操作,完成主从数据同步。

同步延迟原因

主库写binlog操作是顺序I/O,从库重放操作是随机I/O
主库对所有DDL和DML产生的日志写进binlog,由于binlog是顺序写,所以效率很高。Slave的SQL Thread线程将主库的DDL和DML操作事件在slave中重放。DML和DDL的IO操作是随机的,不是顺序的,成本高很多。所以SQL Thread线程的速度赶不上主库学binlog的速度,就会产生主从延迟。

从库出现锁等待
从库出现读锁,导致重放操作需要从库先释放锁。

命令查看同步状态

登陆主库,输入show slave status,查看 Seconds_Behind_Master 参数。