超简单理解分库分表
一、为什么要做分库分表
在数据爆炸的年代,单表数据达到千万级别,甚至过亿的量,都是很常见的情景。这时候再对数据库进行操作就是非常吃力的事情了,select个半天都出不来数据,这时候业务已经难以维系。不得已,分库分表提上日程,我们的目的很简单,减小数据库的压力,缩短表的操作时间。
二、如何进行数据分片
数据切分(Sharding),简单的来说,就是通过某种特定的条件,将存放在同一个数据库中的数据拆分存放到多个数据库(主机)中,从而达到分散单台机器负载的情况,即分库分表。根据数据切分规则的不同,主要有两种模式,
垂直切分(纵向切分),是对不同的表进行切分,存储到不同的数据库(主机)之上。
水平切分(横向切分),是对同一个表中的数据进行切分,存储到不同的数据库(主机)之上。规则是根据表中数据的逻辑关系,按照某种条件拆分。
1.垂直切分
-
垂直分表
也就是
大表分小表
,基于列字段进行的,把一张表竖着切成两断。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。 一般是针对那种几百列的大表,也避免查询时,数据量太大造成的“跨页”问题。 -
垂直分库
垂直分库,强调的是业务的拆分。一个数据库由多个表构成,每个表对应不同的业务,那么我们可以指按照业务的不同将表进行分类,并将其分布到不同的数据库上,这样就将数据分摊到了不同的库上面,做到专库专用。
比如用户User一个库,商品Producet一个库,订单Order一个库。 切分后,要放在多个服务器上,而不是一个服务器上。
为什么这么做?
没有拆分之前,所有的CRUD(增删改查)都在一个数据库上,而单个数据库的性能平静在500w左右,随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps等非常吃紧。垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈。
-
垂直拆分的优点:
拆分规则明确,拆分后业务清晰;系统之间进行整合或扩展变的容易;数据维护变的容易;按照成本、应用的等级、应用的类型等将表放到不同的机器上,便于管理。垂直拆分的缺点:
部分业务表无法关联Join,只能通过接口方式解决,提高了系统的复杂度;受每种业务的不同限制,存在单库性能瓶颈,不易进行数据扩展和提升性能;分布式事务处理复杂。
2.水平切分(重点)
-
水平分表
针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。
-
水平分库分表
将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。
比如,原数据库有一张交易记录表,数据量非常大,其中表中有个地区字段,经过深入考证符合水平拆分的条件。我们就按照这个字段进行水平拆分,按不同的地区(北京、上海、江苏、浙江、广东等)拆分成10个库。
高峰时段同时有100万次请求,如果是单库,数据库就会承受100万次的请求压力,拆分成100个表分别放入10个库中,每个表进行1万次请求,则每个数据库会承受10万次的请求压力,这样压力就减少了很多,并且是成倍减少的。
-
数据路由算法
-
向下取整
从0到10000一个表,10001到20000一个表; -
一致性HASH
一个商场系统,一般都是将用户,订单作为主表,然后将和它们相关的作为附表,这样不会造成跨库事务之类的问题。 取用户id,然后hash取模,分配到不同的数据库上。
一致性HASH原理. -
地理区域
比如按照华东,华南,华北这样来区分业务,七牛云应该就是如此。
-
时间
按照时间切分,就是将6个月前,甚至一年前的数据切出去放到另外的一张表,因为随着时间流逝,这些表的数据 被查询的概率变小,所以没必要和“热数据”放在一起,这个也是“冷热数据分离”。
-
-
水平拆分的优点:
拆分规则抽象好,join 操作基本可以数据库做;不存在单库大数据,高并发的性能瓶颈;应用端改造较少;提高了系统的稳定性跟负载能力。
-
水平拆分的缺点:
拆分规则不好抽象;分片事务一致性难以解决;数据多次扩展难度大;跨库 join 性能较差。
三、数据切分后会出现的问题
事务支持
分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
多库结果集合并(group by,order by)
TODO
跨库join
TODO 分库分表后表之间的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表, 结果原本一次查询能够完成的业务,可能需要多次查询才能完成。 粗略的解决方法: 全局表:基础数据,所有库都拷贝一份。 字段冗余:这样有些字段就不用join去查询了。 系统层组装:分别查询出所有,然后组装起来,较复杂。
分库分表方案产品
目前市面上的分库分表中间件相对较多,其中基于代理方式的有MySQL Proxy和Amoeba, 基于Hibernate框架的是Hibernate Shards,基于jdbc的有当当sharding-jdbc, 基于mybatis的类似maven插件式的有蘑菇街的蘑菇街TSharding, 通过重写spring的ibatis template类的Cobar Client。
还有一些大公司的开源产品:
上面我们也讲了两种数据切分方式的优点和缺点,但是他们有些共同的缺点,
分布式事务的问题;跨节点 Join 的问题;跨节点合并排序分页的问题;多数据源管理问题。一般来说,业务上存在着复杂 join 的场景是很难切分的,往往业务独立的易于切分。如何切分,我们遵循如下原则,
能不切分尽量不要切分;如果要切分一定要选择合适的切分规则,提前规划好;数据切分尽量通过数据冗余或表分组来降低跨库 Join 的可能;由于数据库中间件对数据 Join 实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表 Join。
数据源管理的问题
分库分表之后,数据源的管理是系统实现的关键。
系统应用层面系统应用代码层面,目前主要有两种思路,
客户端模式,也就是在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合。比如可以依赖spring注解实现。中间代理模式,统一管理所有的数据源,后端数据库集群对前端应用程序透明。考虑到系统的复杂性和扩展性,建议第二种中间代理模式。虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常实用的。
- 中间件层面
上面的系统层面,需要的代码实现比较复杂,中间件是在数据集群前面加一层代理,比如Cobar、Mycat等数据库中间件。实用数据库中间件,对代码层面的实现是很大的解放。
# 总结来自
https://blog.csdn.net/qq_39940205/article/details/80536666
https://blog.csdn.net/azhuyangjun/article/details/86976568