电商系统架构设计系列(九):如何规划和设计分库分表?

上篇文章中,我给你留了一个思考题:分库分表该如何设计?

今天这篇文章,我们来聊一下如何规划和设计分库分表,以及要考虑哪些问题。

引言

当要解决海量数据的问题,就必须要用到分布式的存储集群了,因为 MySQL 本质上是一个单机数据库,所以很多场景下不是太适合存 TB 级别以上的数据。

但是,绝大部分的电商大厂,它的在线交易这部分的业务,比如说,订单、支付相关的系统,还是舍弃不了 MySQL,原因是,只有 MySQL 这类关系型数据库,才能提供金融级的事务保证。对于分布式事务,那些新的分布式数据库提供的所谓的分布式事务,多少都有点儿残血,目前还达不到这些交易类系统对数据一致性的要求。

那既然 MySQL 支持不了这么大的数据量,这么高的并发,还必须要用它,怎么解决这个问题呢?还是按照我们之前的文章跟你说的思想,分片,也就是拆分数据。1TB 的数据,一个库撑不住,我把它拆成 100 个库,每个库就只有 10GB 的数据了,这不就可以了么?这种拆分就是所谓的 MySQL 分库分表。

不过,思路是这样没错,分库分表实践起来是非常不容易的,有很多问题需要去思考和解决。

如何规划分库分表?

我们以订单表来举例子。首先需要思考的问题是,分库还是分表?分库呢,就是把数据拆分到不同的 MySQL 库中去,分表就是把数据拆分到同一个库的多张表里面。

在考虑到底是分库还是分表之前,我们需要先明确一个原则:

那就是能不拆就不拆,能少拆不多拆。

原因也很简单,你把数据拆分得越散,开发和维护起来就越麻烦,系统出问题的概率就越大。

基于这个原则我们想一下,什么情况下适合分表,什么情况下不得不分库?

那我们分库分表的目的是为了解决两个问题:

  1. 是数据量太大,查询慢的问题。这里面我们讲的“查询”其实主要是事务中的查询和更新操作,因为只读的查询可以通过缓存和主从分离来解决。解决查询慢,只要减少每次查询的数据总量就可以了,也就是说,分表就可以解决问题。
  2. 是为了应对高并发的问题。应对高并发的思想,一个数据库实例撑不住,就把并发请求分散到多个实例中去。所以,解决高并发的问题是需要分库的。

简单地说,数据量大,就分表;并发高,就分库。

一般情况下,我们的方案都需要同时做分库分表,这时候分多少个库,多少张表,分别用预估的并发量和数据量来计算就可以了,预估量建议为现有量的5-10倍。

另外,我个人不建议你在方案中考虑二次扩容的问题,也就是考虑未来的数据量,把这次分库分表设计的容量都填满了之后,数据如何再次分裂的问题。

现在技术和业务变化这么快,等真正到了那个时候,业务早就变了,可能新的技术也出来了,你之前设计的二次扩容方案大概率是用不上的,所以没必要为了这个而增加方案的复杂程度。

这里强调一下,越简单的设计可靠性越高。

如何选择 Sharding Key?

分库分表还有一个重要的问题是,选择一个合适的列或者说是属性,作为分表的依据,这个属性一般称为 Sharding Key。像我们上篇文章说到的归档历史订单的方法,它的 Sharding Key 就是订单完成时间。每次查询的时候,查询条件中必须带上这个时间,我们的程序就知道,三个月以前的数据查订单历史表,三个月内的数据查订单表,这就是一个简单的按照时间范围来分片的算法。

选择合适 Sharding Key 和分片算法非常重要,直接影响了分库分表的效果。我们首先来说如何选择 Sharding Key 的问题。

选择这个 Sharding Key 最重要的参考因素是,我们的业务是如何访问数据的。

比如我们把订单 ID 作为 Sharding Key 来拆分订单表,那拆分之后,如果我们按照订单 ID 来查订单,就需要先根据订单 ID 和分片算法计算出,我要查的这个订单它在哪个分片上,也就是哪个库哪张表中,然后再去那个分片执行查询就可以了。

但是,当我打开“我的订单”这个页面的时候,它的查询条件是用户 ID,这里没有订单 ID,那就没法知道我们要查的订单在哪个分片上,就没法查了。当然你要强行查的话,那就只能把所有分片都查一遍,再合并查询结果,这个就很麻烦,而且性能很差,还不能分页。

那要是把用户 ID 作为 Sharding Key 呢?也会面临同样的问题,使用订单 ID 作为查询条件来查订单的时候,就没办法找到订单在哪个分片了。这个问题的解决办法是,在生成订单 ID 的时候,把用户 ID 的后几位作为订单 ID 的一部分,比如说,可以规定,18 位订单号中,第 10-14 位是用户 ID 的后四位,这样按订单 ID 查询的时候,就可以根据订单 ID 中的用户 ID 找到分片。

那我们系统对订单的查询方式,肯定不只是按订单 ID 或者按用户 ID 这两种啊。比如说,商家希望看到的是自己店铺的订单,还有各种和订单相关的报表。对于这些查询需求,我们一旦对订单做了分库分表,就没法解决了。那怎么办呢?

一般的做法是,把订单数据同步到其他的存储系统中去,在其他的存储系统里面解决问题。比如说,我们可以再构建一个以店铺 ID 作为 Sharding Key 的只读订单库,专门供商家来使用。或者,把订单数据同步到 HDFS 中,然后用一些大数据技术来生成订单相关的报表。

所以你看,一旦做了分库分表,就会极大地限制数据库的查询能力,之前很简单的查询,分库分表之后,可能就没法实现了。

你要记得一句话:分库分表一定是,数据量和并发大到所有招数都不好使了(比如缓存),我们才拿出来的最后一招。

如何选择分片算法?

举个例子,我们能不能用订单完成时间作为 Sharding Key 呢?比如说,我分 12 个分片,每个月一个分片,这样对查询的兼容要好很多,毕竟查询条件中带上时间范围,让查询只落到某一个分片上,还是比较容易的,我在查询界面上强制用户必须指定时间范围就行了。

这种做法有个很大的问题,比如现在是 3 月份,那基本上所有的查询都集中在 3 月份这个分片上,其他 11 个分片都闲着,这样不仅浪费资源,很可能你 3 月那个分片根本抗不住几乎全部的并发请求。这个问题就是“热点问题”。

也就是说,我们希望并发请求和数据能均匀地分布到每一个分片上,尽量避免出现热点。这是选择分片算法时需要考虑的一个重要的因素。一般常用的分片算法就那么几种,刚刚讲到的按照时间范围分片的方法是其中的一种。

基于范围来分片容易产生热点问题,不适合作为订单的分片方法,但是这种分片方法的优点也很突出,那就是对查询非常友好,基本上只要加上一个时间范围的查询条件,原来该怎么查,分片之后还可以怎么查。范围分片特别适合那种数据量非常大,但并发访问量不大的 ToB 系统。比如说,电信运营商的监控系统,它可能要采集所有人手机的信号质量,然后做一些分析,这个数据量非常大,但是这个系统的使用者是运营商的工作人员,并发量很少。这种情况下就很适合范围分片。

一般来说,订单表都采用更均匀的哈希分片算法。比如说,我们要分 24 个分片,选定了 Sharding Key 是用户 ID,那我们决定某个用户的订单应该落到那个分片上的算法是,拿用户 ID 除以 24,得到的余数就是分片号。这是最简单的取模算法,一般就可以满足大部分要求了。当然也有一些更复杂的哈希算法,像一致性哈希之类的,特殊情况下也可以使用。

需要注意的一点是,哈希分片算法能够分得足够均匀的前提条件是,用户 ID 后几位数字必须是均匀分布的。比如说,你在生成用户 ID 的时候,自定义了一个用户 ID 的规则,最后一位 0 是男性,1 是女性,这样的用户 ID 哈希出来可能就没那么均匀,可能会出现热点。

还有一种分片的方法:查表法。查表法其实就是没有分片算法,决定某个 Sharding Key 落在哪个分片上,全靠人为来分配,分配的结果记录在一张表里面。每次执行查询的时候,先去表里查一下要找的数据在哪个分片中。

查表法的好处就是灵活,怎么分都可以,你用上面两种分片算法都没法分均匀的情况下,就可以用查表法,人为地来把数据分均匀了。查表法还有一个特好的地方是,它的分片是可以随时改变的。比如我发现某个分片已经是热点了,那我可以把这个分片再拆成几个分片,或者把这个分片的数据移到其他分片中去,然后修改一下分片映射表,就可以在线完成数据拆分了。

但你需要注意的是,分片映射表本身的数据不能太多,否则这个表反而成为热点和性能瓶颈了。查表法相对其他两种分片算法来说,缺点是需要二次查询,实现起来更复杂,性能上也稍微慢一些。但是,分片映射表可以通过缓存来加速查询,实际性能并不会慢很多。

总结

对 MySQL 这样的单机数据库来说,分库分表是应对海量数据和高并发的最后一招,分库分表之后,将会对数据查询有非常大的限制。

分多少个库需要用并发量来预估,分多少表需要用数据量来预估。选择 Sharding Key 的时候,一定要能兼容业务最常用的查询条件,让查询尽量落在一个分片中,分片之后无法兼容的查询,可以把数据同步到其他存储中去,来解决这个问题。

我们常用三种分片算法,范围分片容易产生热点问题,但对查询更友好,适合并发量不大的场景;哈希分片比较容易把数据和查询均匀地分布到所有分片中;查表法更灵活,但性能稍差。

对于订单表进行分库分表,一般按照用户 ID 作为 Sharding Key,采用哈希分片算法来均匀分布用户订单数据。为了能支持按订单号查询的需求,需要把用户 ID 的后几位放到订单号中去。

最后,还需要强调一下,我们所提到的这些分片相关的知识,不仅仅适用于 MySQL 的分库分表,你在使用其他分布式数据库的时候,一样会遇到如何分片、如何选择 Sharding Key 和分片算法的问题,它们的原理都是一样的,所以我们说的这些方法也都是通用的。

感谢阅读,如果你觉得这篇文章对你有一些启发,也欢迎把它分享给你的朋友。

思考题

怎么能避免写出慢SQL?

期待、欢迎你留言或在线联系,与我一起讨论交流,“一起学习,一起成长”。

上一篇文章

电商系统架构设计系列(八):订单数据越来越多,数据库越来越慢该怎么办?


推荐阅读

  • 【架构】高可用高并发系统设计原则
  • 【总结】互联网技术架构中常用的分库分表方案汇总
  • 技术破局,业绩狂飙十倍:亿级电商平台重构大揭秘
  • 当我们聊高并发时,到底是在聊什么?如何真正地掌握高并发设计能力?
  • 微服务架构实战 - 我的经验分享总结2019(系统架构师)架构演进过程-从信息流架构到电商中台架构​​​​​​

系列分享

  • Elasticsearch教程
  • 微服务架构实战
  • 架构思维成长系列
  • 电商系统架构设计系列

------------------------------------------------------

------------------------------------------------------

我的CSDN主页

关于我(个人域名,更多我的信息)

我的开源项目集Github

期望和大家 一起学习,一起成长,共勉,O(∩_∩)O谢谢

如果你有任何建议,或想学习的知识,可与我一起讨论交流

欢迎交流问题,可加个人QQ 469580884,

或者,加我的群号 751925591,一起探讨交流问题

不讲虚的,只做实干家

Talk is cheap,show me the code

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

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

相关文章

ROS2 中的分布式系统

一、说明 当您运行 ROS2 应用程序时,通常需要在不同机器的不同位置运行 ROS2 节点。由于 ROS2 在抽象的 DDS 层中使用节点之间的通信,因此我们可以非常轻松地安排通信。 为了充分理解 ROS2 的架构,我建议您熟悉本文。 出于本文的目的&#xf…

江西南昌电气机械三维测量仪机械零件3d扫描-CASAIM中科广电

精密机械零部件是指机械设备中起到特定功能的零件,其制造精度要求非常高。这些零部件通常由金属、塑料或陶瓷等材料制成,常见的精密机械零部件包括齿轮、轴承、螺丝、活塞、阀门等。精密机械零部件的制造需要高精度的加工设备和工艺,以确保其…

微信小程序使用npm引入三方包详解

目录 1 前言2 微信小程序npm环境搭建2.1 创建package.json文件2.2 修改 project.config.json2.3 修改project.private.config.json配置2.4 构建 npm 包2.5 typescript 支持2.6 安装组件2.7 引入使用组件 1 前言 从小程序基础库版本 2.2.1 或以上、及开发者工具 1.02.1808300 或…

Mac常见恶意软件再现,办公应用程序潜藏风险如何防范?

Mac电脑正受到臭名昭著的XLoader恶意软件的新变种的攻击,该恶意软件已被重写为在最好的MacBook上本地运行。 虽然XLoader至少从2015年开始出现,但在2021年发现macOS变体之前,它主要用于针对Windows PC。然而,该版本是作为Java程序…

【Redis从头学-7】Redis中的Set数据类型实战场景之用户画像去重、共同关注、专属粉丝

🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 📖所属专栏:Re…

【leetcode 力扣刷题】移除链表元素 多种解法

移除链表元素的多种解法 203. 移除链表元素解法①:头节点单独判断解法②:虚拟头节点解法③:递归 203. 移除链表元素 题目链接:203.移除链表元素 题目内容: 理解题意:就是单纯的删除链表中所有值等于给定的…

0基础学习VR全景平台篇 第88篇:智慧眼-成员管理

一、功能说明 成员管理,是指管理智慧眼项目的成员,拥有相关权限的人可以进行添加成员、分配成员角色、设置成员分类、修改成员以及删除成员五项操作。但是仅限于管理自己的下级成员,上级成员无权管理。 二、前台操作页面 登录智慧眼后台操…

公文校对的艺术:如何确保你的正式文件零错误?

公文是政府和企业中最重要的正式文件之一。一个小小的错误,不仅会影响公文的专业性,甚至可能带来法律和经济后果。因此,如何进行精准的公文校对成为了一门必不可少的技能。接下来,我们将分享一些专业的公文校对技巧,并…

Docker容器与虚拟化技术:容器运行时说明与比较

目录 一、理论 1.容器运行时 2.容器运行时接口 3.容器运行时层级 4.容器运行时比较 5.强隔离容器 二、问题 1.K8S为何难以实现真正的多租户 三、总结 一、理论 1.容器运行时 (1)概念 Container Runtime 是运行于 k8s 集群每个节点中&#xff…

greenplum gpfdist外部表(只读)的实现---理论

经过项目的验证测试以及初步商用化,本篇将进一步讲解greenplum外部表的实现原理,包括设计原则、交互协议与实现流程。gpfdist工具的简介与使用见回顾greenplum gpfdist工具。 1 设计原则 greenplum作为分布式分析型数据库,其每个节点都是独立…

如何批量加密PDF文件并设置不同密码 - 批量PDF加密工具使用教程

如果你正在寻找一种方法来批量加密和保护你的PDF文件,批量PDF加密工具是一个不错的选择。 它是一个体积小巧但功能强大的Windows工具软件,能够批量给多个PDF文件加密和限制,包括设置打印限制、禁止文字复制,并增加独立的打开密码。…

【Django】Task4 序列化及其高级使用、ModelViewSet

【Django】Task4 序列化及其高级使用、ModelViewSet Task4主要了解序列化及掌握其高级使用,了解ModelViewSet的作用,ModelViewSet 是 Django REST framework(DRF)中的一个视图集类,用于快速创建处理模型数据的 API 视…

C++ 网络编程项目fastDFS分布式文件系统(四)-fastCGI项目相关技术以及linux搜狗输入法相关问题。

目录 1. Nginx作为web服务器处理请求 2. http协议复习 Get方式提交数据 Post方式提交数据 3. fastCGI 3.1 CGI 3.2 fastCGI 3.3 fastCGI和spawn-fcgi安装 1. 安装fastCGI 2. 安装spawn-fcgi 3.4 nginx && fastcgi 4其他知识点 1. fastCGI环境变量 - fas…

滑动验证码-elementui实现

使用elementui框架实现 html代码 <div class"button-center"><el-popoverplacement"top":width"imgWidth"title"安全验证"trigger"manual"v-model"popoverVisible"hide"popoverHide"show&quo…

P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布

题目描述 石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一样&#xff0c;则不分胜负。在《生活大爆炸》第二季第 8 集中出现了一种石头剪刀布的升级版游戏。 升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势: 斯波克:《星际迷航》主…

FairyGUI编辑器自定义菜单扩展插件

本文涉及到的软件有&#xff1a;FairyGUI&#xff0c;VSCode 代码环境涉及到了&#xff1a;Lua VSCode插件&#xff1a;EmmyLua 在编写FairyGUI编辑器菜单前&#xff0c;了解一下FairyGUIEditor的API会有效的帮助我们解决很多问题。FairyGUI的扩展是通过编辑器自带的插件功能…

面试-快速学习计算机网络-UDP/TCP

1. OSI四层和七层映射 区别&#xff1a; 应用层&#xff0c;表示层&#xff0c;会话层合并为了应用层数据链路层和物理层合并为了网络接口层 2. TCP和UDP的区别&#xff1f; 总结&#xff1a; 1 . TCP 向上层提供面向连接的可靠服务 &#xff0c;UDP 向上层提供无连接不可靠服…

Lnton羚通算法算力云平台在环境配置中Windows10终端和VSCode下如何打开Anaconda-Prompt

在Windows 10的终端和VSCode中&#xff0c;可以直接打开Anaconda Prompt。下面是两种方法&#xff1a; Windows 10终端&#xff1a;在开始菜单中搜索"Anaconda Prompt"&#xff0c;然后点击打开。这将启动Anaconda Prompt终端&#xff0c;你可以在其中执行conda相关命…

2337. 移动片段得到字符串

题目描述&#xff1a; 给你两个字符串 start 和 target &#xff0c;长度均为 n 。每个字符串 仅 由字符 ‘L’、‘R’ 和 ‘_’ 组成&#xff0c;其中&#xff1a; 字符 ‘L’ 和 ‘R’ 表示片段&#xff0c;其中片段 ‘L’ 只有在其左侧直接存在一个 空位 时才能向 左 移动&a…

通过Matlab编程分析微分方程、SS模型、TF模型、ZPK模型的关系

微分方程、SS模型、TF模型、ZPK模型的关系 一、Matlab编程 微分方程、SS模型、TF模型、ZPK模型的关系二、对系统输出进行微分计算三、对系统输出进行积分计算四、总结五、系统的零点与极点的物理意义参考 &#xff1a;[https://www.zhihu.com/question/22031360/answer/3073452…