阿里二面:为什么要分库分表?

1a08a243048efdd08fed5beb5e0a0783.png

在高并发系统当中,分库分表是必不可少的技术手段之一,同时也是BAT等大厂面试时,经常考的热门考题。

你知道我们为什么要做分库分表吗?

这个问题要从两条线说起:垂直方向水平方向

1 垂直方向

垂直方向主要针对的是业务,下面聊聊业务的发展跟分库分表有什么关系。

1.1 单库

在系统初期,业务功能相对来说比较简单,系统模块较少。

为了快速满足迭代需求,减少一些不必要的依赖。更重要的是减少系统的复杂度,保证开发速度,我们通常会使用单库来保存数据。

系统初期的数据库架构如下:da2e6502f260396a6c3b3eee18b20570.png此时,使用的数据库方案是:一个数据库包含多张业务表。用户读数据请求和写数据请求,都是操作的同一个数据库。

1.2 分表

系统上线之后,随着业务的发展,不断的添加新功能。导致单表中的字段越来越多,开始变得有点不太好维护了。

一个用户表就包含了几十甚至上百个字段,管理起来有点混乱。

这时候该怎么办呢?

答:分表

用户表拆分为:用户基本信息表用户扩展表

4c52840b2a759958219e19703a53da6d.png用户基本信息表中存的是用户最主要的信息,比如:用户名、密码、别名、手机号、邮箱、年龄、性别等核心数据。

这些信息跟用户息息相关,查询的频次非常高。

而用户扩展表中存的是用户的扩展信息,比如:所属单位、户口所在地、所在城市等等,非核心数据。

这些信息只有在特定的业务场景才需要查询,而绝大数业务场景是不需要的。

所以通过分表把核心数据和非核心数据分开,让表的结构更清晰,职责更单一,更便于维护。

除了按实际业务分表之外,我们还有一个常用的分表原则是:把调用频次高的放在一张表,调用频次低的放在另一张表。

有个非常经典的例子就是:订单表和订单详情表。

1.3 分库

不知不觉,系统已经上线了一年多的时间了。经历了N个迭代的需求开发,功能已经非常完善。

系统功能完善,意味着系统各种关联关系,错综复杂。

此时,如果不赶快梳理业务逻辑,后面会带来很多隐藏问题,会把自己坑死。

这就需要按业务功能,划分不同领域了。把相同领域的表放到同一个数据库,不同领域的表,放在另外的数据库。

具体拆分过程如下:bf349f4b26eb04aba4105774029040f4.png

将用户、产品、物流、订单相关的表,从原来一个数据库中,拆分成单独的用户库、产品库、物流库和订单库,一共四个数据库。

在这里为了看起来更直观,每个库我只画了一张表,实际场景可能有多张表。

这样按领域拆分之后,每个领域只用关注自己相关的表,职责更单一了,一下子变得更好维护了。

1.4 分库分表

有时候按业务,只分库,或者只分表是不够的。比如:有些财务系统,需要按月份和年份汇总,所有用户的资金。

这就需要做:分库分表了。

每年都有个单独的数据库,每个数据库中,都有12张表,每张表存储一个月的用户资金数据。130b859b31a6da26e616b91994be3112.png这样分库分表之后,就能非常高效的查询出某个用户每个月,或者每年的资金了。

此外,还有些比较特殊的需求,比如需要按照地域分库,比如:华中、华北、华南等区,每个区都有一个单独的数据库。

甚至有些游戏平台,按接入的游戏厂商来做分库分表。

2 水平方向

水分方向主要针对的是数据,下面聊聊数据跟分库分表又有什么关系。

2.1 单库

在系统初期,由于用户非常少,所以系统并发量很小。并且存在表中的数据量也非常少。

这时的数据库架构如下:87ff1764e7ebfd8f5d62fc368ca77a39.png此时,使用的数据库方案同样是:一个master数据库包含多张业务表

用户读数据请求和写数据请求,都是操作的同一个数据库,该方案比较适合于并发量很低的业务场景。

2.2 主从读写分离

系统上线一段时间后,用户数量增加了。

此时,你会发现用户的请求当中,读数据的请求占据了大部分,真正写数据的请求占比很少。

众所周知,数据库连接是有限的,它是非常宝贵的资源。而每次数据库的读或写请求,都需要占用至少一个数据库连接。

如果写数据请求需要的数据库连接,被读数据请求占用完了,不就写不了数据了?

这样问题就严重了。

为了解决该问题,我们需要把读库写库分开。

于是,就出现了主从读写分离架构:54982b0d953b6ee42a445fa38b148834.png考虑刚开始用户量还没那么大,选择的是一主一从的架构,也就是常说的一个master一个slave。

所有的写数据请求,都指向主库。一旦主库写完数据之后,立马异步同步给从库。这样所有的读数据请求,就能及时从从库中获取到数据了(除非网络有延迟)。

读写分离方案可以解决上面提到的单节点问题,相对于单库的方案,能够更好的保证系统的稳定性。

因为如果主库挂了,可以升级从库为主库,将所有读写请求都指向新主库,系统又能正常运行了。

读写分离方案其实也是分库的一种,它相对于为数据做了备份,它已经成为了系统初期的首先方案。

但这里有个问题就是:如果用户量确实有些大,如果master挂了,升级slave为master,将所有读写请求都指向新master。

但此时,如果这个新master根本扛不住所有的读写请求,该怎么办?

这就需要一主多从的架构了:

ce60e4f5087a5562ab4114b230f2b495.png上图中我列的是一主两从,如果master挂了,可以选择从库1或从库2中的一个,升级为新master。假如我们在这里升级从库1为新master,则原来的从库2就变成了新master的的slave了。

调整之后的架构图如下:b78ed30bd42a36d934d30908d311c9a2.png这样就能解决上面的问题了。

除此之外,如果查询请求量再增大,我们还可以将架构升级为一主三从、一主四从...一主N从等。

2.3 分库

上面的读写分离方案确实可以解决读请求大于写请求时,导致master节点扛不住的问题。但如果某个领域,比如:用户库。如果注册用户的请求量非常大,即写请求本身的请求量就很大,一个master库根本无法承受住这么大的压力。

这时该怎么办呢?

答:建立多个用户库。

用户库的拆分过程如下:f7149e5677fe7be522e4a54d0c477886.png在这里我将用户库拆分成了三个库(真实场景不一定是这样的),每个库的表结构是一模一样的,只有存储的数据不一样。

2.4 分表

用户请求量上来了,带来的势必是数据量的成本上升。即使做了分库,但有可能单个库,比如:用户库,出现了5000万的数据。

根据经验值,单表的数据量应该尽量控制在1000万以内,性能是最佳的。如果有几千万级的数据量,用单表来存,性能会变得很差。

如果数据量太大了,需要建立的索引也会很大,从小到大检索一次数据,会非常耗时,而且非常消耗cpu资源。

这时该怎么办呢?

答:分表,这样可以控制每张表的数据量,和索引大小。

表拆分过程如下:

70bc8e6025ea657a974f2cb0bc2b6fb5.png我在这里将用户库中的用户表,拆分成了四张表(真实场景不一定是这样的),每张表的表结构是一模一样的,只是存储的数据不一样。

如果以后用户数据量越来越大,只需再多分几张用户表即可。

2.5 分库分表

当系统发展到一定的阶段,用户并发量大,而且需要存储的数据量也很多。这时该怎么办呢?

答:需要做分库分表

如下图所示:0e07516533d2e3b7655cde68300377f8.png图中将用户库拆分成了三个库,每个库都包含了四张用户表。

如果有用户请求过来的时候,先根据用户id路由到其中一个用户库,然后再定位到某张表。

路由的算法挺多的:

  • 根据id取模,比如:id=7,有4张表,则7%4=3,模为3,路由到用户表3。

  • 给id指定一个区间范围,比如:id的值是0-10万,则数据存在用户表0,id的值是10-20万,则数据存在用户表1。

  • 一致性hash算法

这篇文章就不过多介绍了,后面会有文章专门介绍这些路由算法的。

3 真实案例

接下来,废话不多说,给大家分享三个我参与过的分库分表项目经历,给有需要的朋友一个参考。

3.1 分库

我之前待过一家公司,我们团队是做游戏运营的,我们公司提供平台,游戏厂商接入我们平台,推广他们的游戏。

游戏玩家通过我们平台登录,成功之后跳转到游戏厂商的指定游戏页面,该玩家就能正常玩游戏了,还可以充值游戏币。

这就需要建立我们的账号体系和游戏厂商的账号的映射关系,游戏玩家通过登录我们平台的游戏账号,成功之后转换成游戏厂商自己平台的账号。

这里有两个问题:

  1. 每个游戏厂商的接入方式可能都不一样,账号体系映射关系也有差异。

  2. 用户都从我们平台登录,成功之后跳转到游戏厂商的游戏页面。当时有N个游戏厂商接入了,活跃的游戏玩家比较多,登录接口的并发量不容小觑。

为了解决这两个问题,我们当时采用的方案是:分库。即针对每一个游戏都单独建一个数据库,数据库中的表结构允许存在差异。34be8aef896afecb6596f411383488a1.png我们当时没有进一步分表,是因为当时考虑每种游戏的用户量,还没到大到离谱的地步。不像王者荣耀这种现象级的游戏,有上亿的玩家。

其中有个比较关键的地方是:登录接口中需要传入游戏id字段,通过该字段,系统就知道要操作哪个库,因为库名中就包含了游戏id的信息。

3.2 分表

还是在那家游戏平台公司,我们还有另外一个业务就是:金钻会员

说白了就是打造了一套跟游戏相关的会员体系,为了保持用户的活跃度,开通会员有很多福利,比如:送游戏币、充值有折扣、积分兑换、抽奖、专属客服等等。

在这套会员体系当中,有个非常重要的功能就是:积分

用户有很多种途径可以获取积分,比如:签到、充值、玩游戏、抽奖、推广、参加活动等等。

积分用什么用途呢?

  1. 退换实物礼物

  2. 兑换游戏币

  3. 抽奖

说了这么多,其实就是想说,一个用户一天当中,获取积分或消费积分都可能有很多次,那么,一个用户一天就可能会产生几十条记录。

如果用户多了的话,积分相关的数据量其实挺惊人的。

我们当时考虑了,水平方向的数据量可能会很大,但是用户并发量并不大,不像登录接口那样。

所以采用的方案是:分表

当时使用一个积分数据库就够了,但是分了128张表。然后根据用户id,进行hash除以128取模。

dff7941836d7567cef52978813b7d604.png

需要特别注意的是,分表的数量最好是2的幂次方,方便以后扩容。

3.3 分库分表

后来我去了一家从事餐饮软件开发的公司。这个公司有个特点是在每天的中午和晚上的就餐高峰期,用户的并发量很大。

用户吃饭前需要通过我们系统点餐,然后下单,然后结账。当时点餐和下单的并发量挺大的。

餐厅可能会有很多人,每个人都可能下多个订单。这样就会导致用户的并发量高,并且数据量也很大。

所以,综合考虑了一下,当时我们采用的技术方案是:分库分表

经过调研之后,觉得使用了当当网开源的基于jdbc的中间件框架:sharding-jdbc

当时分了4个库,每个库有32张表。

ddc5bcbdf7d5f3561861150edd05c547.png

4 总结

上面主要从:垂直和水平,两个方向介绍了我们的系统为什么要分库分表。

说实话垂直方向(即业务方向)更简单。

在水平方向(即数据方向)上,分库分表的作用,其实是有区别的,不能混为一谈。

  • 分库:是为了解决数据库连接资源不足问题,和磁盘IO的性能瓶颈问题。

  • 分表:是为了解决单表数据量太大,sql语句查询数据时,即使走了索引也非常耗时问题。此外还可以解决消耗cpu资源问题。

  • 分库分表:可以解决 数据库连接资源不足、磁盘IO的性能瓶颈、检索数据耗时 和 消耗cpu资源等问题。

如果在有些业务场景中,用户并发量很大,但是需要保存的数据量很少,这时可以只分库,不分表。

如果在有些业务场景中,用户并发量不大,但是需要保存的数量很多,这时可以只分表,不分库。

如果在有些业务场景中,用户并发量大,并且需要保存的数量也很多时,可以分库分表。

好了,今天的内容就先到这里。

是不是有点意犹未尽?

没关系,其实分库分表相关内容挺多的,本文作为分库分表系列的第一弹,作为一个开胃小菜吧,分享给大家。

在文章末尾顺便提几个问题:

  1. 分库分表的具体实现方案有哪些?

  2. 分库分表后如何平滑扩容?

  3. 分库分表后带来了哪些问题?

  4. 如何在项目中实现分库分表功能?

欢迎关注,敬请期待我的下一篇文章。


最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下方二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

4043d5f5a94fdb9b28e1017f3164c534.gif

往期推荐

ef49e4b96173fe30695407af30c11c7d.png

MySQL 性能优化的 9 种姿势,面试再也不怕了!


cd9b92bd3e461ac311425a58f52ccda2.png

高并发下秒杀商品,必须知道的9个细节


b5b9b4a07db285edd55ad354be9b9c72.png

面试官:怎么解决MySQL中的死锁问题?


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544509.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 中 List 分片的 5 种方法!

作者 | 王磊来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)前些天在实现 MyBatis 批量插入时遇到了一个问题,当批量插入的数据量比较大时,会导致程序执行报错&a…

Matlab仿真炮弹飞行轨迹——探究射弹参数对飞行轨迹的影响

目录1.分析炮弹受力2.设定参数并仿真3.通过仿真寻找最佳射弹速度3.1.射弹角度的影响3.2.射弹速率的影响3.3.炮弹属性和空气的影响3.3.1.空气阻力系数的影响3.3.2.炮弹质量的影响1.分析炮弹受力 假设炮弹在飞行过程中可以看成质点,运动时仅考虑初始速度、重力加速度…

50行代码,搞定敏感数据读写!

每天早上七点三十,准时推送干货一、介绍在实际的软件系统开发过程中,由于业务的需求,在代码层面实现数据的脱敏还是远远不够的,往往还需要在数据库层面针对某些关键性的敏感信息,例如:身份证号、银行卡号、…

【Python】导入资源管理器的文件列表(计算文件和文件夹大小)

文章目录1.按照扩展名进行分类2.导出文件的大小3.计算文件夹大小4.分类到字典5.完整代码及效果1.按照扩展名进行分类 使用Python查询一个路径下的所有文件可以借助glob模块以及os模块。 在导入文件列表之前,我们需要指定我们的操作目录,操作目录一经指定…

HashMap 中的一个“坑”!

作者 | 王磊来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)最近公司新来了一个小伙伴,问了磊哥一个比较“奇怪”的问题,这个问题本身的难度并不大,但…

【Python】交互式界面创建函数

文章目录简介规则思路示例代码与运行效果简介 运行Python时,在程序运行过程中手动输入一个函数表达式,并将其作为一个函数进行后续的调用工作,类似于Matlab里面的匿名函数。这个功能使用传统语言会相当麻烦,当然,我也…

原生 js前端路由系统实现3之代码 构建工具 和 querystring功能

为什么80%的码农都做不了架构师?>>> 构建 目前前端构建工具流行的是 grunk.js 功能是大而全,但往往大而全的东西为了多样性 需要做额外的配置 我还是想要有一个专门为自己特性项目而生构建工具 我不想加载第三方的node模块,也不…

单例模式,真不简单

前言单例模式无论在我们面试,还是日常工作中,都会面对的问题。但很多单例模式的细节,值得我们深入探索一下。这篇文章透过单例模式,串联了多方面基础知识,非常值得一读。1 什么是单例模式?单例模式是一种非…

【python】最优化方法之一维搜索(黄金分割法+斐波那契法)

文章目录1.概念2.遍历搜索3.优化算法3.1.一维搜索原则3.2.黄金分割法Code Block3.3.斐波拉契法Code Block1.概念 \qquad一维搜索是最优化方法最简单的一种,即求一个在(a,b)内,连续下单峰函数f(x)f(x)f(x)的极小值。所谓下单峰函数就是只有一个极小值的函…

MySQL系列之E-1------MySQL主从复制原理

主从复制是异步复制,可以通过google的一个插件实现半同步E.1 主从复制原理1、建立主从复制的用户名和密码2、将master上主库需要进行复制的库“锁库”3、通过mysqldump备份master上主库,“解锁“,在slave端进行恢复4、更改配置文件5、在丛库上执行change…

工作中常用的 6 种设计模式!

前言 哈喽,大家好。平时我们写代码呢,多数情况都是流水线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的方式就是:使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中…

【Matlab/C/Python/VB/...】代码复制到word时如何变成彩色的

文章目录下载Notepad复制代码在Notepad粘贴在word中粘贴下载Notepad Notepad是一款免费的Windows软件,一般Windows10和Windows7系统都已经自带,也可以在应用商店直接搜索下载 「win10系统兼容的是7.8版本」 复制代码 在语言编辑乱码复制代码&#xff…

hadoop 2.5.0安装和配置

安装hadoop要先做以下准备: 1.jdk,安装教程在 http://www.cnblogs.com/stardjyeah/p/4640917.html 2.ssh无密码验证,配置教程在 http://www.cnblogs.com/stardjyeah/p/4641524.html 3.linux静态ip配置,教程在 http://www.cnblo…

基于双线性插值的图像旋转原理及MATLAB实现(非自带函数)

目录1.图像旋转的原理1.1.旋转矩阵1.2.双线性插值1.3.像素点匹配2.实现效果与说明1.图像旋转的原理 1.1.旋转矩阵 旋转一幅图像(假设这幅图像大小是矩形的),当然应该从像素点(pixels)开始,在直角坐标系中…

漫画:给女朋友介绍什么是 “元宇宙” ?

什么是更高的自由度呢?或许有人觉得,我们在网络游戏当中,不是也很自由吗?想怎么玩就怎么玩。但是,无论一款网络游戏的元素有多么丰富,游戏当中的角色、任务、职业、道具、场景,都是游戏设计师预…

MyBatis 中为什么不建议使用 where 1=1?

作者 | 王磊来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)最近接手了一个老项目,“愉悦的心情”自然无以言表,做开发的朋友都懂,这里就不多说了&am…

【openMV与机器视觉】四旋翼飞行控制背景下的PID控制与摄像头算法简介

文章目录声明1.四旋翼飞行控制简介2.飞行控制算法2.1.接收机PWM生成2.2.PID算法位置PID速度PID3.摄像头算法3.1.图像处理3.2.霍夫曼变换3.3.巡线算法3.3.寻找目标点降落算法声明 \qquad本文的算法在openMV IDE例程的基础上进行原创,在比赛结束后予以发表&#xff1b…

聊聊sql优化的15个小技巧

前言sql优化是一个大家都比较关注的热门话题,无论你在面试,还是工作中,都很有可能会遇到。如果某天你负责的某个线上接口,出现了性能问题,需要做优化。那么你首先想到的很有可能是优化sql语句,因为它的改造…

【MATLAB】Parzen窗与K近邻算法原理与代码详解

文章目录1.非参数估计原理2.Parzen窗2.1.算法原理2.2.Matlab实现与参数探究3.K近邻3.1.算法原理3.2.Matlab实现与参数探究1.非参数估计原理 \qquad已知一个样本的概率分布时,我们只需要对概率分布中的参数进行估计即可得到该样本的概率密度函数。例如已知样本X服从正…

使用 Lambda 表达式实现超强的排序功能

我们在系统开发过程中,对数据排序是很常见的场景。一般来说,我们可以采用两种方式:借助存储系统(SQL、NoSQL、NewSQL 都支持)的排序功能,查询的结果即是排好序的结果查询结果为无序数据,在内存中…