Mysql数据库读写分离

Mysql作为现代最受欢迎的关系型数据库,几乎是每个后台程序员都必须掌握的一个技能。后台面试中,Mysql也经常出现,除了常见的事务、索引之外,Mysql的一些部署与应用也经常出现,今天我们来看到一个Mysql常见的技术--读写分离。

为什么需要读写分离

我们都知道单台机器的性能是有限的,每台机器可以维护的连接数是有限的,CPU的算力是有限的,每台机器的内存也是有限的,那么,随着业务的增长,数据日益增多,我们必然会面对这样一个问题,部署Mysql的机器会越来越成为系统的瓶颈。

对于这个问题,我们有两种解决思路,第一个是把数据库进行拆分,不同的业务拆分到不同的数据库,或者同一个业务按照一定的维度进行拆分,也就是我们常说的分库分表。

另外一个思路,由于大部分互联网应用都是读多写少的,所以,我们能否不拆分数据库,让同一份数据复制到多台机器上,不同业务到不同的机器上进行数据读取。这就是我们常常说的读写分离。

通常,我们都是两种手段一并使用的。

读写分离如何实现

首先是数据同步问题,主机是如何把数据从主机同步到从机的。一般,我们都是通过Mysql的主从同步进行实现,当然,也有一些大厂会自研相关的中间件进行解决。Mysql的主从同步主要是利用Binlog的回放机制,将主机上的binlog文件同步到从数机器上进行回放。

第二个是程序的路由问题,写的时候写主机,读的时候什么时候读取主机,什么时候读取从机。

最简单的方法,就是交给程序去实现,由代码自己去决定是读机还是从机。优点是简单,开发方便,并且非常灵活,不同的业务可以自主选择是否读取从机。缺点是开发需要理解每次数据读取是访问哪个数据库,如果遇到不靠谱的程序员,有时候真是一种灾难。另外,如果遇到紧急情况,例如主机故障需要另外选择主机的时候,可能需要修改所有业务机器的配置,才能完成主机的切换。

第二个是使用数据库中间件,由中间件去决定如何路由。中间件对外屏蔽了多种细节,对业务来说,就跟直接连接数据库一样,降低了开发的难度。即使是数据库主机发生变化,只需要操作数据库中间件。当然,有得必有失,新增的中间件势必会增加系统的复杂度,中间件的性能与稳定性也是一个考验,多路由一个系统也会造成延迟的增加。

读写分离会带来什么问题?

无论是采用哪一种读写分离的方案,都会面临这样的一个问题,刚刚更新的数据,立马在从库进行查询,可能会查询到脏数据,因为主从同步是需要时间的。设想,如果用户在支付完订单之后,回到订单页面,看到订单还是未支付,是有怎么样的感受?

为了解决主从同步延迟的问题,一般我们可以采用下面的解决方案:

强制读主库,对于用户读取订单、支付等重要的信息,强制读取主库信息,不读从库。从库,留给一些对实时性要求不高的场景读取,例如后台异步任务、库存系统校验订单状态等等。

缓存标记方案,因为主从同步延迟造成的脏读只是占整个系统读取的一部分,如果我们把所有的读取都切换成读取主库,那么读写分离的意义就会大打折扣,有没有折中的方案呢?我们知道,内存相对于磁盘,读写效率更快,那么,我们可否在服务端维护一个LRUCache,用来表示最近哪些数据被更新过。例如,我们维护哪些用户的订单ID最近有更新,一旦查询的用户命中这个Cache,那么就强制读主库。由于数据的每次查询可能落到不同的机器上,我们可以使用Redis来作为缓存,解决这个问题。

Sleep方案,这个方案听起来很搞笑,后台系统怎么可以Sleep呢?要Sleep多久呢?但是,这个方案实际上是个应用最广泛的方案,你发现没有?当你手机唤起微信支付或者支付宝支付之后,页面上明明只有一个返回原来APP,却不帮你自动跳转,跳转回来之后,会给你弹一个支付成功页,而不是直接回到订单首页,这些都是为了延长用户的操作时间,为后台系统争取更加充分的时间。

其他的,还有判断主从同步的延迟时间等多种判断手段,感兴趣的话可以继续了解。

下一篇
« Prev Post
上一篇
Next Post »