背景:业务发展初期为了便于快速迭代,很多应用都采用集中式的架构,随着业务规模的扩展,系统变得越来越复杂,访问量越来越大,不得不进一步扩展系统的吞吐能力。
优化1、主从集群:通过数据库的复制策略,可以将一台mysql数据库服务器中的数据复制到其他的mysql数据库服务器之上,当各台数据库服务器上都包含相同数据的时候,前端应用通过访问mysql集群中任意一台服务器,都能够读取到相同的数据,这样,每台mysql服务器所需要承担的负载就会大大降低,从而提高整个系统的承载能力,达到系统扩展的目的。
要实现数据库的复制,需要开启master服务器端的binary log,数据复制的过程实际上就是slave从master获取binary log,然后再在本地镜像的执行日志中所记录的操作,由于复制过程是异步的,因此,master和slave之间的数据有可能存在延迟的现象,此时只能够保证数据最终的一致性。
优化2、读写分离:前端服务器通过master来执行数据写入的操作,数据的更新通过binary log同步到slave集群,而对于数据读取的请求,则交由slave来处理,这样,slave集群可以分担数据库读的压力,并且,读写分离还保障了数据能够达到最终一致性。一般而言,大多数站点的读数据库操作要比写数据库操作更为密集,如果读的压力较大,还可以通过新增slave来进行系统的扩展,因此,master-slave的架构能够显著的减轻前面所提到的单库读的压力,毕竟在大多数应用当中,读的压力要比写的压力大的多。
master-slaves复制架构存在一个问题,即所谓的单点故障,当master宕机,系统将无法写入,而在某些特定的场景下,可能需要master停机,以便进行系统维护、优化或者升级,同样的道理,master停机将导致整个系统都无法写入,直到master恢复,大部分情况下这显然是难以接受的。为了尽可能的降低系统停止写入的时间,最佳的方式就是采用dual master架构,即master-master架构。
优化3、分表:对于访问极为频繁且数据量巨大的单表来说,我们首先要做的,就是减少单表的记录条数,以便减少数据查询所需要的时间,提高数据库的吞吐,这就是所谓的 分表。在分表之前,首先需要选择适当的分表策略,使得数据能够较为均衡的分布到多张表中,并且,不影响正常的查询。对于互联网企业来说,大部分数据都是与用户进行关联的,因此,用户id是最常用的分表字段,因为大部分查询都需要带上用户id,这样既不影响查询,又能够使数据较为均衡的分布到各个表中。
优化4、分库:分表能够解决单表数据量过大带来的查询效率下降的问题,但是,却无法给数据库的并发处理能力带来质的提升,面对高并发的读写访问,当数据库master服务器无法承载写操作压力时,不管如何扩展slave服务器,此时都没有意义了。因此,我们必须换一种思路,对数据库进行拆分,从而提高数据库写入能力,这就是所谓的 分库。举例来说,假设某门户网站,它包含了新闻、用户、帖子、评论等等几大块内容,对于数据库来说,它可能包含这样几张表,news、users、post、comment,随着数据量的增加,可以根据业务逻辑进行拆分,分成多个库,以提高系统吞吐能力。
有的时候,数据库可能即面临着高并发访问的压力,又需要面对海量数据的存储问题,这时候,需要对数据库即采用分库策略,又采用分表策略,以便同时扩展系统的并发处理能力,以及提升单表的查询性能,这就是所谓的 分库分表。
假设将原来的单库单表order拆分成256个库,每个库包含1024个表,那么,按照前面所提到的路由策略,对于userid=262145的访问,路由的计算过程如下:
中间变量=262145%(256*1024)=1
库=取整(1/1024)=0
表=1%1024=1
这意味着,对于userid=262145的订单记录的查询和修改,将被路由到第0个库的第1个表中执行。
缺陷:
1.条件查询、分页查询受到限制,查询必须带上分库分表所带上的id
2.事务可能跨多个库,数据一致性无法通过本地事务实现,无法使用外键
3.分库分表规则确定以后,扩展变更规则需要迁移数据