why分库分表
分库分表其实是解决海量数据存储、高并发查询和写的问题。解决这个问题还有其他的方案,但是使用场景不同,比如:
- NosSql:比如Hbase,MongoDB,这些适合非结构化、不关心事务的场景,这时可以可以选择Nosql阵营的产品。
- 关系型数据库:
- 读写分离:读多写少模式,采用主从架构,根据qps的峰值和单台机器查询的性能确定数量。
- 表分区:在表存储阶段进行存储,应用无感知,因为是在一个库内完成的操作,无法线性扩展,所以只能适应数据量不是特别大的case。
本章主要讨论关系型数据库的分库分表
- 分表:单表瓶颈:单表数据过千万时,查询RT会升高,整体的QPS会下降,难以支撑高并发场景。
- 分库:单库瓶颈:应用数变多,io,磁盘达到瓶颈,整体的QPS会下降,难以支撑高并发场景。
how分库分表
-
水平切分与垂直切分
- 垂直切分:垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。表的记录并不多,但是字段却很长,表占用空间很大,检索表的时候需要执行大量的IO,严重降低了性能。这时需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系。
- 切分原则
- 1,把不常用的字段单独放在一张表;,
- 2,把text,blob等大字段拆分出来放在附表中;
- 3,经常组合查询的列放在一张表中;
- 优点
- 数据库的拆分简单明了,拆分规则明确;
- 应用程序模块清晰明确,整合容易;
- 数据维护方便易行,容易定位;
- 缺点
- 部分表关联无法在数据库级别完成,需要在程序中完成;
- 对于访问极其频繁且数据量超大的表仍然存在性能平静,不一定能满足要求;
- 事务处理相对更为复杂;
- 切分达到一定程度之后,扩展性会遇到限制;
- 过读切分可能会带来系统过渡复杂而难以维护。
- 备注:一定要在设计阶段就解决这个问题,时候的拆分成本代价较高
- 切分原则
- 水平切分:将一个表的记录水平分到多张表里面,下面会细说
- 垂直切分:垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。表的记录并不多,但是字段却很长,表占用空间很大,检索表的时候需要执行大量的IO,严重降低了性能。这时需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系。
-
如何选择分库分表字段:
- 充分的业务场景分析,找出使用频度最高的字段。
- 常见的有卖家id、买家id、订单id、商户id、业务id、时间
-
分库分表水平切分的策略:确定分表字段后,要确定如何按照字段去分,常见算法分区、取模、数据路由表
- 按照时间分区
- 原理:将一定区间内的数据放到一张表,多个表在一个库里面
- 案例:具体用哪一种,需要根据数据量进行评估
- 按照日分
每日1张表,当单库超过100张表的时候,分到下一个库。
算法:库ID=(当前日期-上线日期)/100 表ID=业务表_yyyyMMdd - 按照月分
业务表_yyyyMM - 按照年分
业务表_yyyy
- 按照日分
- 先hash,后取模
- 直接取模
- 范围分表
- 比如四张表,每个表只存1000w,第一个表存1-1000w,第四张表存储3001-4000w
- 按照时间分区
带来的问题&解决的办法
事物都具有两面性,分库分表固然解决了高并发存储的问题,但是也带来了一些后遗症
- 全局主键问题
- 多种查询维度的问题:比如订单表,既要通过买家id来查,又要通过卖家id来查,这时sharding column就矛盾了。怎么解决呢?
- 数据冗余:上面的例子,可以冗余两张表,分别是买家和卖家表。牺牲存储来换查询复杂度
- 表替代索引:数据冗余适合查询维度较少的场景,如果多了,数据冗余量太大,就不再是合理的方案了,表替代索引法。
- 全局存储搜索法:通过搜索引擎的方式存储和查询,比如数据同步到ES上。
- 分库分表+es的方案,随着数据量越来越来,虽然分库分表可以继续成倍扩容,但是这时候压力又落到了es这里,这个架构也会慢慢暴露出问题!
一般订单表,积分明细表等需要分库分表的核心表都会有好几十列,甚至上百列(假设有50列),但是整个表真正需要参与条件索引的可能就不到10个条件(假设有10列)。这时候把50个列所有字段的数据全量索引到es中,对es集群有很大的压力,后面的es分片故障恢复也会需要很长的时间。
这个时候我们可以考虑减少es的压力,让es集群有限的资源尽可能保存条件检索时最需要的最有价值的数据,即只把可能参与条件检索的字段索引到es中,这样整个es集群压力减少到原来的1/5(核心表50个字段,只有10个字段参与条件),而50个字段的全量数据保存到HBase中,这就是经典的es+HBase组合方案,即索引与数据存储隔离的方案。
Hadoop体系下的HBase存储能力我们都知道是海量的,而且根据它的rowkey查询性能那叫一个快如闪电。而es的多条件检索能力非常强大。这个方案把es和HBase的优点发挥的淋漓尽致,同时又规避了它们的缺点,可以说是一个扬长避免的最佳实践。
它们之间的交互大概是这样的:先根据用户输入的条件去es查询获取符合过滤条件的rowkey值,然后用rowkey值去HBase查询,后面这一查询步骤的时间几乎可以忽略,因为这是HBase最擅长的场景
- 分库分表+es的方案,随着数据量越来越来,虽然分库分表可以继续成倍扩容,但是这时候压力又落到了es这里,这个架构也会慢慢暴露出问题!
业界知名中间件产品和优劣对比
- 阿里的TDDL,DRDS和cobar,
- 开源社区的sharding-jdbc(3.x已经更名为sharding-sphere);
- 民间组织的MyCAT;
- 360的Atlas;
- 美团的zebra;