From 4d905626fec6e461e5ef4e6b5b8e0d58eb3942b5 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sat, 1 Dec 2018 11:19:34 +0800 Subject: [PATCH] docs(mysql): add mysql-read-write-separation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MySQL如何实现读写分离?主从复制的原理是啥?如何解决主从同步的延时问题? --- README.md | 4 +- .../mysql-read-write-separation.md | 41 ++++++++++++++++++ img/mysql-master-slave.png | Bin 0 -> 24794 bytes 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 docs/high-concurrency/mysql-read-write-separation.md create mode 100644 img/mysql-master-slave.png diff --git a/README.md b/README.md index c4a6b69..6aedf51 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,7 @@ - [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) ### 读写分离 -- 如何实现 MySQL 的读写分离? -- MySQL 主从复制原理是啥? -- 如何解决 MySQL 主从同步的延时问题? +- [如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?](/docs/high-concurrency/mysql-read-write-separation.md) ## 高可用架构 diff --git a/docs/high-concurrency/mysql-read-write-separation.md b/docs/high-concurrency/mysql-read-write-separation.md new file mode 100644 index 0000000..52d80a2 --- /dev/null +++ b/docs/high-concurrency/mysql-read-write-separation.md @@ -0,0 +1,41 @@ +## 面试题 +你们有没有做 MySQL 读写分离?如何实现 MySQL 的读写分离?MySQL 主从复制原理的是啥?如何解决 MySQL 主从同步的延时问题? + +## 面试官心理分析 +高并发这个阶段,肯定是需要做读写分离的,啥意思?因为实际上大部分的互联网公司,一些网站,或者是 app,其实都是读多写少。所以针对这个情况,就是写一个主库,但是主库挂多个从库,然后从多个从库来读,那不就可以支撑更高的读并发压力了吗? + +## 面试题剖析 +### 如何实现 MySQL 的读写分离? +其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。 + +### MySQL 主从复制原理的是啥? +主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的 binlog 日志拷贝到自己本地,写入一个 relay 中继日志中。接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL,这样就可以保证自己跟主库的数据是一样的。 + +![mysql-master-slave](/img/mysql-master-slave.png) + +这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行 SQL 的特点,在高并发场景下,从库的数据一定会比主库慢一些,是**有延时**的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。 + +而且这里还有另外一个问题,就是如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就丢失了。 + +所以 MySQL 实际上在这一块有两个机制,一个是**半同步复制**,用来解决主库数据丢失问题;一个是**并行复制**,用来解决主从同步延时问题。 + +这个所谓**半同步复制**,也叫 `semi-sync` 复制,指的就是主库写入 binlog 日志之后,就会将**强制**此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到**至少一个从库**的 ack 之后才会认为写操作完成了。 + +所谓**并行复制**,指的是从库开启多个线程,并行读取 relay log 中不同库的日志,然后**并行重放不同库的日志**,这是库级别的并行。 + +### MySQL 主从同步延时问题(精华) +以前线上确实处理过因为主从同步延时问题而导致的线上的 bug,属于小型的生产事故。 + +是这个么场景。有个同学是这样写代码逻辑的。先插入一条数据,再把它查出来,然后更新这条数据。在生产环境高峰期,写并发达到了 2000/s,这个时候,主从复制延时大概是在小几十毫秒。线上会发现,每天总有那么一些数据,我们期望更新一些重要的数据状态,但在高峰期时候却没更新。用户跟客服反馈,而客服就会反馈给我们。 + +我们通过 MySQL 命令: +```sql +show status +``` +查看 `Seconds_Behind_Master`,可以看到从库复制主库的数据落后了几 ms。 + +一般来说,如果主从延迟较为严重,有以下解决方案: +- 分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。 +- 打开 MySQL 支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了 2000/s,并行复制还是没意义。 +- 重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。 +- 如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询**设置直连主库**。**不推荐**这种方法,你这么搞导致读写分离的意义就丧失了。 \ No newline at end of file diff --git a/img/mysql-master-slave.png b/img/mysql-master-slave.png new file mode 100644 index 0000000000000000000000000000000000000000..585963279b4cf24d0261aa7cf04feb1b6df12f58 GIT binary patch literal 24794 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 literal 0 HcmV?d00001