写点什么

数据库的主从分离

作者:ES_her0
  • 2022 年 7 月 16 日
  • 本文字数:1254 字

    阅读完需:约 4 分钟

数据库的主从分离似乎已经成了互联网服务的标配了,可能除了刚起步的创业公司在业务量不大的情况下没有采用,剩下的都会默认做一个主从分离。今天稍微深聊一下主从分离的细节。

实现原理

首先主从分离一般情况下指的是读写分离,主库承担写入的任务,读库承担读取的任务。一个对用户开放的服务往往都是读远多于写,但数据库读的压力往往也要大于写,所以在这里将写库(一般称之为主库)和读库(一般称之为从库)分开,可以很大程度上提升业务系统的性能。但这里说的读写分离并没有真正的分离,数据依然需要从主库复制到从库,只是对于 api 请求来说,读的请求会落到从库上,写的请求落到主库上。

以 mysql 为例,阐述一下数据的主从复制是如何实现的。


简单画了个图表示主从同步的过程。首先数据变更会都会记录一个 log,mysql 这里叫 binlog,当设置了从库之后,从库会新建一个异步的 IO 线程来读取主库的 binlog,到了从库之后变成了 relaylog,这里再从 log 解析成 SQL,最后入到从库。因为是异步线程,且 binlog 的变更被从库订阅了,数据库可以认为是准实时同步,但延迟肯定是比单机的 mysql 要差一些。

注意事项

从单机变成集群,系统的复杂度提升了,肯定也会带来一些额外的问题。这里主要说 2 个问题。

主从延迟

如上一章节所说,主从的同步直接必然会存在延迟,毕竟是一次网络连接,速度取决于网速、数据包大小、请求频率等。对于有些场景,即使主从同步慢了,比如在电商系统下单了但从我的订单里暂时没有查到,然后过了几秒查到了,这并不是什么不可接受的问题,甚至在很多用户眼里都不算问题。但在另一种情形下,可能就会是比较大的问题。还是用电商举例,这回主角变成了程序员。在代码 save 了一个订单数据,然后紧接着在另一个地方去查询这笔订单的数据来处理进一步的业务,这个时候因为延迟没查到就会觉得这笔订单不存在,进而产生比较严重的后果。

这种问题的解决思路是什么呢?

  • 继续增加复杂度,引入缓存或者消息队列,在存数据库时同步向外部系统发送一个全量的数据,在代码中需要进一步处理业务的地方才有查缓存或者消费消息的方式来进行。这种方式处理好异常场景的回滚和拦截,是一个比较合适的方式。

  • 对于某些对速度要求比较高的场景,采取强制查主库的方式。这样没有引入复杂度,但极端情况下会影响主库的性能,进而影响整个业务的性能。虽然是极端场景,但挂一次就损失惨重,还是要尽量避免。

数据访问

当前市面上主流的做法是给 mysql 再做一层代理,这层对业务开发者不可见,会自动识别 SQL,进而做一些改写去访问不同的库。现有的有 360 的 Atlas 和美团基于 Atlas 进一步开发的 DBproxy。这种做法会增加 1 次网络情况,对性能会有轻微的影响。

还有一种是在代码层面包装,让业务代码自己决定连接哪个库。这种做法不具备普适性,每种语言都要实现一遍,当心血来潮想尝试新的编程语言时,这就是实实在在的拦路虎。但就老实的坚守 Java 的阵地,这也是一种性能更高的做法。

小结

主从分离并不是 mysql 特有的,这其实是一种问题的解决思路。就像潮汐车道一样,根据场景给出不同的调度策略。在 redis 和 es 这样的存储中也在广泛使用。


用户头像

ES_her0

关注

还未添加个人签名 2018.03.21 加入

还未添加个人简介

评论

发布
暂无评论
数据库的主从分离_7月月更_ES_her0_InfoQ写作社区