【进阶篇】MySQL分库分表详解

文章目录

  • 0. 前言
    • 1. 垂直分库分表
    • 2. 水平分库分表
  • 1. 理解过程及实现方案
      • 问题讨论
      • 衍生出分库分表策略
      • 借助成熟组件使用
      • 分库分表阶段完成后面临的问题
        • 1. 异地多活问题
        • 2. 数据迁移问题
        • 3. 分布式事务问题
        • 4. join查询的问题
    • 分库分表的策略实现示例
  • 2. 参考文档

在这里插入图片描述

0. 前言

假设有一个电商网站,随着用户量和订单量的增加,单一数据库难以承载如此庞大的数据量,查询速度也逐渐降低,这时就需要进行分库分表。

1. 垂直分库分表

电商网站有用户模块和订单模块,可以将用户表和订单表拆分到不同的数据库中。例如,原本在同一个数据库中的用户表(包含用户基础信息和用户扩展信息)和订单表,可以拆分为两个数据库,一个数据库存储用户的基础信息,另一个数据库存储用户的扩展信息和订单信息。

最常见的博客文章都是以电商系统作为案例,因为他是最具备代表性,电商网站的用户模块和订单模块是可以拆分到不同的数据库中的。这种拆分方式可以提高系统的可扩展性和性能。

假设有一个电商网站,它有一个数据库,其中包含两个表:用户表(User)和订单表(Order)。用户表包含用户的基础信息(如用户名、密码等)和用户的扩展信息(如用户的购物偏好、历史订单等)。订单表包含订单的详细信息(如订单号、购买的商品、数量、价格等)。

原始结构可能如下:

Database: EcommerceDBTable: User- UserID- Username- Password- Preferences- HistoryOrdersTable: Order- OrderID- UserID- Product- Quantity- Price

可以将这个数据库拆分为两个数据库:一个数据库(UserDB)存储用户的基础信息,另一个数据库(OrderDB)存储用户的扩展信息和订单信息。

拆分后的结构可能如下:

Database: UserDBTable: UserBasic- UserID- Username- PasswordDatabase: OrderDBTable: UserExtension- UserID- Preferences- HistoryOrdersTable: Order- OrderID- UserID- Product- Quantity- Price

这样,当用户的基础信息和订单信息需要进行大量的读写操作时,这两个操作可以在不同的数据库上并行进行,从而提高系统的性能。同时,由于用户的基础信息和订单信息被存储在不同的数据库中,因此,如果其中一个数据库出现问题,也不会影响到另一个数据库的正常运行,从而提高了系统的可用性。

2. 水平分库分表

假设订单表中有上百万条数据,查询和写入速度逐渐下降。此时,可以根据订单ID进行水平分表,比如订单ID为奇数的存入订单表1,订单ID为偶数的存入订单表2。这样,原本一个表需要处理的数据量就减半了,可以提高查询和写入速度。

在进行分库分表后,对于程序查询也需要做相应的调整。例如在进行水平分表后,查询某个订单信息时,需要先判断订单ID是奇数还是偶数,然后再决定查询哪个表。

Database: OrderDBTable: Order- OrderID- UserID- Product- Quantity- Price
Database: OrderDBTable: Order0- OrderID- UserID- Product- Quantity- PriceTable: Order1- OrderID- UserID- Product- Quantity- Price

在这种情况下,Order0用于存储ID为偶数的订单,Order1用于存储ID为奇数的订单。

查询和写入的伪代码可能如下所示:

def get_order(order_id):if order_id % 2 == 0:# Query Order0 tablereturn query_order_0(order_id)else:# Query Order1 tablereturn query_order_1(order_id)

这样,我们可以根据订单ID的奇偶性来决定查询或写入哪个表,从而将原本一个表需要处理的数据量减半,提高查询和写入速度。

实际的分库分表会更复杂。同时,分库分表也可能会带来一些问题,如数据一致性问题、跨库事务问题等。因此,在设计分库分表方案时,需要进行充分的考虑,并可能需要引入其他的技术(如分布式事务)来解决这些问题。

那么,让一起深入了解一下数据库知识应用实践之分库分表。

1. 理解过程及实现方案

记住一句话,不是所有系统一上来就搞分库分表,包括淘宝,京东。尤其这种超前设计,对小公司来说就是累赘,甚至隐患。不仅人才成本,资源成本,运维成本。甚至学习成本都不容小觑。所以基本上都是不断衍生到分库分表,才算是中小公司正确的技术路线和最优实践。

我们以一个场景:例如有一个电子商务网站,随着业务的发展,用户数量、商品数量和交易数量都在快速增长。原来单一的数据库已经无法满足需求,查询速度慢,系统负载高,甚至出现宕机情况。这样的情况下,为了提高系统的性能和稳定性,就需要进行数据库的分库分表。

问题讨论

分库分表的目的是为了解决单个数据库无法承受大量数据和高并发的问题。但是分库分表也会带来一些问题,例如数据一致性问题、分布式事务问题、跨库跨表查询问题、数据迁移问题等。

衍生出分库分表策略

  1. 垂直分库分表:按业务模块进行分库,将大表按照字段进行分表,例如用户库、商品库等。

  2. 水平分库分表:将数据按一定的规则分散到不同的数据库或表中,例如按用户ID的hash值分库,按订单时间分表等。

借助成熟组件使用

常见框架:

  1. MyCat:一个开源的分库分表中间件,支持自定义分片规则,可以实现读写分离、事务和SQL的完全透明。
  2. Sharding-JDBC:一款轻量级的Java框架,提供了强大的分库分表、读写分离、分布式事务和分布式序列等功能。
  3. Shardingsphere:包含了Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这三款独立的产品,可以满足不同场景下的数据分片需求。
    分库分表的复杂问题:

分库分表阶段完成后面临的问题

当技术演进到我们已经解决了分库分表基本问题,解决了并发问题,解决性能问题,接下来我们基本上面临如下几个问题。关于这些问题又需要我们继续去学习和研究尝试更多方案。此处我们不做展开。

1. 异地多活问题

在数据库地理分布、灾备等问题上,如果是多库多表的情况,数据同步和备份的复杂度将会增加。

2. 数据迁移问题

.在分库分表后,如何对旧数据进行迁移以及如何在迁移过程中保证业务的正常运行是个大问题。

3. 分布式事务问题

在传统的单体数据库中,事务是保证数据一致性的重要手段。但在分库分表的环境下,原有的事务机制不能再使用,需要引入新的分布式事务解决方案。

4. join查询的问题

在分库分表后,原本在一个库或一个表中可以做的join查询就变得困难,需要通过应用层去做关联和组合。

分库分表的策略实现示例

  1. 函数法(哈希、取模等):根据某个字段(比如用户ID)的函数结果进行分库分表。
  2. 范围法(枚举、区间):比如根据日期范围,订单ID范围等进行分库分表。
  3. 一致性哈希:在新增或减少数据库节点的时候,能够最小化数据的迁移。

我们用Java写一些伪代码方便大家理解。
假设我们有多种根据某个值(如用户ID或订单ID)来确定应将数据存储在哪个数据库的方式。我们分别用函数法,范围法和一致性哈希法三种方法模拟一下。

  1. 函数法:我们可以将用户ID除以数据库数量的余数作为数据库的索引。
public String getDatabase(int userId) {int dbCount = 2; // 假设我们有2个数据库int dbIndex = userId % dbCount;return "db" + dbIndex;
}
  1. 范围法:我们可以使用订单ID作为范围进行划分,比如订单ID小于10000的存储在一个数据库,大于等于10000的存储在另一个数据库。
public String getDatabase(int orderId) {if (orderId < 10000) {return "db0";} else {return "db1";}
}
  1. 一致性哈希:这种方法需要使用到特殊的数据结构,例如TreeMap。首先,我们将每个数据库(称为节点)添加到一个TreeMap中,然后计算键(如用户ID)的哈希值,并在TreeMap中找到该哈希值对应的数据库。如果没有找到,则返回哈希值最接近的数据库。
public class ConsistentHashing {private TreeMap<Integer, String> nodes = new TreeMap<>();public void addNode(String nodeName) {int hash = nodeName.hashCode();nodes.put(hash, nodeName);}public void removeNode(String nodeName) {int hash = nodeName.hashCode();nodes.remove(hash);}public String getDatabase(String key) {if (nodes.isEmpty()) {return null;}int hash = key.hashCode();if (!nodes.containsKey(hash)) {SortedMap<Integer, String> tailMap = nodes.tailMap(hash);hash = tailMap.isEmpty() ? nodes.firstKey() : tailMap.firstKey();}return nodes.get(hash);}
}

其实真实场景中我们大多都使用分库分表组件或者中间件,最著名的和大家最常用的sharding-jdbc就是解决这类场景的一个优秀的,轻量级的分库分表组件,虽然有很多bug或者不足,但是足以解决我们90%的问题了。后面有一个章节我会写一个详细教程关于sharding-jdbc使用详解。除了它还有一些国产的中间件也不错。如下

  1. TDDL:阿里巴巴开源的分库分表中间件,支持复杂的分库分表策略。
  2. Oceanus:网易云数据库的分库分表解决方案,支持自动分库分表、读写分离、分布式事务等功能。

2. 参考文档

  1. “MySQL分库分表方案” - InfoQ。介绍了 MySQL 的分库分表方案,并对实施这种方案的步骤进行了详细的讨论。链接:https://www.infoq.cn/article/solution-of-mysql-sub-database-and-sub-table

  2. “MySQL 分库分表实践” - 阿里云社区的一篇文章也可以参考学习。介绍了 MySQL 分库分表的实践和经验。链接:https://developer.aliyun.com/article/776687

  3. “分库分表架构设计” 详细介绍了分库分表架构的设计和实施。链接:https://www.jianshu.com/p/d7f3d3808f25

  4. ShardingSphere 是 Apache 的一个开源项目包包含了我上面说的sharding-jdbc,提供了分库分表的解决方案。链接:https://shardingsphere.apache.org/document/current/cn/overview/

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

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

相关文章

46、SpringBoot输入校验--JSR 303

★ Spring Boot的输入校验 springboot支持两种校验方式&#xff1a;1. Spring原生提供的 Validation&#xff0c;这种验证方式需要开发者手写验证代码&#xff0c;比较繁琐。就是普通的if判断2. 使用JSR 303的校验&#xff0c;这种验证方式只需使用注解、即可以声明式的方式进…

4G版本云音响设置教程阿里云平台版本

4G版本云音响设置教程介绍 第一章 介绍了在阿里云物联网平台生一个设备使用的三元素 第二章 转换阿里云三元素 为MQTT参数&#xff0c;并下载到设备中 第三章 阿里云物联网套件协议使用说明&#xff0c;如何发送数据至设备并播放 本文目录引导 目录 4G版本云音响设置教程介…

利用frps搭建本地自签名https服务的透传

nginx的搭建就不介绍了&#xff0c;教程很多&#xff0c;基本上油手就会。 在本例中&#xff0c;frp服务器的域名是 www.yourfrp.com&#xff0c;同时也是反向代理nginx服务器; 本地网站要用的域名&#xff1a; test.abcd.com 请事先将 test.abcd.com 解析到 frp所在服务器…

大数据面试题:MapReduce压缩方式

面试题来源&#xff1a; 《大数据面试题 V4.0》 大数据面试题V3.0&#xff0c;523道题&#xff0c;679页&#xff0c;46w字 可回答&#xff1a;1&#xff09;Hadoop常见的压缩算法有哪些&#xff1f; 问过的一些公司&#xff1a;网易云音乐(2022.11)&#xff0c;阿里(2020.…

重写 UGUI

重写Button using UnityEngine; using UnityEngine.UI; public class MyButton : Button {[SerializeField] private int _newNumber; }using UnityEditor;//编辑器类在UnityEditor命名空间下。所以当使用C#脚本时&#xff0c;你需要在脚本前面加上 "using UnityEditor&q…

华为云云服务器评测 [Vue3 博物馆管理系统] 使用Vue3、Element-plus菜单组件构建轮播图

系列文章目录 第一章 定制上中下&#xff08;顶部菜单、底部区域、中间主区域显示&#xff09;三层结构首页 第二章 使用Vue3、Element-plus菜单组件构建菜单 第三章 使用Vue3、Element-plus菜单组件构建轮播图 [第四章 使用Vue3、Element-plus菜单组件构建组图文章] 华为云云…

如何中mac上安装多版本python并配置PATH

摘要 mac 默认安装的python是 python3&#xff0c;但是如果我们需要其他python版本时&#xff0c;该怎么办呢&#xff1f; 例如&#xff1a;需要python2 版本&#xff0c;如果使用homebrew安装会提示没有python2。同时使用python --version 会发现commond not found。 所以本…

uniapp小程序单页面改变手机电量,头部通知的颜色效果demo(整理)

onShow(){ // 改变电池的颜色 wx.setNavigationBarColor({ frontColor: ‘#ffffff’, //只支持两种颜色 backgroundColor: ‘#ffffff’, animation: { duration: 1 } }) }

Android 13 - Media框架(9)- NuPlayer::Decoder

这一节我们将了解 NuPlayer::Decoder&#xff0c;学习如何将 MediaCodec wrap 成一个强大的 Decoder。这一节会提前讲到 MediaCodec 相关的内容&#xff0c;如果看不大懂可以先跳过此篇。原先觉得 Decoder 部分简单&#xff0c;越读越发现自己的无知&#xff0c;Android 源码真…

IDEA设置文件编码

IDEA设置文件编码 File->Settings->Editor->File Encodings 均设置为utf-8 新项目 设置 文件编码 点击New Projects Setup 再点击Settings for New Projects File->Settings->Editor->File Encodings 均设置为utf-8

【Linux】文件

Linux 文件 什么叫文件C语言视角下文件的操作文件的打开与关闭文件的写操作文件的读操作 & cat命令模拟实现 文件操作的系统接口open & closewriteread 文件描述符进程与文件的关系重定向问题Linux下一切皆文件的认识文件缓冲区缓冲区的刷新策略 stuout & stderr 什…

windows笔记本远程连接如何打开任务管理器?

参考素材&#xff1a; https://jingyan.baidu.com/article/8275fc86a97f5207a03cf6cd.html https://www.anyviewer.cn/how-to/ctrl-alt-delete-remote-desktop-6540.html 网上查了很多方法&#xff0c;都说ctrlaltend可以解决这个问题。 但是笔记本键盘上没有end键。 继续查了一…

【MATLAB第71期】基于MATLAB的Abcboost自适应决策树多输入单输出回归预测及多分类预测模型(更新中)

【MATLAB第71期】基于MATLAB的Abcboost自适应决策树多输入单输出回归预测及多分类预测模型&#xff08;更新中&#xff09; 一、效果展示&#xff08;多分类预测&#xff09; 二、效果展示&#xff08;回归预测&#xff09; 三、代码获取 CSDN后台私信回复“71期”即可获取下…

c++:QT day2 信号和槽

1.多态&#xff1a; 静态多态&#xff1a;函数的重载 动态多态&#xff1a;程序运行 多态的实现:父类的指针或引用&#xff0c;指向或初始化子类的对象&#xff0c;调用子类对父类重写的函数&#xff0c;进而展开子类的功能 2.虚函数&#xff1a;用virtua关键字修饰的函数是虚函…

【算法】leetcode 105 从前序与中序遍历序列构造二叉树

题目 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,20,7] Output: [3,9,20,null,null,15,7]示例 2: Input: pr…

SpringBoot自定义消息总线

一、前言 在现代的分布式系统中&#xff0c;消息传递已成为一个非常流行的模式。它使得系统内的不同部分可以松耦合地通信&#xff0c;从而实现更高效、更可靠的应用程序。本博客将介绍SpringBoot如何提供简单易用的消息传递机制&#xff0c;并展示如何自定义消息总线以满足特定…

kafka详解二

kafka详解二 1、 offset 1.1 offset介绍 老版本 Consumer 的位移管理是依托于 Apache ZooKeeper 的&#xff0c;它会自动或手动地将位移数据提交到 ZooKeeper 中保存。当 Consumer 重启后&#xff0c;它能自动从 ZooKeeper 中读取位移数据&#xff0c;从而在上次消费截止的地…

【探索SpringCloud】服务发现-Nacos服务端数据结构和模型

前言 上一文中&#xff0c;我们从官方的图示了解到Nacos的服务数据结构。但我关心的是&#xff0c;Nacos2.x不是重构了吗&#xff1f;怎么还是这种数据结构&#xff1f;我推测&#xff0c;必然是为了对Nacos1.x的兼容&#xff0c;实际存储应该不是这样的。于是&#xff0c;沿着…

vue的第2篇 第一个vue程序

一 环境的搭建 1.1常见前端开发ide 1.2 安装vs.code 1.下载地址&#xff1a;Visual Studio Code - Code Editing. Redefined 2.进行安装 1.2.1 vscode的中文插件安装 1.在搜索框输入“chinese” 2.安装完成重启&#xff0c;如下变成中文 1.2.2 修改工作区的颜色 选中[浅色]…

opencv 提取选中区域内指定hsv颜色的水印

基于《QT 插件化图像算法研究平台》做的功能插件。提取选中区域内指定hsv颜色的水印。 《QT 插件化图像算法研究平台》有个HSV COLOR PICK功能&#xff0c;可以很直观、方便地分析出水印 的hsv颜色&#xff0c;比如, 蓝色&#xff1a;100,180,0,255,100,255。 然后利用 opencv …