分库分表以后,如何实现扩容?

news2024/9/22 11:33:19

在实际开发中,数据库的扩容和不同的分库分表规则直接相关,今天我们从系统设计的角度,抽象了一个项目开发中出现的业务场景,从数据库设计、路由规则,以及数据迁移方案的角度进行讨论。

从业务场景出发进行讨论

假设这样一个业务场景,现在要设计电商网站的订单数据库模块,经过对业务增长的估算,预估三年后,数据规模可能达到 6000 万,每日订单数会超过 10 万。

首先选择存储实现,订单作为电商业务的核心数据,应该尽量避免数据丢失,并且对数据一致性有强要求,肯定是选择支持事务的关系型数据库,比如使用 MySQL 及 InnoDB 存储引擎。

然后是数据库的高可用,订单数据是典型读多写少的数据,不仅要面向消费者端的读请求,内部也有很多上下游关联的业务模块在调用,针对订单进行数据查询的调用量会非常大。基于这一点,我们在业务中配置基于主从复制的读写分离,并且设置多个从库,提高数据安全。

最后是数据规模,6000 万的数据量,显然超出了单表的承受范围,参考《阿里巴巴 Java 开发手册》中「单表行数超过 500 万行」进行分表的建议,此时需要考虑进行分库分表,那么如何设计路由规则和拆分方案呢?接下来会对此展开讨论。

路由规则与扩容方案

现在我们考虑 3 种路由规则:对主键进行哈希取模、基于数据范围进行路由、结合哈希和数据范围的分库分表规则。

1. 哈希取模的方式

哈希取模是分库分表中最常见的一种方案,也就是根据不同的业务主键输入,对数据库进行取模,得到插入数据的位置。

6000 万的数据规模,我们按照单表承载百万数量级来拆分,拆分成 64 张表,进一步可以把 64 张表拆分到两个数据库中,每个库中配置 32 张表。当新订单创建时,首先生成订单 ID,对数据库个数取模,计算对应访问的数据库;接下来对数据表取模,计算路由到的数据表,当处理查询操作时,也通过同样的规则处理,这样就实现了通过订单 ID 定位到具体数据表。

3.png


规则示意图

通过哈希取模的方式进行路由,优点是数据拆分比较均匀,但缺点是不利于后面的扩容。假设我们的订单增长速度超出预估,数据规模很快达到了几亿的数量级,原先的数据表已经不满足性能要求,数据库需要继续进行拆分。

数据库拆分以后,订单库和表的数量都需要调整,路由规则也需要调整,为了适配新的分库分表规则,保证数据的读写正常,不可避免地要进行数据迁移,具体的操作,可以分为停机迁移不停机迁移两种方式。

  • 停机迁移

停机迁移的方式比较简单,比如我们在使用一些网站或者应用时,经常会收到某段时间内暂停服务的通知,一般是在这段时间内,完成数据迁移,将历史数据按照新的规则重新分配到新的存储中,然后切换服务。

  • 不停机迁移

不停机迁移也就是常说的动态扩容,依赖业务上的双写操作实现,需要同时处理存量和增量数据,并且做好各种数据校验。

一般来说,具体的数据库扩容方式有基于原有存储增加节点,以及重新部署一套新的数据库两种策略,针对不同的扩容方式,需要不同的迁移方案和双写策略支持。

如果重新部署新的数据库存储,可以粗略地分为以下的步骤:

  • 创建一套新的订单数据库;

  • 在某个时间点上,将历史数据按照新的路由规则分配到新的数据库中;

  • 在旧数据库的操作中开启双写,同时写入到两个数据库;

  • 用新的读写服务逐步替代旧服务,同步进行数据不一致校验,最后完成全面切流。

这是一个非常简化的流程,实际开发中要处理的细节有很多,感兴趣的同学可以去了解下数据迁移的 ETL 等标准化流程。

2. 基于数据范围进行拆分

基于数据范围进行路由,通常是根据特定的字段进行划分不同区间,对订单表进行拆分中,如果基于数据范围路由,可以按照订单 ID 进行范围的划分。

同样是拆分成 64 张数据表,可以把订单 ID 在 3000万 以下的数据划分到第一个订单库,3000 万以上的数据划分到第二个订单库,在每个数据库中,继续按照每张表 100万 的范围进行划分。

4.png


规则示意图

可以看到,基于数据范围进行路由的规则,当进行扩容时,可以直接增加新的存储,将新生成的数据区间映射到新添加的存储节点中,不需要进行节点之间的调整,也不需要迁移历史数据。

但是这种方式的缺点就是数据访问不均匀。如果按照这种规则,另外一个数据库在很长一段时间内都得不到应用,导致数据节点负荷不均,在极端情况下,当前热点库可能出现性能瓶颈,无法发挥分库分表带来的性能优势。

3. 结合数据范围和哈希取模

现在考虑,如果结合以上两种方式数据范围和哈希取模,那么是不是可以实现数据均匀分布,也可以更好地进行扩容?

我们设计这样的一个路由规则,首先对订单 ID 进行哈希取模,然后对取模后的数据再次进行范围分区。

5.png


订单数据库进一步拆分

可以看到,通过哈希取模结合数据区间的方式,可以比较好地平衡两种路由方案的优缺点。当数据写入时,首先通过一次取模,计算出一个数据库,然后使用订单 ID 的范围,进行二次计算,将数据分散到不同的数据表中。

这种方式避免了单纯基于数据范围可能出现的热点存储,并且在后期扩展时,可以直接增加对应的扩展表,避免了复杂的数据迁移工作。

上面我们通过一个业务场景设计,思考了分库分表下的几种路由规则和扩容方案,这是一个开放性问题,思路要比方案更重要,而实际业务也要比这个复杂得多,你可以结合项目实践,思考在你负责的模块中,是如何设计路由规则,以及可以如何进行数据扩容的。

总结

本文从一个真实业务场景的设计出发,分享了分库分表不同路由规则的设计,对应的优缺点,以及对扩容方式的影响。

今天的问题如果出现在面试中,可以认为是一个典型的系统设计类问题,那么回答系统设计类问题,有哪些要注意的点呢?

首先,系统设计类问题出现在面试中,很重要的一方面是考察沟通,要和面试官确认整体的数据规模,输入和输出,明确系统设计的边界,比如数据规模不同,直接影响数据库表的设计方式。

其次,是找到主要问题,理解系统的瓶颈,然后就可以应用各种系统设计的技巧,进行各个业务层的设计。

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

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

相关文章

LeetCode(60)K 个一组翻转链表【链表】【困难】

目录 1.题目2.答案3.提交结果截图 链接: K 个一组翻转链表 1.题目 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。 k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xf…

1231. 航班时间(整行字符串输入:getline(cin,line))

题目: 1231. 航班时间 - AcWing题库 输入样例: 3 17:48:19 21:57:24 11:05:18 15:14:23 17:21:07 00:31:46 (1) 23:02:41 16:13:20 (1) 10:19:19 20:41:24 22:19:04 16:41:09 (1)输出样例: 04:09:05 12:10:39 14:22:05 思路: …

Jmeter分布式性能测试,80%资深测试都会遇到这个坑!

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…

鸿蒙HarmonyOS4.0 入门与实战

一、开发准备: 熟悉鸿蒙官网安装DevEco Studio熟悉鸿蒙官网 HarmonyOS应用开发官网 - 华为HarmonyOS打造全场景新服务 应用设计相关资源: 开发相关资源: 例如开发工具 DevEco Studio 的下载 应用发布: 开发文档:

PMP项目管理 - 质量管理

系列文章目录 现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. PMP项目管理 - 质量管理 系列文章目录一、规划质量管理 - 关注工作需要达到的质量二、管理…

爆火的“数字人”,你还不知道吗?

数字人是一种基于人工智能技术创建的虚拟实体,具有高度智能化和交互性。他们可以像真正的人类一样思考、学习和表达情感,与人类进行对话和互动。数字人的出现在电影中已经有了一些令人难忘的片段。 首先,值得一提的是电影《阿凡达》中的数字…

maui中实现加载更多 RefreshView跟ListView(1)

效果如图: MainPage.xaml.cs: using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Xaml; using System.ComponentModel; using System.Runtime.CompilerServices…

基于Java SSM框架实现智能停车场系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现智能停车场系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个智能停车场管理系统,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述…

【KMP】【判断是否是重复子字符串】Leetcode 459 重复的子字符串

【KMP】【判断是否是重复子字符串】Leetcode 459 重复的子字符串 解法1 拼接字符串-掐头去尾后判断是否含有原字符串解法2 KMP——重复子串的最小单位是这个字符串里的最长相等前后缀所不包含的子串解法3 暴力解法KMP ---------------🎈🎈题目链接&…

编译 pywinhook v1.6.2 的环境设置和步骤

准备做一个鼠标事件响应程序。 查了一下相关python的第三方类库,发现有 pyhook。 一、起源 pyhook 1、pyhook是最早的版本 pyhook支持的python版本比较低,代码在 https://sourceforge.net/projects/pyhook/ 2、之后产生了两个并行版本 pyHook3 和 p…

来聊聊Spring的循环依赖

文章目录 首先了解一下什么是循环依赖简述解决循环依赖全过程通过debug了解Spring解决循环依赖全过程Aservice的创建递归来到Bservice的创建然后BService递归回到了getAservice的doGetBean中故事再次回到Aservice填充BService的步骤 总结成流程图为什么二级就能解决循环依赖问题…

六个优质开源项目,让你更了解Django框架开发

Django 是一个开源的 Web 应用框架,由 Python 写成。采用了 MTV 的框架模式,即模型 M,视图 V 和模版 T。它最初是被用来开发 CMS 软件的,所以 Django 很适合用来搭建内容类网站,它的设计目的是使常见的 Web 开发任务变…

【Nginx】Nginx了解(基础)

文章目录 Nginx产生的原因Nginx简介Nginx的作用反向代理负载均衡策略动静分离 Nginx的Windows下的安装Linux下的安装Nginx常用命令 负载均衡功能演示 Nginx产生的原因 背景 一个公司的项目刚刚上线的时候,并发量小,用户使用的少,所以在低并发…

大数据技术之Shell(超级详细)

大数据技术之Shell(超级详细) 第1章 Shell概述 Shell 是一种脚本语言,用于在操作系统的命令行界面(CLI)下执行命令和脚本。在大数据领域,Shell 脚本常用于编写数据处理和分析任务的自动化脚本&#xff0c…

B站剧场播放模式2.0

文章目录 v 1.01、新版本改进1-1 去掉了冗余1-2 剧场模式增强1-3 演示视频 2、代码 v 1.0 油猴脚本-Bilibili剧场模式仿Youtube-CSDN博客 https://blog.csdn.net/qq_45020818/article/details/131751288 功能比较粗糙,很多细节不完善,代码也写的很乱。 …

地图自定义省市区合并展示数据整合

需求一:将省级地图下的两个市合并成一个区域,中间的分割线隐藏。 1、访问下方地址,搜索并下载省级地图json文件。 地址:https://datav.aliyun.com/portal/school/atlas/area_selector 2、切换到边界生成器,上传刚刚下…

Milesight VPN server.js 任意文件读取漏洞(CVE-2023-23907)

0x01 产品简介 MilesightVPN 是一款软件,一个 Milesight 产品的 VPN 通道设置过程更加完善,并可通过网络服务器界面连接状态。 0x02 漏洞概述 MilesightVPN server.js接口处存在文件读取漏洞,攻击者可通过该漏洞读取系统重要文件&#xff…

(1)(1.7) HOTT telemetry

文章目录 前言 1 布线和设置 2 参数说明 前言 Plane-4.0.0(及更高版本)、Copter-4.0.4(及更高版本)和 Rover-4.1.0(及更高版本)支持 Graupner HOTT 遥测技术。 1 布线和设置 与自动驾驶仪的连接可通过…

HNU-计算机网络-实验3-应用层和传输层协议分析(PacketTracer)

计算机网络 课程基础实验三应用层和传输层协议分析(PacketTracer) 计科210X 甘晴void 202108010XXX 【给助教的验收建议】 如果是助教,比起听同学读报告,更好的验收方式是随机抽取一个场景(URL/HTTPS/FTP&#xff09…

Vue笔记-在axios中的than函数中使用this需要注意的地方

在Vue中,可以使用this关键字来访问到组件中定义的变量。然而,在axios的then函数中,this关键字的作用域会改变,会指向axios对象本身而不是Vue组件实例。因此,不能直接访问到Vue组件中定义的变量。 解决这个问题的一种方…