前文介绍MySQL主从模式,将读写分离以提高性能。
主从模式对于写少读多的场景确实非常大的优势,但是总会写操作达到瓶颈的时候,导致性能提不上去。
总的来说就是数据库出现性能瓶颈,对外表现有几个方面:
在高并发场景下,大量请求都需要操作数据库,导致连接数不够了,请求处于阻塞状态。
如果数据库中存在一张上亿数据量的表,一条 SQL 没有命中索引会全表扫描,这个查询耗时会非常久。
业务量剧增,单库数据量越来越大,给存储造成巨大压力。
如果系统处于高速发展阶段,拿商城系统来说,一天下单量可能几十万,那数据库中的订单表增长就特别快,增长到一定阶段数据库查询效率就会出现明显下降。
这时候可以在设计上进行解决:
分库分表方案更多的是对关系型数据库数据存储和访问机制的一种补充,而不是颠覆。
MySQL 的高可用架构大多都是一主多从,所有写入操作都发生在 Master 上,随着业务的增长,数据量的增加,很多接口响应时间变得很长,经常出现 Timeout,而且通过升级 MySQL 实例配置已经无法解决问题了,这时候就要分库。
分表的应用场景是单表数据量增长速度过快,影响了业务接口的响应时间,但是 MySQL 实例的负载并不高,这时候只需要分表,不需要分库(拆分实例)。
垂直分库是按业务分库,例如一个电商系统shop库按业务分有订单表,会员表,商品表,按业务拆分后,响应的shop库被拆分到三个RDS实例中,数据库写入能力提升,服务的接口响应时间变短,提供稳定性。
以用户系统为例,将user表按字段拆分为user_base 和 user_info表,两个表通过userid进行联系。 例如登录系统只需要userid,username和password,如果不分表,则每次登录都需要把整张user表加载进内存进行判断,sex,address,age和nick_name这些无用到的字段也会占内存。
基于表或字段划分,表结构不同
在单库未拆分表之前,我们可以很方便使用 join 操作关联多张表查询数据,但是经过分库分表后两张表可能都不在一个数据库中,如何使用 join 呢?
有几种方案可以解决:
业务量比较大的时候,即使做了垂直拆分,依然会存在以下问题:
根据一定的逻辑,例如将userid取模,将数据放到不同的库上。
举个例子,交易数据库的订单表 orders 有2亿多数据,RDS 实例遇到了写入瓶颈,普通的 insert 都需要50ms,时常也会收到 CPU 使用率告警,这时就要考虑分库了。
根据业务量增长趋势,计划扩容一台同配置的RDS实例,将订单表 orders 拆分20个子表,每个 RDS 实例10个。 这样解决了订单表 orders 太大的问题,查询的时候要先通过分区键 user_id 定位是哪个 RDS 实例,再定位到具体的子表,然后做 DML操作,
问题是代码改造的工作量大,而且服务调用链路变长了,对系统的稳定性有一定的影响。
其实已经有些数据库中间件实现了分库分表的功能,例如常见的 mycat,阿里云的 DRDS 等。
根据一定的逻辑,例如将userid取模,将数据放到不同的表上。
水平拆分的方式也很多,除了上面说的按照 id 拆表,还可以按照时间维度取拆分,比如订单表,可以按每日、每月等进行拆分。
基于数据划分,表结构相同,数据不同。
参考网址:https://www.jianshu.com/p/fddf278e30cb