数据库分库分表
概述
在业务量不大时,单库单表即可支撑。 当数据量过大存储不下、或者并发量过大负荷不起时,就要考虑分库分表。
相关术语
- 读写分离: 不同的数据库,同步相同的数据,分别只负责数据的读和写;
- 分区: 指定分区列表达式,把记录拆分到不同的区域中(必须是同一服务器,可以是不同硬盘),应用看来还是同一张表,没有变化;
- 分库:一个系统的多张数据表,存储到多个数据库实例中;
- 分表: 对于一张多行(记录)多列(字段)的二维数据表
分表又分两种情形:
- 垂直分表: 竖向切分,不同分表存储不同的字段,可以把不常用或者大容量、或者不同业务的字段拆分出去;
- 水平分表(最复杂): 横向切分,按照特定分片算法,不同分表存储不同的记录。
是否一定要采用分库分表?
需要注意的是,分库分表会为数据库维护和业务逻辑带来一系列复杂性和性能损耗,除非预估的业务量大到万不得已,切莫过度设计、过早优化。
规划期内的数据量和性能问题,尝试能否用下列方式解决:
- 当前数据量:如果没有达到几百万,通常无需分库分表;
- 数据量问题:增加磁盘、增加分库(不同的业务功能表,整表拆分至不同的数据库);
- 性能问题:升级CPU/内存、读写分离、优化数据库系统配置、优化数据表/索引、优化 SQL、分区、数据表的垂直切分;
- 如果仍未能奏效,才考虑最复杂的方案:数据表的水平切分。
分库分表方案
代理层方式
部署一台代理服务器伪装成 MySQL 服务器,代理服务器负责与真实 MySQL 节点的对接,应用程序只和代理服务器对接,对应用程序是透明的。 比如 MyCAT。
MyCAT 后端可以支持 MySQL, SQL Server, Oracle, DB2, PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。
MyCAT 不仅仅可以用作读写分离,以及分表分库、容灾管理,而且可以用于多租户应用开发、云平台基础设施,让你的架构具备很强的适应性和灵活性。
应用层方式
处于业务层和 JDBC 层中间,是以 JAR 包方式提供给应用调用,对代码有侵入性。主要方案有:
- 淘宝网的 TDDL: 已于 2012 年关闭了维护通道,建议不要使用。
- 当当网的 Sharding-JDBC: 仍在活跃维护中。
Sharding-JDBC定位为轻量Java框架,使用客户端直连数据库,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。
Sharding-JDBC分片策略灵活,可支持等号、between、in等多维度分片,也可支持多分片键。 SQL解析功能完善,支持聚合、分组、排序、limit、or等查询,并支持Binding Table以及笛卡尔积表查询。Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零:
- 可适用于任何基于Java的ORM框架,如JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
- 可基于任何第三方的数据库连接池,如DBCP、C3P0、 BoneCP、Druid等。
- 理论上可支持任意实现JDBC规范的数据库。虽然目前仅支持MySQL,但已有支持Oracle、SQLServer等数据库的计划。
分库分表引入的问题
分布式事务
分布式事务的解决方案:由于两阶段/三阶段提交对性能损耗大,可改用事务补偿机制。
跨节点JOIN
对于单库 JOIN,MySQL 原生就支持; 对于多库,出于性能考虑,不建议使用 MySQL 自带的 JOIN,可以用以下方案避免跨节点 JOIN:
- 全局表: 一些稳定的共用数据表,在各个数据库中都保存一份;
- 字段冗余: 一些常用的共用字段,在各个数据表中都保存一份;
- 应用组装:应用获取数据后再组装。
- 另外,某个 ID 的用户信息在哪个节点,他的关联数据(比如订单)也在哪个节点,可以避免分布式查询。
跨节点聚合
只能在应用程序端完成。 但对于分页查询,每次大量聚合后再分页,性能欠佳。
节点扩容
节点扩容后,新的分片规则导致数据所属分片有变,因而需要迁移数据。
仅是学习笔记,难免出错,望不吝指点