您的当前位置:首页>全部文章>文章详情

【PHP】一文搞懂MySQL数据库分库分表

CrazyPanda发表于:2024-07-17 09:34:40浏览:237次TAG: #mysql
原文链接:https://blog.csdn.net/shida219/article/details/117981566

如果数据量过大,大家一般会分库分表。分库需要注意的内容比较少,但分表需要注意的内容就多了。

工作这几年没遇过数据量特别大的业务,那些过亿的数据,因为索引设置合理,单表性能没有影响,所以实战中一直没用过分表。最近手里有个项目,预估数据量会很大,分表方案是选项之一,趁着这次机会,把分表的内容整理一下。

这次要讲的主要是水平分库分表,其它种类的分库、分表比较容易理解。后面如果不详细说明,都指水平分库分表。

1.基础知识

1.1分库分表定义

1.1.1分库

垂直分库:按照业务模块进行切分,将不同模块的表切分到不同的数据库中。

如电商系统有电商数据库,按照业务模块可以分为用户库、商品库、订单库,这些都可以当做独立数据库,不需要放到一起。好处是既能独立变更,又能隔绝相互影响。

1.png

1.1.2分表

垂直分表:也就是“大表拆小表”,基于列字段进行的。一般是因为表设计不合理,需要进行拆分。

如一张表存放学生、老师、课程、成绩信息,最好拆分为学生表、课程表、成绩表。

水平分表:针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。不建议采用。

水平分库分表:将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈。

1.png

1.2分区与分片的区别

分表时经常能看到两个名词:分区和分片。这两个词都是指将大表的数据分成多块,但两者还是有本质区别的。

Sharding(分片) 的思想从分区的思想而来,但数据库分区基本上是数据对象级别的处理,比如表和索引的分区,每个子数据集上能够有不同的物理存储属性,还是单个数据库范围内的操作,而 Sharding 是能够跨数据库,甚至跨越物理机器的。

MySQL5.1提供的分区(Partition)功能确实可以实现表的分区,但是这种分区是局限在单个数据库范围里的,它不能跨越服务器的限制。
1.png

我们在分表的时候,一般使用的是分片方案,即数据存放在多个物理机器。

1.3分片策略

分片规则一般有如下:

1.3.1按照哈希切片
  1. mod-long:用于分区列为数值的hash分区

    分片列 id=分区列值 mod 分片数

  2. mod-long-by-hash:用于分区列为字符串的hash分区

    分片列id=hash(分区列值) mod 分片数

1.3.2按照范围切片
  1. range:建表时创建分区规则,根据分区规则就可以确定分区列的值在哪个分区上

    一般分区列为时间或者数值,如

    date_range:0: 10000001: 20000002: 30000003: 40000004: maxvalue

    如果分区列值为1500000,则数据放到1号分片上。

2.分库分表中间件

需要使用者感知不到这是分片表,使用时需要和正常表一样,一般需要引入中间件。

操作分片表一般有三种方式:

2.1客户端分片

所谓的客户端分片即在使用数据库的应用层直接操作分片逻辑,分片规则需要在同一个应用的多个节点间进行同步,每个应用层嵌入一个操作切片的逻辑实现。如当当网的Sharding JDBC。
1.png

2.2代理分片

代理分片就是在应用层和数据库层之间添加一个代理层,把分片的路由规则配置在代理层,代理层对外提供与JDBC兼容的接口给应用层,在业务实现之后,在代理层配置路由规则即可。如Mycat就是基于此种解决方案来实现的。
1.png

2.3支持事务的分布式数据库

支持分布式事务的框架,目前有OceanBase、TiDB框架,这些框架将可伸缩特定和分布式事务的实现包装到了分布式数据库内部实现,对使用者透明,使用者不需要直接控制这些特性,但是对事务的支持不如关系型数据,适合大数据日志系统、统计系统、查询系统、社交网站等。

2.4说明

支持事务的分布式数据库算另一种选型了,和MySQL已经没有关系。

对于客户端分片和代理分片,目前工作过的两家公司用的都是代理方式,一家用的是MyCAT,一家用的Dbatman。客户端分片方式没有接触过。这两种的区别为:
1.png

3.分布式事务

分片意味数据分布在多台物理机器上,引入分布式事务问题。我们将单表的数据切片后存储在多个数据库甚至是多个数据库实例中,所以依靠数据库本身的事务机制不能满足需要,这时就需要用到分布式事务来解决。关于分布式事务的相关内容可以看分布式系统与一致性协议

这里不细讲分布式事务如何处理,后面会单独写篇文章。我们聊一下分布式事务会对操作MySQL产生什么影响。

既然知道引入了分布式事务问题,那么操作MySQL的时候,肯定不能和单表一样进行操作。不同中间件能力不一样,所以需要单独分析,我以Dbatman为例,阐述使用上的区别。

  1. 分片版本不维护自增与主键唯一,业务可自行维护唯一键

  • 意味不同分片的主键id会重复

  1. 不支持跨分片事务写,可以跨分片事务读

  • 如果确保事务操作的内容在一个分片内,就不是分布式事务,和单机行为一致

  • 一个事务涉及多个分片叫跨节点事务,单分片事务支持

  1. update和insert必须带分片列

总结一下就是操作同一个分片没影响,操作不同分片需要看中间件支持不支持。

4.是否选择分库分表

选择做分库分表,考虑的几个要素是:

  1. 空间方面:单个物理实例无法支撑数据存储需求,单台物理机无法继续通过加盘的方式扩容

  2. 主库性能:受限于单个主库的CPU/内存/磁盘IOPS的影响,接近或者达到上限后,需要拆分

  3. 容灾方面:减少单个主库宕机对于写入的影响。

针对以上3点,我们还可以多考虑一下,有没有更合适的方案

  1. 空间方面:

    • 删除历史数据清空空间

    • 修改存储模型降低对于MySQL磁盘的占用

    • 改用空间压缩比更高的存储引擎

  2. 主库性能:

    • 可以通过读写分离的方式,降低对于写库的读请求量,从而提升对于写入的支撑。

    • 优化数据写入模型,减少批量写入(削峰)

  3. 容灾方面:

    • 如果业务对于读高可用要求比较高,一般建议是做读写分离,将重要的请求路由至读库。读库数量一般会比写库多N个,在代理层面会做容灾的自动切换。

    • 从集群整体的角度看,分库分表实际上是会扩大故障率,假设单台物理机的SLA是99.99%,那么2台物理机的SLA就是99.98(约数), 10台物理机的SLA就只剩下99.90%了。平均每年的故障时间也会从52分钟提升到525分钟。所以在有些场景下,单个节点故障可能会导致代理整个不可用,从而放大故障的影响范围。

5.设计

现在项目需求为:

  1. 生成唯一码,码值为整数

  2. 码值需要批量插入数据库

  3. 对码的更新操作都是单条处理,而且对码值进行操作需要进行记录

  4. 最终数量不定,长远看数据量会很大

基于上面的需求,做如下设计:

  1. 以码值为主键,自己控制主键唯一

  2. 码表使用range进行分片,如分片范围为01亿,1亿2亿

  3. 码表的操作记录表同样使用range进行分片,分片范围和码表一致

通过这种设计能够实现需求。

但计算后发现,单表能存百亿条数据,而且索引设计比较合理,业务逻辑相对简单,无高并发请求,单表好像也可以搞。

总结

正常情况下,我们一般需要做水平分库分表,这就涉及到分布式事务,一定要考虑清楚是否能满足自己的需求、想用的SQL语句是否都能支持,考虑一下是否还有别的方案。

关于中间件的实现原理,了解的不是很深,后面有时间的话,可以学习一下。

猜你喜欢

【PHP】支付宝小程序授权登录踩坑记录
最近做了个uniapp转支付宝小程序的项目,遇到了很多问题,在此记录一下。1 授权登录,提示grant_type参数不正确接口链接https://opendocs.alipay.com/mini/05dxgc?pathHash=1a3ecb13小程序端先获取授权codePage({   getAuthCode() {     my.getAuthCode({      &nbs
发表于:2023-12-27 浏览:382 TAG:
【PHP】详解PHP的Sodium加密扩展函数
Sodium 出现的目的也是为了代替Mcrypt这个原来的加密扩展。在 PHP7.2 之后,Mcrypt已经被移除,在PHP7.1时就已经被标记为过时。不过,Sodium扩展的应用也并不是很多,大部分情况下我们都会使用OpenSSL来进行加密操作,所以,我们这篇文章只做了解即可。Sodium 扩展在 PHP7.2 后是跟随 PHP 源码一起发布的,只需要在编译的时候加上 --with-sodium 即可安装成功。如果是 PHP7.2 之前的版本,需要单独安装这个扩展。同时,操作系统中也需要安装
发表于:2023-12-19 浏览:291 TAG:
【PHP】php常用的第三方类库有哪些
php常用的第三方类库有Laravel、Symfony、Guzzle、PHPUnit、Monolog、Swift Mailer、PHPExcel、Carbon、Doctrine、PHPMailer等。详细介绍:1、Laravel是一个流行的PHP框架,提供了丰富的功能和工具,用于快速构建Web应用程序,它包含了许多常用的类库,例如路由、数据库访问、模板引擎、身份验证等等。本教程操作系统:windows10系统、PHP 8.1.3版本、DELL G3电脑。在PHP开发中,有许多常用的第三
发表于:2023-12-04 浏览:633 TAG:
【PHP】Permission denied怎么解决
Permission denied的解决方法:1、确保当前用户具有足够的权限来执行该操作;2、如果当前用户没有足够的权限,可以尝试更改文件或目录的权限;3、如果当前用户不是管理员或没有足够的权限,可以尝试使用管理员权限来执行操作;4、可以尝试更改文件系统属性,以便允许写入操作;5、可以尝试释放磁盘空间,以便有足够的空间来执行操作;6、检查文件是否被其他进程占用。当我们遇到Permission denied这样的错误提示时,这通常意味着我们没有足够的权限来执行某个操作。解决Permiss
发表于:2023-12-06 浏览:355 TAG:
【PHP】php中?:与??运算符有什么不同?
在PHP 7中,有两个类似的语法结构:“??”和“?:”,它们都是用于处理条件判断和返回值的运算符。尽管它们看起来相似,但它们的作用和用法有一些区别。"?:"是三目运算符,语法格式为:$result = $test ? $test : ′ ′ ; 意思就是当test存在时(即empty($test)为false),则返回它本身,否则返回空(当然也可以返回其他,这里的空只是举个例子)。"??"是php7新引入的语法,它相当于是isset($result[‘k
发表于:2024-08-01 浏览:273 TAG:
【PHP】php哪些函数可以用来去幂方值
hp可以用来去幂方值的函数有pow函数、双星号、exp函数、sqrt函数和log函数等。详细介绍:1、pow函数用于计算x的y次幂,x是底数,y是指数;2、双星号是幂运算符,用于计算一个数的幂;3、exp函数用于计算以e为底的x次幂,e是自然对数的底数,x是指数;4、sqrt函数用于计算一个数的平方根,x是计算平方根的数;5、log函数用于计算以指定底数为底的对数。本教程操作系统:windows10系统、PHP 8.1.3版本、DELL G3电脑。在PHP中,可以使用一些内置的函数来进行幂运算
发表于:2024-03-15 浏览:280 TAG:
【PHP】php二维数组排序
        PHP作为一种常用的Web编程语言,在不同的应用场景下,对数组的处理是不可避免的。而对于数组排序,也是开发时经常面对的一个问题。本文将介绍如何对二维数组进行排序。一、二维数组排序概述在PHP中,二维数组是由多个一维数组链接而成的复合数组,也就是说,它不仅有行的概念,还有列的概念。当需要对二维数组进行排序时,通常需要对其中某一列进行排序。这时候需要使用PHP提供的函数来进行排序。二、对二维数组进行排序的方法1.使用usort()函数u
发表于:2023-12-14 浏览:377 TAG:
【PHP】ThinkPHP6中间件介绍
一、什么是中间件?当客户端发送请求至服务器时,HTTP请求会经过多个中间件,最后返回响应给客户端。中间件可以在请求到达目标控制器或动作之前对请求进行操作可以在响应离开目标控制器或动作之前对响应进行操作二、中间件的作用我们可以在不修改应用程序逻辑的情况下添加额外的功能,如登录验证、检查用户权限、权限控制请求过滤判断当前浏览器环境是在微信或支付宝写系统日志统计三、中间件的类型1、前置中间件前置中间件的意思就是,在http请求完成之前,先执行中间件的代码。一般用来检查用户权限在app/middlewa
发表于:2024-07-29 浏览:251 TAG: #php #thinkphp #中间件
【PHP】9个适用于PHP的最佳自动化测试框架
您是否花了很长时间调试您PHP代码? 好吧,对于大多数程序员来说,这可能不是最迷人的挑战,但是有一种解决方案可以帮助我们缩短这项繁琐的任务。 自动化测试通过允许预先编写的测试来驱动开发过程,可以显着改善PHP开发的工作流程 。在这篇文章中,我们将尝试了解为什么自动化测试如此酷 ,它如何工作以及您可以从中开始的最佳测试框架是什么。为什么测试很重要新手PHP开发人员倾向于不为他们的代码编写测试。 我们大多数人的职业生涯都是通过逐一测试刚在浏览器窗口中编写的新特性和功能开始的,当出现问题时,我们一无所
发表于:2024-06-22 浏览:265 TAG: #测试
【PHP】7个php字符串处理函数有哪些
7个php字符串处理函数有strlen()、strpos()、substr()、str_replace()、strtolower()、strtoupper()、trim()等。详细介绍:1、strlen(),用于获取字符串的长度;2、strpos(),用于查找字符串中的特定子串,返回第一次出现位置;3、substr(),用于获取字符串的子串;4、str_replace()等等。本教程操作系统:Windows10系统、PHP8.1.3版本、Dell G3电脑。在PHP中,有许多可以用于字
发表于:2023-12-04 浏览:684 TAG: