详解数据库分库分表(sharding)|附案例分析
概述
数据库分库分表的用处:数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,数据库中的表会越来越多,表中的数据量也会越来越大,相应的数据操作,增删改查也会越来越大;另外,由于无法进行分布式部署的情况下,一台服务器的资源(CPU,IO,磁盘,内存)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。基于上述原因,我们需要用到数据库分库分表操作。
一、基本思想
分库分表的目的就是讲一个数据库切分成多个部分放到不同的数据库上,以便缓解单一数据库的性能问题。
举个例子吧,当你面对海量数据的数据库时,若归因为表多导致的数据量大的话,建议采用垂直切分,就是把关系紧密(比如一个应用模块的表)的表放在一个数据库(server)。如果表并不多,但是每张表的数据非常的多,那就要采用水平切分了。就是将表按照某种规则(常用方法是按ID散列)切分到多个数据库(server)上。当然这只是举了一个例子,因为现实情况要比这个复杂,需要将两种切分方式联合使用才能使得系统性能更优(因为可能一张表的数据量很大,超出了一台服务器的能力范围,这时候就要在垂直拆分的基础上再进行水平拆分)。下面详细介绍一下垂直切分和水平切分。
二、数据库的垂直切分和水平切分
垂直切分:就是按功能模块拆分,比如分为订单库,商品库,用户库。垂直切分最大的特点就是简单明了,实施方便。
水平切分:将同一个表的数据进行分块保存到不同的数据库。
三、案例分析
案例:简单购物系统,涉及以下几张表
1、产品表(数据量10w,稳定)
2、订单表(数据量200W,且有增长趋势)
3、用户表(数据量100w,且有增长趋势)
以mysql为例讲述下水平拆分和垂直拆分,mysql数据库能容忍的数据量级在百万静态数据到千万
垂直拆分:
解决问题:表与表之间的io竞争
不解决的问题:但表中数据量增长出现的压力
方案:把产品表和用户表放到一个server上,订单表单独放到一个server上
水平拆分:
解决问题:单表中数据量增长出现的压力
不解决的问题:表与表之间的io竞争
方案:用户表通过性别拆分为男用户表和女用户表;订单表通过已完成和完成中拆分为已完成订单和未完成订单;产品表未完成订单放一个server上,已完成订单表和男用户表放一个server上,女用户表放一个server上(女的爱购物,数据增量大)
四、拆分策略
如上述所提到的,拆分一般顺序是先垂直拆分再水平拆分。
垂直拆分的结果正好为水平拆分做好铺垫,垂直拆分的思路就是分析表之间的聚合关系,把关系紧密的表放在一个server上(多数情况下可能是同一个模块或者同一个“聚集”,聚集是指:领域驱动设计里的“聚合根”),这个“聚合根”也是进行水平拆分的依据,所有和聚合根关联的而数据将被水平分割到各自的shard碎片中。这样出现跨shard关联的可能性就非常的小,应用程序就不必打断既有的表间关联。
五、拆分所带来的问题
1、事务问题
事务问题的一般解决方式分为两种:分布式事务和通过应用程序与数据库共同控制实现事务
方案一;使用分布式事务
优点:交友数据库管理,简单有效
缺点:性能代价高,特别是shard越来越多时
方案二:由应用程序和数据库共同控制
原理:将一个跨多个数据库的分布式事务分成多个仅处于单个数据库上面的小事务,并通过应用程序来总控各个小事务
优点:性能上有优势
缺点:需要应用程序在事务控制上做灵活的设计
2、跨节点Join问题
避免join操作,将操作分成多步完成。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。
3、跨节点的count,order by ,group by以及聚合函数的问题
解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。
六、总结
数据库分库原因是避免数据库表与表之间的eio竞争,数据库分表原因是为了避免单表数据量增长带来的压力。在实际项目中要先理清整个数据路库的er关系图,在进行拆分,此外需要对一些sql语句进行适当的拆分和优化。
篇幅有限,关于数据库分库分表就介绍到这里了,后期会分享更多DBA内容,感兴趣的朋友可以关注下。