当前位置: 首页 > news >正文

好好的系统,为什么要分库分表?

不急于上手实战 ShardingSphere 框架,先来复习下分库分表的基础概念,技术名词大多晦涩难懂,不要死记硬背理解最重要,当你捅破那层窗户纸,发现其实它也就那么回事。

什么是分库分表

分库分表是在海量数据下,由于单库、表数据量过大,导致数据库性能持续下降的问题,演变出的技术方案。

分库分表是由分库分表这两个独立概念组成的,只不过通常分库与分表的操作会同时进行,以至于我们习惯性的将它们合在一起叫做分库分表。

通过一定的规则,将原本数据量大的数据库拆分成多个单独的数据库,将原本数据量大的表拆分成若干个数据表,使得单一的库、表性能达到最优的效果(响应速度快),以此提升整体数据库性能。

为什么分库分表

单机数据库的存储能力、连接数是有限的,它自身就很容易会成为系统的瓶颈。当单表数据量在百万以里时,我们还可以通过添加从库、优化索引提升性能。

一旦数据量朝着千万以上趋势增长,再怎么优化数据库,很多操作性能仍下降严重。为了减少数据库的负担,提升数据库响应速度,缩短查询时间,这时候就需要进行分库分表。

为什么需要分库?

容量

我们给数据库实例分配的磁盘容量是固定的,数据量持续的大幅增长,用不了多久单机的容量就会承载不了这么多数据,解决办法简单粗暴,加容量!

连接数

单机的容量可以随意扩展,但数据库的连接数却是有限的,在高并发场景下多个业务同时对一个数据库操作,很容易将连接数耗尽导致 too many connections 报错,导致后续数据库无法正常访问。

可以通过 max_connections 查看 MySQL 最大连接数。

show variables like '%max_connections%'

将原本单数据库按不同业务拆分成订单库、物流库、积分库等不仅可以有效分摊数据库读写压力,也提高了系统容错性。

为什么需要分表?

做过报表业务的同学应该都体验过,一条 SQL 执行时间超过几十秒的场景。

导致数据库查询慢的原因有很多,SQL 没命中索引、like 扫全表、用了函数计算,这些都可以通过优化手段解决,可唯独数据量大是 MySQL 无法通过自身优化解决的。慢的根本原因是 InnoDB 存储引擎,聚簇索引结构的 B+tree 层级变高,磁盘 IO 变多查询性能变慢,详细原理自行查找一下,这里不用过多篇幅说明。

阿里的开发手册中有条建议,单表行数超 500 万行或者单表容量超过 2GB,就推荐分库分表,然而理想和实现总是有差距的,阿里这种体量的公司不差钱当然可以这么用,实际上很多公司单表数据几千万、亿级别仍然不选择分库分表。

什么时候分库分表

技术群里经常会有小伙伴问,到底什么情况下会用分库分表呢?

分库分表要解决的是现存海量数据访问的性能瓶颈,对持续激增的数据量所做出的架构预见性。

是否分库分表的关键指标是数据量,我们以 fire100.top 这个网站的资源表 t_resource 为例,系统在运行初始的时候,每天只有可怜的几十个资源上传,这时使用单库、单表的方式足以支持系统的存储,数据量小几乎没什么数据库性能瓶颈。

但某天开始一股神秘的流量进入,系统每日产生的资源数据量暴增至十万甚至上百万级别,这时资源表数据量到达千万级,查询响应变得缓慢,数据库的性能瓶颈逐渐显现。

以 MySQL 数据库为例,单表的数据量在达到亿条级别,通过加索引、SQL 调优等传统优化策略,性能提升依旧微乎其微时,就可以考虑做分库分表了。

既然 MySQL 存储海量数据时会出现性能瓶颈,那么我们是不是可以考虑用其他方案替代它?比如高性能的非关系型数据库 MongoDB

可以,但要看存储的数据类型!

现在互联网上大部分公司的核心数据几乎是存储在关系型数据库(MySQL、Oracle 等),因为它们有着 NoSQL 如法比拟的稳定性和可靠性,产品成熟生态系统完善,还有核心的事务功能特性,也是其他存储工具不具备的,而评论、点赞这些非核心数据还是可以考虑用 MongoDB 的。

如何分库分表

分库分表的核心就是对数据的分片(Sharding)并相对均匀的路由在不同的库、表中,以及分片后对数据的快速定位与检索结果的整合。

分库与分表可以从:垂直(纵向)和 水平(横向)两种纬度进行拆分。下边我们以经典的订单业务举例,看看如何拆分。

垂直拆分

1、垂直分库

垂直分库一般来说按照业务和功能的维度进行拆分,将不同业务数据分别放到不同的数据库中,核心理念 专库专用

按业务类型对数据分离,剥离为多个数据库,像订单、支付、会员、积分相关等表放在对应的订单库、支付库、会员库、积分库。不同业务禁止跨库直连,获取对方业务数据一律通过 API 接口交互,这也是微服务拆分的一个重要依据。

垂直分库很大程度上取决于业务的划分,但有时候业务间的划分并不是那么清晰,比如:电商中订单数据的拆分,其他很多业务都依赖于订单数据,有时候界线不是很好划分。

垂直分库把一个库的压力分摊到多个库,提升了一些数据库性能,但并没有解决由于单表数据量过大导致的性能问题,所以就需要配合后边的分表来解决。

2、垂直分表

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

例如:一张 t_order 订单表上有几十个字段,其中订单金额相关字段计算频繁,为了不影响订单表 t_order 的性能,就可以把订单金额相关字段拆出来单独维护一个 t_order_price_expansion 扩展表,这样每张表只存储原表的一部分字段,通过订单号 order_no 做关联,再将拆分出来的表路由到不同的库中。

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

水平拆分

上边垂直分库、垂直分表后还是会存在单库、表数据量过大的问题,当我们的应用已经无法在细粒度的垂直切分时,依旧存在单库读写、存储性能瓶颈,这时就要配合水平分库、水平分表一起了。

1、水平分库

水平分库是把同一个表按一定规则拆分到不同的数据库中,每个库可以位于不同的服务器上,以此实现水平扩展,是一种常见的提升数据库性能的方式。

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

这种方案往往能解决单库存储量及性能瓶颈问题,但由于同一个表被分配在不同的数据库中,数据的访问需要额外的路由工作,因此系统的复杂度也被提升了。

2、水平分表

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

例如:一张 t_order 订单表有 900 万数据,经过水平拆分出来三个表,t_order_1t_order_2t_order_3,每张表存有数据 300 万,以此类推。

水平分表尽管拆分了表,但子表都还是在同一个数据库实例中,只是解决了单一表数据量过大的问题,并没有将拆分后的表分散到不同的机器上,还在竞争同一个物理机的 CPU、内存、网络 IO 等。要想进一步提升性能,就需要将拆分后的表分散到不同的数据库中,达到分布式的效果。

数据存在哪个库的表

分库分表以后会出现一个问题,一张表会出现在多个数据库里,到底该往哪个库的哪个表里存呢?

上边我们多次提到过一定规则 ,其实这个规则它是一种路由算法,决定了一条数据具体应该存在哪个数据库的哪张表里。

常见的有 取模算法 、范围限定算法范围+取模算法 、预定义算法

1、取模算法

关键字段取模(对 hash 结果取余数 hash (XXX) mod N),N 为数据库实例数或子表数量)是最为常见的一种路由方式。

以 t_order 订单表为例,先给数据库从 0 到 N-1 进行编号,对 t_order 订单表中 order_no 订单编号字段进行取模 hash(order_no) mod N,得到余数 ii=0 存第一个库,i=1 存第二个库,i=2 存第三个库,以此类推。

同一笔订单数据会落在同一个库、表里,查询时用相同的规则,用 t_order 订单编号作为查询条件,就能快速的定位到数据。

优点

实现简单,数据分布相对比较均匀,不易出现请求都打到一个库上的情况。

缺点

取模算法对集群的伸缩支持不太友好,集群中有 N 个数据库实 ·hash(user_id) mod N,当某一台机器宕机,本应该落在该数据库的请求就无法得到处理,这时宕掉的实例会被踢出集群。

此时机器数减少算法发生变化 hash(user_id) mod N-1,同一用户数据落在了在不同数据库中,等这台机器恢复,用 user_id 作为条件查询用户数据就会少一部分。

2、范围限定算法

范围限定算法以某些范围字段,如时间或 ID区拆分。

用户表 t_user 被拆分成 t_user_1t_user_2t_user_3 三张表,后续将 user_id 范围为 1 ~ 1000w 的用户数据放入 t_user_1,1000~ 2000w 放入 t_user_2,2000~3000w 放入 t_user_3,以此类推。按日期范围划分同理。

优点

  • 单表数据量是可控的
  • 水平扩展简单只需增加节点即可,无需对其他分片的数据进行迁移

缺点

  • 由于连续分片可能存在数据热点,比如按时间字段分片时,如果某一段时间(双 11 等大促)订单骤增,存 11 月数据的表可能会被频繁的读写,其他分片表存储的历史数据则很少被查询,导致数据倾斜,数据库压力分摊不均匀。

3、范围 + 取模算法

为了避免热点数据的问题,我们可以对上范围算法优化一下

这次我们先通过范围算法定义每个库的用户表 t_user 只存 1000w 数据,第一个 db_order_1 库存放 userId 从 1 ~ 1000w,第二个库 1000~2000w,第三个库 2000~3000w,以此类推。

每个库里再把用户表 t_user 拆分成 t_user_1t_user_2t_user_3 等,对 userd 进行取模路由到对应的表中。

有效的避免数据分布不均匀的问题,数据库水平扩展也简单,直接添加实例无需迁移历史数据。

4、地理位置分片

地理位置分片其实是一个更大的范围,按城市或者地域划分,比如华东、华北数据放在不同的分片库、表。

5、预定义算法

预定义算法是事先已经明确知道分库和分表的数量,可以直接将某类数据路由到指定库或表中,查询的时候亦是如此。

分库分表出来的问题

了解了上边分库分表的拆分方式不难发现,相比于拆分前的单库单表,系统的数据存储架构演变到现在已经变得非常复杂。看几个具有代表性的问题,比如:

分页、排序、跨节点联合查询

分页、排序、联合查询,这些看似普通,开发中使用频率较高的操作,在分库分表后却是让人非常头疼的问题。把分散在不同库中表的数据查询出来,再将所有结果进行汇总合并整理后提供给用户。

比如:我们要查询 11、12 月的订单数据,如果两个月的数据是分散到了不同的数据库实例,则要查询两个数据库相关的数据,在对数据合并排序、分页,过程繁琐复杂。

事务一致性

分库分表后由于表分布在不同库中,不可避免会带来跨库事务问题。后续会分别以阿里的 Seata 和 MySQL 的 XA 协议实现分布式事务,用来比较各自的优势与不足。

全局唯一的主键

分库分表后数据库表的主键 ID 业务意义就不大了,因为无法在标识唯一一条记录,例如:多张表 t_order_1t_order_2 的主键 ID 全部从 1 开始会重复,此时我们需要主动为一条记录分配一个 ID,这个全局唯一的 ID 就叫分布式ID,发放这个 ID 的系统通常被叫发号器。

多数据库高效治理

对多个数据库以及库内大量分片表的高效治理,是非常有必要,因为像某宝这种大厂一次大促下来,订单表可能会被拆分成成千上万个 t_order_n 表,如果没有高效的管理方案,手动建表、排查问题是一件很恐怖的事。

历史数据迁移

分库分表架构落地以后,首要的问题就是如何平滑的迁移历史数据,增量数据和全量数据迁移,这又是一个比较麻烦的事情,后边详细讲。

分库分表架构模式

分库分表架构主要有两种模式:client 客户端模式和 proxy 代理模式

客户模式

client 模式指分库分表的逻辑都在你的系统应用内部进行控制,应用会将拆分后的 SQL 直连多个数据库进行操作,然后本地进行数据的合并汇总等操作。

代理模式

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

如何抉择

如何选择 client 模式和 proxy 模式,我们可以从以下几个方面来简单做下比较。

1、性能

性能方面 client 模式表现的稍好一些,它是直接连接 MySQL 执行命令; proxy 代理服务则将整个执行链路延长了,应用 -> 代理服务 ->MySQL,可能导致性能有一些损耗,但两者差距并不是非常大。

2、复杂度

client 模式在开发使用通常引入一个 jar 可以; proxy 代理模式则需要搭建单独的服务,有一定的维护成本,既然是服务那么就要考虑高可用,毕竟应用的所有 SQL 都要通过它转发至 MySQL。

3、升级

client 模式分库分表一般是依赖基础架构团队的 Jar 包,一旦有版本升级或者 Bug 修改,所有应用到的项目都要跟着升级。小规模的团队服务少升级问题不大,如果是大公司服务规模大,且涉及到跨多部门,那么升级一次成本就比较高;

proxy 模式在升级方面优势很明显,发布新功能或者修复 Bug,只要重新部署代理服务集群即可,业务方是无感知的,但要保证发布过程中服务的可用性。

4、治理、监控

client 模式由于是内嵌在应用内,应用集群部署不太方便统一处理;proxy 模式在对 SQL 限流、读写权限控制、监控、告警等服务治理方面更优雅一些。

相关文章:

好好的系统,为什么要分库分表?

不急于上手实战 ShardingSphere 框架,先来复习下分库分表的基础概念,技术名词大多晦涩难懂,不要死记硬背理解最重要,当你捅破那层窗户纸,发现其实它也就那么回事。 什么是分库分表 分库分表是在海量数据下&#xff0…...

多种调度模式下的光储电站经济性最优储能容量配置分析(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

二分法(适用于任何题型!!!)

今天看二分法看了一天,看吐了,现在讲讲怎么做类题。 只讲两种做法(实则是可合并为一种),任何题型都可以转化为这种做法!!!是任何! 首先,设置 int left,righ…...

js常见的七种继承及实现

在 JavaScript 中,常见的继承方式有以下七种:大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库1. 原型链继承原型链继承是 JavaScript 中一种基于原型的继承方式&#…...

案例分析之——理由Mybatis动态SQL实现复用

无复用思想的做法: 在没有复用思想的时候,就只顾着实现功能。比如开发过程中涉及到两个表的更新功能,每需要更新一处,就写一个接口,结果出现了写了11个接口的情况。 这样虽然功能实现了,可是可能自…...

MCM 箱模型建模方法及大气 O3 来源解析实用干货

OBM 箱模型可用于模拟光化学污染的发生、演变过程,研究臭氧的生成机制和进行敏感性分析,探讨前体物的排放对光化学污染的影响。箱模型通常由化学机理、物理过程、初始条件、输入和输出模块构成,化学机理是其核心部分。MCM (Master Chemical M…...

【独家】华为OD机试 - 最长连续交替方波信号(C 语言解题)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

代码随想录算法训练营第二十一天打卡 | 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

打卡第21天,继续二叉树,前几天终于补完了,感觉难度上来了。 今日任务 530.二叉搜索树的最小绝对差501.二叉搜索树中的众数 二叉树的最近公共祖先 530.二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root ,返回 树中任意两不…...

免费下载丨一看即会,Serverless 技术进阶必读百宝书

过去一年,全球正在加速推进云计算的 Serverless 化进程。Serverless 架构已经逐渐从“被接受”走向了“被学习”和“被应用”。云的产品体系正在 Serverless 化,从计算、存储、数据库到中间件,越来越多的云产品采用了 Serverless 模式。服务器…...

SQL语句的加锁方式 - Mysql 锁机制

SQL语句的加锁方式 - Mysql锁机制 SELECT ... FROM SELECT ... FOR UPDATE / SELECT ... FOR SHARED MODE SELECT ... LOCK IN SHARE MODE SELECT ... FOR UPDATE UPDATE ... WHERE ... DELETE FROM ... WHERE ... INSERT INSERT ... ON DUPLICATE KEY UPDATE REPLACE Mysql锁机…...

C#开发的OpenRA的游戏主界面怎么样创建4

继续游戏主界面创建的主题, 前面已经说到怎么样找到mainmenu.yaml来显示主界面,也说了怎么样找到各个子控件类。 现在就来仔细分析一下,主界面每一部分的功能。 比如下面这个区域的界面是怎么样创建: 要创建这一小部分的界面显示,也是需要做很多的工作。 因为在这里所有UI…...

覆盖5大主流开发平台的报表控件,它值得你一看

为什么大家现在都在使用第三方报表工具呢? 第三方报表工具是数据库存储,数据库程序通常可以存放的数据量是相当大的,可以处理非常复杂的数据结构关系,报表数据交互速度也非常快。不仅能够提高开发效率,还能实现灵活美…...

【冲刺蓝桥杯的最后30天】day4

大家好😃,我是想要慢慢变得优秀的向阳🌞同学👨‍💻,断更了整整一年,又开始恢复CSDN更新,从今天开始更新备战蓝桥30天系列,一共30天,如果对你有帮助或者正在备…...

spring boot actuator 动态修改日志级别

1 日志级别 Spring Boot Actuator包括在运行时查看和配置应用程序日志级别的功能。您可以查看整个列表,也可以查看单个记录器的配置,该配置由显式配置的日志级别和日志框架给出的有效日志级别组成。这些级别可以是: TRACEDEBUGINFOWARNERRORFATALOFFnu…...

兴达易控Modbus转Profinet网关连接1200Profinet转modbus接三菱A800变频器案例

下面介绍A800 变频器通过兴达易控modbus转profinet网关,使1200plc无需编程实现Profinet转modbus协议转换,把modbus变频器轻松组网 网络拓扑如下图 打开博图组态加载GSD文件,modbus转profinet网关从站接口接入到1200PLC上 配置modbus转profine…...

「SAP ABAP」OPEN SQL(四)【FROM语句】

💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后…...

一文吃透 SpringMVC 中的转发和重定向

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

Hbase操作命令

目录 创建表,表中有两个列族 baseinfo, schoolinfo 查看指定表全名空间中的表 查看表描述 禁用/启用 查看是否启用/禁用 删除表 注意,首先要将删除的表设置为禁用状态才可以删除,否则会报错 新增列族 删除列族 更改列族存储版本的限制 增…...

1>LINK : fatal error LNK1104: cannot open file ‘libconvtname.obj‘

我自己最后找到问题原因是: 引用的库名称没有.lib,只有libconvtname。 改成完整的libconvtname.lib即可。 以下是chatGPT的回答 The error message "fatal error LNK1104: cannot open file libconvtname.obj" usually occurs when Visual S…...

数据结构——链表OJ题目讲解(1)

作者:几冬雪来 时间:2023年3月7日 内容:数据结构链表OJ题目讲解 题目来源:力扣和牛客 目录 前言: 刷题: 1.移出链表元素: 2.链表的中间结点: 3. 链表中倒数第k个结点&#xff1…...

LeetCode_二分搜索_困难_154.寻找旋转排序数组中的最小值 II

目录1.题目2.思路3.代码实现(Java)1.题目 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums [0,1,4,4,5,6,7] 在变化后可能得到: 若旋转 4…...

面向对象设计模式:创建型模式之建造者模式

一、引入 Build:建造和构建具有建筑结构的大型物体 建楼:打牢地基、搭建框架、然后自下而上一层层盖起来。构建物体:通常需要先建造组成这个物体的各个部分,然后分阶段把它们组装起来 二、建造者模式 2.1 Intent 意图 Separate…...

集成学习boosting、bagging、stacking

目录 一、介绍 二、三种架构学习 (1)boosting (2)bagging (3)stacking 一、介绍: 对于单个模型来说很难拟合复杂的数,模型的抗干扰能力较低,所以我们希望可以集成多…...

数据模型(上):模型分类和模型组成

1.模型分类 ​ 数据模型是一种由符号、文本组成的集合,用以准确表达信息景观,达到有效交流、沟通的目的。数据建模者要求能与来自不同部门,具有不同技术背景,不同业务经验,不同技术水平的人员交流、沟通。数据建模者要了解每个人员的观点,并通过反馈证明理解无误,最终作…...

郑州轻工业大学2022-2023(2) 数据结构题目集 - ZZULI

6-1 线性表元素的区间删除 6-1 线性表元素的区间删除 分数 20 全屏浏览题目 切换布局 作者 DS课程组 单位 浙江大学 给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素。删除后表中剩余元素保持顺序存储,并且相对位置不能改变…...

【Python语言基础】——Python MySQL Drop Table

Python语言基础——Python MySQL Drop Table 文章目录Python语言基础——Python MySQL Drop Table一、Python MySQL Drop Table一、Python MySQL Drop Table 删除表 您可以使用 “DROP TABLE” 语句来删除已有的表: 实例 删除 “customers” 表: import…...

2023美团面试真题

面试前需要准备: 1. Java 八股文:了解常考的题型和回答思路; 2. 算法:刷 100-200 道题,记住刷题最重要的是要理解其思想,不要死记硬背,碰上原题很难,但 大多数的解题思路是相通的…...

【微信小程序开发全流程】篇章0:基于JavaScript开发的校园综合类微信小程序的概览

基于JavaScript开发的校园综合类微信小程序的概览 本文仅供学习,未经同意请勿转载 一些说明:上述项目来源于笔者我本科大三阶段2019年电子设计课程项目,在这个项目中,我主要是负责的部分有前端,前后端的对接&#xf…...

如何分析sql性能

1、前言 提到sql性能分析,可能都会想到explain,它在mysql里被称为执行计划,也就是说可以通过该命令看出mysql在通过优化器分析之后如何执行sql。mysql的内置优化器十分强大,它能帮我们把sql再次优化,以最低的成本去执…...

市场营销书籍推荐:《经理人参阅:市场营销》

要学好市场营销有什么好方法?答案是看书!比起碎片化地去阅读一些文章或看一些相关视频,读书来得更实在些。倘若能静下心来好好读上一本系统性的市场营销书籍,学好营销管理将不会再是一件难事。然而,问题的关键是&#…...