什么是分库分表,为什么要分库分表?

简介: 笔者经常将缓存、分库分表、消息队列定义为高并发三剑客。开发互联网应用系统时,分库分表是一个绕不开的技术点。这篇文章,我们会探讨如下问题:

笔者经常将缓存、分库分表、消息队列定义为高并发三剑客。开发互联网应用系统时,分库分表是一个绕不开的技术点。

这篇文章,我们会探讨如下问题:

1 性能瓶颈

很多系统最开始都是单数据库架构。

面对越来越大的业务流量时,系统层面就会有瓶颈,体现在如下两点:

  1. 数据库瓶颈显现。频繁的磁盘操作导致数据库服务器 IO 消耗增加,同时多表关联,排序,分组,非索引字段条件查询也会让 cpu 飙升,最终都会导致数据库连接数激增;
  2. 网关大规模超时。在高并发场景下,大量请求直接操作数据库,数据库连接资源不够用,大量请求处于阻塞状态。

为了缓解主数据库的压力,很容易就想到的策略:SQL优化

  1. 合理添加索引;
  2. 减少多表 JOIN 关联,通过程序组装,减少数据库读压力;
  3. 减少大事务,尽快释放数据库连接。

另外一个策略是:读写分离

读写分离可以减少主库写压力,同时读从库可水平扩展。当然,读写分离依然有局限性:

  1. 读写分离可能面临主从延迟的问题,不太适合实时性要求较高的场景;
  2. 读写分离可以缓解读压力,但是写操作的压力随着业务爆发式的增长并没有很有效的缓解。

分库分表就是海量数据下,为了解决单库、表数据量过大,导致数据库性能持续下降的问题,演变出的技术方案

2 基本概念

分库和分表是两个概念,但通常会把它们合在一起简称为分库分表。所谓分库分表,业界并没有一个统一的定义,你可以简单理解为:

为了解决由于数据量过大而导致的数据库性能降低的问题,将原来独立的数据库拆分成若干数据库,把原来数据量大的表拆分成若干数据表,使得单一数据库、单一数据表的数据量变得足够小,从而达到提升数据库性能的效果。

分库分表分为分库和分表两个维度,在开发过程中,对于每个维度都可以采用两种拆分思路,即垂直拆分水平拆分

3 分库维度

3.1 垂直分库

垂直分库通常根据业务和功能的维度进行拆分,将不同业务数据分别存储在不同的数据库中,遵循核心理念“专库专用”。

按照业务类型对数据进行分离,将相关表放置在相应的数据库中,例如订单库、支付库、会员库和促销库等。

同时,将服务进行拆分,比如订单服务、支付服务、会员服务等,不同服务禁止跨库直连,而是通过API接口或者远程 RPC 进行数据交互。

垂直分库可以有效将一个数据库的压力分散到多个库中,从而提升整体系统的吞吐。

然而,垂直分库并不能完全解决某一业务表(比如电商订单表)数据量过大,单库查询和写入性能急剧下降的问题,我们可以采用水平分库的方案。

3.2 水平分库

水平分库是将同一个表按照特定规则拆分到不同的数据库中,每个数据库可以位于不同的服务器上。

图中我们将订单库拆分成两个数据库,两个库内有完全相同的订单表t_ent_order ,我们在访问某一笔订单时可以通过对订单的订单编号取模的方式 订单编号 mod 2 (数据库实例数) ,指定该订单应该在哪个数据库中操作。

假如订单表一共有1亿条,拆分到8个订单库中,那么每个库存储1000多万条,相比单库来讲,订单服务的性能能大幅提升。

4 分表维度

4.1 垂直分表

垂直分表针对业务上字段比较多的大表进行的,一般是把业务宽表中比较独立的字段,或者不常用的字段拆分到单独的数据表中,是一种大表拆小表的模式。

我们可以将订单表按照业务领域拆分成两个表,本别是订单信息核心表和订单详情表。

数据库它是以行为单位将数据加载到内存中,这样拆分以后核心表大多是访问频率较高的字段,而且字段长度也都较短,因而可以加载更多数据到内存中,减少磁盘 IO ,增加索引查询的命中率,进一步提升数据库性能。

4.2 水平分表

水平分表是在同一个数据库内,把一张大数据量的表按一定规则,切分成多个结构完全相同表,而每个表只存原表的一部分数据。

订单表有 900 万数据,水平拆分出来三个表,t_ent_order_1t_ent_order_2t_ent_order_3 ,每张表存储300万条。

5 选择分库还是分表

写到这里,有的读者肯定会问:什么时候选择分库,什么时候选择分表呢

  • 分库:

    提升数据库实例的磁盘存储容量、支撑更多的数据库连接,最终大幅度提升数据的写入和读取 (磁盘 IO 指标)。

  • 分表

    减少单表的存储容量,提升数据的查询效率,并没有将拆分后的表分散到不同的物理机器上。这些子表仍然在竞争同一个物理机的 CPU、内存、网络 IO 等资源,依然存在性能上限。

因此在真实场景中,我们是根据实际场景混合使用

图中,我们将订单库拆分四个订单库实例,每个订单库都包含四个订单分表。这种分库分表策略可以大幅提升订单服务的性能,同时也可以充分利用数据库资源。

6 代理模式和客户端模式

分库分表架构分为两种模式:客户端模式代理模式

1、客户端模式

在客户端模式下,分库分表的逻辑完全由系统应用内部控制。应用直接连接多个数据库执行拆分后的 SQL 操作,然后在本地进行数据的合并和汇总等操作。

应用层分片方案业界有 sharding-jdbcTDDL 等。

它的优点:直连数据库,额外开销小,实现简单,轻量级中间件。缺点:无法减少连接数消耗,有一定的侵入性,多数只支持 Java 语言。

2、代理模式

代理模式将应用程序与 MySQL 数据库隔离,业务方的应用不在需要直连数据库,而是连接代理服务,代理服务实现了 MySQL 的协议,对业务方来说代理服务就是数据库,它会将 SQL 分发到具体的数据库进行执行,并返回结果。

代理层分片方案业界有 MycatCobarShardingSPhere Proxy等 。

它的优点:应用零改动,和语言无关,可以通过连接共享减少连接数消耗。缺点:因为是代理层,存在额外的时延。

7 分库分表缺点

分库分表本质上是为了解决数据的写入和读取性能,但也带来了复杂性,主要体现在如下几点:

1、跨库关联查询

在数据切分之前,应用可以通过 SQL 的 JOIN 操作关联多张表查询数据,但引入分库分表之后,数据可能分布在不同的数据库节点上,那么如何 JOIN 呢 ?

  • 字段冗余: 在每个分片中冗余存储关联表的部分数据,尽量包含查询中所需的字段,以避免跨分片进行 JOIN 操作。

  • 全局表: 创建一个全局表,其中包含所有分片中的关键信息。这个全局表可能包含一些通用的、经常需要联合查询的数据。这样,在某些情况下,应用可以直接在全局表中查询,而不需要进行 JOIN 操作。

  • 应用层组装: 在应用层,通过业务逻辑进行数据的组装。当查询涉及到多个分片时,应用层负责获取并组装分片中的数据,避免在数据库层进行复杂的 JOIN 操作。

2、分布式事务

单数据库可以使用本地事务,一旦涉及到多数据库,也就只能通过分布式事务来解决。

常用解决方案有:基于可靠消息(MQ)的解决方案、两阶段事务提交、柔性事务等。

3、排序、分页、函数计算问题

跨节点多库进行查询时,会出现 limit 分页、order by 排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片;当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户。

4、分布式ID

常见的分布式 ID 算法:UUID、雪花算法、百度 uid-generator 、美团Leaf、滴滴 Tinyid 。

相关文章
|
7月前
|
缓存 关系型数据库 MySQL
分库分表知识总结(四)
分库分表知识总结(四)
83 1
|
3月前
|
SQL Oracle 关系型数据库
分库分表
分库分表
|
7月前
|
存储 关系型数据库 中间件
什么是分库分表
什么是分库分表
112 3
|
2月前
|
存储 Java 关系型数据库
分库分表专题
分库分表专题
|
5月前
|
中间件 数据库
分库分表全局查询
【7月更文挑战第12天】
146 12
|
7月前
|
存储 算法 数据库连接
为什么要分库分表
为什么要分库分表
为什么要分库分表
|
7月前
|
缓存 监控 Java
分库分表带来的问题
分库分表带来的问题
|
SQL 缓存 关系型数据库
什么情况下需要考虑分库分表?
什么情况下需要考虑分库分表?
160 0
|
存储 负载均衡 Oracle
分库分表介绍
分库分表是一种用于解决大规模数据存储和查询性能问题的数据库架构设计技术。它将一个数据库拆分成多个独立的数据库实例(分库),并将每个数据库实例的表进一步拆分成多个子表(分表)。这样可以提高数据库的并发处理能力和查询性能。
259 0