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

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

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

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

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_1、t_ent_order_2、t_ent_order_3 ,每张表存储300万条。

5 选择分库还是分表

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

  • 分库:

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

  • 分表:

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

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

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

6 代理模式和客户端模式

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

1、客户端模式

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

应用层分片方案业界有 sharding-jdbc ,TDDL 等。

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

2、代理模式

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

代理层分片方案业界有 Mycat ,Cobar,ShardingSPhere Proxy等 。

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

7 分库分表缺点

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

1、跨库关联查询

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

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

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

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

2、分布式事务

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

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

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

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

4、分布式ID

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

相关文章
|
Java 数据库 Spring
Spring事务失效的场景详解
Spring事务失效的场景详解
492 0
|
SQL 关系型数据库 数据库
学习分布式事务Seata看这一篇就够了,建议收藏
学习分布式事务Seata看这一篇就够了,建议收藏
26358 2
|
数据采集 机器学习/深度学习 数据挖掘
【数学建模】 灰色预测模型
【数学建模】 灰色预测模型
1638 0
|
数据采集 监控 Shell
无需Python:Shell脚本如何成为你的自动化爬虫引擎?
Shell脚本利用curl/wget发起请求,结合文本处理工具构建轻量级爬虫,支持并行加速、定时任务、增量抓取及分布式部署。通过随机UA、异常重试等优化提升稳定性,适用于日志监控、价格追踪等场景。相比Python,具备启动快、资源占用低的优势,适合嵌入式或老旧服务器环境,复杂任务可结合Python实现混合编程。
Java 类是如何被加载的
这篇文章从双亲委派讲到了Class文件的加载,最后又绕回到双亲委派,看似有点绕,其实只有理解了Class的加载机制,才能更好的理解类似双亲委派这样的机制,否则只死记硬背一些空洞的理论,是无法起到由内而外的理解的。
14517 125
|
应用服务中间件 Linux 网络安全
技术指南:如何把docsify项目部署到基于CentOS系统的Nginx中。
总结 与其他部署方法相比,将docsify项目部署到基于CentOS系统的Nginx中比较简单。以上步骤应当帮助你在不花费太多时间的情况下,将你的项目顺利部署到Nginx中。迈出第一步,开始部署你的docsify项目吧!
580 14
|
JSON 人工智能 前端开发
用markdown语法制作一个好看的网址导航页面(markdown-web-nav)
这是一篇关于创建网址导航页面的工具分享文章。作者介绍了从手动编写HTML代码到开发可视化工具 *markdown-web-nav* 的历程,旨在简化网址管理与导航页面生成的过程。该工具支持新增、编辑和删除网址数据,通过导入/导出JSON文件、实时预览Markdown效果以及一键复制等功能,让用户轻松制作美观的网站导航页面。文章还提供了详细的操作步骤及常见问题解答,如还原数据、获取网站图标链接等,适合不同技术水平的用户使用。
950 28
|
存储 固态存储 文件存储
一台电脑最多能接几个硬盘?
电脑硬盘扩展指南:从硬件接口(SATA、M.2、USB)到供电散热,再到操作系统盘符限制,本文全面解析一台电脑最多能接多少硬盘。普通用户适合2-4块硬盘,专业人士可扩展至8块以上,企业服务器则无明确上限。通过RAID阵列或NAS设备,还能突破传统限制,满足海量存储需求。了解这些技巧,助您合理规划存储方案!
|
监控 数据可视化 前端开发
17.8K star!完美超越宝塔的产品,像呼吸一样部署应用,这款开源神器绝了!
Dokploy是一个强大的开源平台,旨在简化全栈 Web 应用的开发和部署。通过其直观的界面和丰富的功能,开发者可以在几分钟内构建和部署复杂的应用程序。Dokploy 提供了灵活的架构和多样的功能,适合各种规模的项目。
1150 3
|
JSON 数据格式 Python
X86架构属于国产化架构吗
在信息时代,处理器架构至关重要。本文通过简单流程和代码示例,帮助初学者理解X86架构是否属于国产化架构。首先明确国产化架构指本土研发的处理器架构,如龙芯、飞腾等。X86架构由Intel设计,主要由外资公司开发,通常不被视为国产架构。文章提供了一个判断X86架构是否国产化的流程图,并用Python代码实现判断过程。Architecture类描述架构来源和类型,App类负责获取和判定架构信息。通过这些步骤,初学者可以更好地掌握相关知识并提升开发技能。
1581 5

热门文章

最新文章