千万级并发架构下,关系型数据库应该如何优化?大厂是如何做分库分表的! (7)

运营端的查询可能不止于单个字段的映射来查询,可能更多的会涉及到一些复杂查询,以及分页查询等,这种查询本身对数据库性能影响较大,很可能影响到用户端对于用户表的操作,所以一般主流的解决方案就是把两个库进行分离。

由于运营端对于数据的一致性和可用性要求不是很高,也不需要实时访问数据库,所以我们可以把C端用户表的数据同步到运营端的用户表,而且用户表可以不需要做分表操作,直接全量查表即可。

当然,如果运营端的操作性能实在是太慢了,我们还可以采用ElasticSearch搜索引擎来满足后台复杂查询的需求。

实际应用中会遇到的问题

在实际应用中,并不是一开始就会想到未来会对这个表做拆分,因此很多时候我们面临的问题是在数据量已经达到一定瓶颈的时候,才开始去考虑这个问题。

所以分库分表最大的难点不是在于拆分的方法论,而是在运行了很长时间的数据库中,如何根据实际业务情况选择合适的拆分方式,以及在拆分之前对于数据的迁移方案的思考。而且,在整个数据迁移和拆分过程中,系统仍然需要保持可用。

对于运行中的表的分表,一般会分为三个阶段。

阶段一,新老库双写

由于老的数据表肯定没有考虑到未来分表的设计,同时随着业务的迭代,可能有些模型也需要优化,因此会设计一个新的表来承载老的数据,而这个过程中,需要做几件事情

数据库表的双写,老的数据库表和新的数据库表同步写入数据,事务的成功以老的模型为准,查询也走老的模型

通过定时任务对数据进行核对,补平差异

通过定时任务把历史数据迁移到新的模型中

阶段二,以新的模型为准

到了第二个阶段,历史数据已经导完了,并且校验数据没有问题。

仍然保持数据双写,但是事务的成功和查询都以新模型为准。

定时任务进行数据核对,补平数据差异

阶段三,结束双写

到了第三个阶段,说明数据已经完全迁移好了,因此。

取消双写,所有数据只需要保存到新的模型中,老模型不需要再写入新的数据。

如果仍然有部分老的业务依赖老的模型,所以等到所有业务都改造完成后, 再废除老的模型。

分库分表后带来的问题

分库分表带来性能提升的好处的同时,也带来了很多的麻烦,

分布式事务问题

分库分表之后,原本在一个库中的事务,变成了跨越多个库,如何保证跨库数据的一致性问题,也是一个常见的难题。如图6-13所示,用户创建订单时,需要在订单库中保存一条订单记录,并且修改库存库中的商品库存,这里就涉及到跨库事务的一致性问题。也就是说我怎么保证当前两个事务操作要么同时成功,要么同时失败。

image-20210716144133821

图6-13 跨库查询

比如查询在合同信息的时候要关联客户数据,由于是合同数据和客户数据是在不同的数据库,那么我们肯定不能直接使用join的这种方式去做关联查询。

我们有几种主要的解决方案:

字段冗余,比如我们查询合同库的合同表的时候需要关联客户库的客户表,我们可以直接把一些经常关联查询的客户字段放到合同表,通过这种方式避免跨库关联查询的问题。

数据同步:比如商户系统要查询产品系统的产品表,我们干脆在商户系统创建一张产品表,通过ETL或者其他方式定时同步产品数据。

全局表(广播表) 比如基础数据被很多业务系统用到,如果我们放在核心系统,每个系统都要去关联查询,这个时候我们可以在所有的数据库都存储相同的基础数据。

ER表(绑定表),我们有些表的数据是存在逻辑的主外键关系的,比如订单表order_info,存的是汇总的商品数,商品金额;订单明细表order_detail,是每个商品的价格,个数等等。或者叫做从属关系,父表和子表的关系。他们之间会经常有关联查询的操作,如果父表的数据和子表的数据分别存储在不同的数据库,跨库关联查询也比较麻烦。所以我们能不能把父表和数据和从属于父表的数据落到一个节点上呢?比如order_id=1001的数据在node1,它所有的明细数据也放到node1;order_id=1002的数据在node2,它所有的明细数据都放到node2,这样在关联查询的时候依然是在一个数据库。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdsws.html