MySQL 分库分表

1. 分库分表的原理和实现

什么是分区、分表、分库 ?

分区
就是把一张表的数据分成 N 个区块,在逻辑上看最终只是一张表,但底层是由N 个物理区块组成的。

分表
就是把一张表按一定的规则分解成 N 个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。

分库
一旦分表,一个库中的表会越来越多。

2. 分库分表的几种常见形式

2.1 垂直分表 (大表拆小表)

拆分是基于关系型数据库中的 “列”(字段)进行的。通常情况,某个表中的字段比较多,可以新建立一张 “扩展表”,将不经常使用或者长度较大的字段拆分出去放到“扩展表”中。
拆分后会遇到很多问题(例如:跨库 join,分布式事务等)

2.2 垂直分库

基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中。

2.3 水平分表 (横向分表)

将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能。最常见的方式就是通过主键或者时间等字段进行 Hash取模(MOD)后拆分。
注意: 水平分表,能够降低单表的数据量,一定程度上可以缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,所以库级别还是会有 IO 瓶颈。所以,一般不建议采用这种做法。

2.4 水平分库分表

水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。这也是很多大型互联网公司所选择的做法。

某种意义上来讲,有些系统中使用的 “冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询),也是类似的实践。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破 IO、连接数、硬件资源的瓶颈。当然,投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(例如:跨分片的复杂查询,跨分片事务等)

3. 分库分表的带来的技术难点

3.1 跨库 join, count, order by, group by及聚合函数

在拆分之前,系统中很多列表和详情页所需的数据是可以通过 sql join 来完成的。而拆分后,数据库可能是分布式在不同实例和不同的主机上,join 将变得非常麻烦。而且基于架构规范,性能,安全性等方面考虑,一般是禁止跨库 join 的。

如何解决:

  • 优先调整垂直分库的设计问题
  • 全局表: 就是有可能系统中所有模块都可能会依赖到的一些表。比较类似我们理解的 “数据字典”。为了避免跨库 join 查询,我们可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心“一致性”问题。
  • 字段冗余: 这是一种典型的反范式设计,在互联网行业中比较常见,通常是为了性能来避免 join 查询。但是适用场景有限, 还需要维护冗余的字段。
  • 数据同步: 定时 A 库中的 tab_a 表和 B 库中 tbl_b 有关联,可以定时将指定的表做同步。当然,同步本来会对数据库带来一定的影响,需要性能影响和数据时效性中取得一个平衡。这样来避免复杂的跨库查询。
  • 系统层组装: 在系统层面,通过调用不同模块的组件或者服务,获取到数据并进行字段拼装。

3.2 跨库事务(分布式事务)的问题

深入理解PHP+Mysql分布式事务与解决方案 - 知乎

3.3 ID 问题

当我们进行分库分表的拆分之后,如果继续使用原来的表自增的方式显然最终查询出来的结果会出现 id 重复问题,处理分库分表下的 id,一般有下面几种方法:

  • UUID
    • 缺点: uuid 长度太长,占据的空间比较大,作为索引并且基于索引的查询性能上面会有一定的影响。
  • 创建一个 sequence 表来维护表明和 id 的关系
CREATE TABLE `SEQUENCE` (  
    `table_name` varchar(18) NOT NULL,  
    `nextid` bigint(20) NOT NULL,  
    PRIMARY KEY (`table_name`)  
) ENGINE=InnoDB
- 每当需要为某个表生成id时,就从 `sequence` 表当中取出 `next_id` ,并将 `next_id` 加一后存入表中,当然缺点也很明显:所有插入数据库当中的数据,都要访问这张表,这张表很容易成为系统瓶颈。

3.4 跨分片的分页排序

对于跨表之间的分页问题,当我们想要访问的是前几页数据时,可以对各个节点进行分页查询,然后再对结果集进行汇总处理,尤其需要注意,如果想要查询第 100 页的数据,这时候,不是单纯的去查询每个表当中第 100 页开始,10 条数据,然后进行汇总,而是需要把每个表当中从 0 开始到 100 页的数据全部查询出来,然后再此基础上进行汇总查询出来第 100 页的数据。

4. 常见的分库分表的工具

  • sharding-sphere:jar,前身是 sharding-jdbc
  • TDDL:jar,Taobao Distribute Data Layer
  • Mycat:中间件
# MySQL 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×