Mysql-经典实战案例(3): pt-archiver 实现 MySQL 千万级大表分库分表(上)

news2025/3/18 15:30:36

零基础实战:使用 pt-archiver 实现 MySQL 千万级大表的水平分表(Hash分片)


本文适合人群:MySQL新手、想低成本实践数据库分表的开发者
环境要求:MySQL 5.7+、Linux系统(建议CentOS/Ubuntu)
你将学会

  • 📦 1分钟生成百万测试数据
  • 🔧 安全拆解大表为5个哈希分片表
  • 🛠 零停机分表迁移实操技巧

一、为什么需要分表?

假设您有一张 订单表 orders 数据达到 1000万行,面临以下问题:
1️⃣ 查询变慢SELECT * FROM orders WHERE user_id='xxx' 需要扫描全表
2️⃣ 维护困难:索引膨胀、备份耗时
3️⃣ 容灾风险:单表损坏可能导致业务瘫痪

解决方案
👉 Hash分表:将数据按 user_id 的哈希值分散到 orders_0~orders_4 五个分片中,查询永远只需扫一张小表!


二、5分钟快速搭建测试环境

环境准备清单

  1. 安装 MySQL 5.7(已安装可跳过)

    # Ubuntusudo apt install mysql-server-5.7# CentOSsudo yum install mysql-community-server
    
  2. 安装 Percona Toolkit

    # 所有Linux版本通用wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.debsudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.debsudo apt-get updatesudo apt-get install percona-toolkit
    
  3. 创建测试数据库

    CREATE DATABASE test_sharding;USE test_sharding;
    
  4. 开启LOCAL INFILE参数

    允许客户端从本地文件系统中读取数据文件,并将其内容加载到远程 MySQL 服务器的表中,使用pt-archiver分片导入的前提参数。

    local_infile = on
    

三、1分钟生成百万测试数据

复制下列代码到 MySQL客户端,快速生成100万测试订单:

-- 创建原始订单表
CREATE TABLE orders (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id VARCHAR(20) NOT NULL,  -- 分片键(关键字段)
  amount DECIMAL(10,2) NOT NULL,
  create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

-- 快速填充100万数据(耗时约30秒)
INSERT INTO orders (user_id, amount)
SELECT 
  CONCAT('user_', FLOOR(RAND() * 1000000)),
  ROUND(RAND() * 100, 2)
FROM 
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) a,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) b,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) c,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) d,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) e,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) f,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) g,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) h,
  (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) i;

执行成功后验证

SELECT COUNT(*) FROM orders; 

四、哈希分表实战:拆解大表为5个分片

1. 创建分片表

-- 创建5个分片表(结构与原表一致)
CREATE TABLE orders_0 LIKE orders;
CREATE TABLE orders_1 LIKE orders;
CREATE TABLE orders_2 LIKE orders;
CREATE TABLE orders_3 LIKE orders;
CREATE TABLE orders_4 LIKE orders;

2. 关键分片逻辑

通过 哈希函数 CRC32 将数据均匀分散到分片中:

CRC32(user_id) % 5 = 0 → 存入 orders_0  
CRC32(user_id) % 5 = 1 → 存入 orders_1  
... 以此类推

3. 使用 pt-archiver 迁移数据

将原表数据按 Hash 规则迁移到分片表(不锁表、不影响线上业务):

迁移到 orders_0 分片
/opt/percona-toolkit-3.6.0/bin/pt-archiver --source h=127.0.0.1,P=3306,u=root,p=密码,D=test_sharding,t=orders --dest h=127.0.0.1,P=3306,u=root,p=密码,D=test_sharding,t=orders_0 --where "CRC32(user_id) %5=0" --limit 500 --commit-each --bulk-insert --no-delete --no-check-charset

迁移其他分片

修改 --where 条件和目标表名,依次执行:

# orders_1(余数1)
pt-archiver ... --where "CRC32(user_id) %5=1" --dest t=orders_1

# orders_2(余数2)
pt-archiver ... --where "CRC32(user_id) %5=2" --dest t=orders_2
...(省略orders_3/4)


五、分片结果验证

1. 核对各分片数据量

SELECT 
  table_name AS '分片表',
  FORMAT(table_rows,0) AS '数据量'
FROM information_schema.tables 
WHERE table_schema = 'test_sharding' 
  AND table_name LIKE 'orders_%';

期望结果(误差应小于2%):

+-----------+-----------+
| 分片表    | 数据量    |
+-----------+-----------+
| orders_0  | 390,780   |
| orders_1  | 390,112   |
| orders_2  | 389,778   |
| orders_3  | 388,776   |
| orders_4  | 389,778   |
+-----------+-----------+

2. 数据完整性检验

-- 所有分片总和 = 原表总数
SELECT 
  (SELECT COUNT(*) FROM orders_0) + 
  (SELECT COUNT(*) FROM orders_1) +
  (SELECT COUNT(*) FROM orders_2) +
  (SELECT COUNT(*) FROM orders_3) +
  (SELECT COUNT(*) FROM orders_4) AS total_count;

-- 应与原表数据量一致
SELECT COUNT(*) FROM orders;

注意!pt-archiverBug不会迁移max(id)那条数据,需要手动完成最后一行数据的迁移

定位数据差异

SELECT * 
FROM orders 
WHERE NOT EXISTS (
  SELECT 1 FROM orders_0 WHERE orders_0.id = orders.id UNION ALL
  SELECT 1 FROM orders_1 WHERE orders_1.id = orders.id UNION ALL
  SELECT 1 FROM orders_2 WHERE orders_2.id = orders.id UNION ALL
  SELECT 1 FROM orders_3 WHERE orders_3.id = orders.id UNION ALL
  SELECT 1 FROM orders_4 WHERE orders_4.id = orders.id 
) 
LIMIT 1;

+---------+-----------+--------+---------------------+
| id      | user_id   | amount | create_time         |
+---------+-----------+--------+---------------------+
| 1953125 | user_9823 |  39.33 | 2025-03-14 17:03:24 |
+---------+-----------+--------+---------------------+

使用insert 插入最后一条数据到orders_4表

INSERT INTO orders_4 (id, user_id, amount, create_time)
SELECT id, user_id, amount, create_time 
FROM orders 
WHERE id=1953125;


六、常见问题排雷指南

1. 迁移性能慢(每秒不到1000条)

  • 优化技巧

    -- 增加批量大小(视内存调整)
    --limit 1000 \
    --bulk-insert \
    

2. 主键冲突错误

  • 解决方案

    • 迁移前清空分片表:TRUNCATE orders_0
    • 或使用 --replace 参数覆盖已有数据

3. 数据分布不均匀

  • 原因排查

    • 检查分片键是否有倾斜(如某user_id占比过高)
    • 改用 一致性哈希算法(如 SHA1(user_id)

七、分表后如何查询数据?

通过业务代码计算目标分片,直连对应表:

# Python示例:按user_id定位分片
user_id = "user_12345"
shard_no = crc32(user_id.encode()) % 5  # 计算分片编号
table_name = f"orders_{shard_no}"
query = f"SELECT * FROM {table_name} WHERE user_id = %s"

总结

通过本方案,我们实现了:

  • 🚀 100万数据安全拆分:无锁迁移、分钟级完成
  • 📊 分布式查询提速:查询性能提升5~10倍
  • 🔒 数据零丢失保证:每一步操作均可回滚验证

下一篇预告
1、如何完成垂直分表?将单表中高频访问的"热数据"与低频使用的"冷数据"分离存储!
2、如何可以将分片逻辑封装到中间件(如 MyCAT),彻底告别单表性能瓶颈!

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

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

相关文章

SSM框架——Spring面试题

Spring常见面试题 Spring框架中的单例bean是线程安全的吗 不是线程安全的 Spring框架中有一个Scope注解,默认的值就是singleton,单例的。 因为一般在spring的bean的中都是注入无状态的对象,没有线程安全问题,如果在bean中定义了可…

云原生大佬重生,记忆逐步复苏(十三:selinux模块)

目录 1:什么是selinux 1.1 SELinux 的作用 1.2. SELinux 的工作原理 1.3. SELinux 的运行模式 2:解析selinux文件上下文标签策略 3:selinux的布尔值 4:调查和解决selinux问题 1:什么是selinux SELinux(Security-Enhanced L…

MySQL高频八股——事务过程中Undo log、Redo log、Binlog的写入顺序(涉及两阶段提交)

大家好,我是钢板兽! 在上一篇文章中,我分别介绍了 Undo Log、Redo Log 和 Binlog 在事务执行过程中的作用与写入机制。然而,实际应用中,这三种日志的写入是有先后顺序的。因此,本篇文章将深入探讨它们的写…

C++进阶——AVL树的实现

1、AVL的概念 1.1 AVL 树的发明 AVL 树由 G.M. Adelson-Velsky 和 E.M. Landis 在 1962 年的论文《An algorithm for the organization of information》中提出。他们的设计目标是解决二叉搜索树在动态操作(插入、删除)中可能退化为链表的问题。 1.2 …

打包当前Ubuntu镜像 制作Ubuntu togo系统

我的系统的基本情况说明: 我原来的系统的具体型号如下: uname -rLinux Engine 5.15.0-134-generic #145~20.04.1-Ubuntu SMP Mon Feb 17 13:27:16 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux我原来的硬盘以及分区策略如下: 可以看到我的分区…

系统架构设计师—案例分析—架构设计

文章目录 经典架构风格对比面向对象架构风格/显示调用风格优点缺点举例 事件驱动的系统/隐式调用风格优点缺点举例 基于规则的系统架构风格优点缺点举例 管道过滤器风格优点缺点举例 仓库风格优点缺点举例 解释器风格优点缺点举例 分层架构风格优点缺点举例 经典架构风格对比 …

基于javaweb的SpringBoot智能相册管理系统图片相册系统设计与实现(源码+文档+部署讲解)

技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

Android 14 Telephony 网络选择功能介绍

一、总体介绍 (一)功能 手动搜网的流程:用户通过UI触发,调用TelephonyManager的API,比如startNetworkScan,然后这个请求会传递到RIL层,通过AT命令与基带通信,进行网络扫描。结果返回后,经过TelephonyRegistry通知应用层。中间可能涉及IPC,比如Binder通信,因为应用和…

深入解析音频编解码器(Audio CODEC):硬件、接口与驱动开发

音频编解码器(Audio CODEC)是音频处理系统中的核心组件,负责 模拟信号与数字信号的相互转换,广泛应用于 智能音箱、嵌入式系统、消费电子产品 等设备。本篇文章将从 硬件结构、接口解析、驱动开发 和 软件配置 等方面,…

深度学习【迭代梯度下降法求解线性回归】

梯度下降法 梯度下降法是一种常用迭代方法,其目的是让输入向量找到一个合适的迭代方向,使得输出值能达到局部最小值。在拟合线性回归方程时,我们把损失函数视为以参数向量为输入的函数,找到其梯度下降的方向并进行迭代&#xff0…

[Lc14_priority_queue] 最后一块石头重量 | 数据流中的第 K 大元素 | 前K个高频单词 | 数据流的中位数

目录 1.最后一块石头的重量 题解 2.数据流中的第 K 大元素 题解 3.前K个高频单词 题解 代码 ⭕4.数据流的中位数 题解 在C中,使用标准库中的priority_queue,默认情况下它是一个最大堆(即大堆排序),这意味着最…

熔断和降级的区别,具体使用场景有哪些?

熔断与降级的核心区别在于触发条件和应用目标,具体差异及使用场景如下: 一、核心区别 对比维度熔断降级触发原因下游依赖服务故障(如超时、异常率过高)触发系统整体负载过高或流量洪峰管理目标层级框架级保护(无业务优…

利用hexo+github部署属于自己的个人博客网站(2025年3月所写)

利用hexogithub部署属于自己的个人博客网站 前情提要:如果你出现了莫名其妙的报错,可能与权限有关,可以以管理员的身份运行git bash或者cmd 本篇博客仅限于利用hexo搭建博客,并且部署到github上面,让自己可以有一个访…

pandas学习笔记(一)——基础知识和应用案例

pandas学习笔记 基础语法参考菜鸟教程:https://www.runoob.com/pandas/pandas-tutorial.html # jupyter import pandas as pd import matplotlib from matplotlib import pyplot as plt import numpy as npmatplotlib.use(TkAgg)data {timestamp: [1, 2, 3, 4, 5…

【AI 大模型】RAG 检索增强生成 ⑤ ( 向量数据库 | 向量数据库 索引结构和搜索算法 | 常见 向量数据库 对比 | 安装并使用 向量数据库 chromadb 案例 )

文章目录 一、向量数据库1、向量数据库引入2、向量数据库简介3、向量数据库 索引结构和搜索算法4、向量数据库 应用场景5、传统数据库 与 向量数据库 对比 二、常见 向量数据库 对比三、向量数据库 案例1、安装 向量数据库 chromadb2、核心要点 解析① 创建数据库实例② 创建数…

解决single cell portal点击下载但跳转的是网页

Single cell RNA-seq of Tmem100-lineage cells in a mouse model of osseointegration - Single Cell Portal 想下载个小鼠数据集: 点击下载跳转为网页: 复制bulk download给的链接无法下载 bulk download给的原链接: curl.exe "http…

基于 Prometheus + Grafana 监控微服务和数据库

以下是基于 Prometheus Grafana 监控微服务和数据库的详细指南&#xff0c;包含架构设计、安装配置及验证步骤&#xff1a; 一、整体架构设计 二、监控微服务 1. 微服务指标暴露 Spring Boot 应用&#xff1a; xml <!-- 添加 Micrometer 依赖 --> <dependency>…

CAN总线的CC帧和FD帧之间如何仲裁

为满足CAN总线日益提高的带宽需求&#xff0c;博世公司于2012年推出CAN FD&#xff08;具有灵活数据速率的CAN&#xff09;标准&#xff0c;国际标准化组织&#xff08;ISO&#xff09;2015年通过ISO 11898-1:2015标准&#xff0c;正式将CAN FD纳入国际标准&#xff0c;以示区别…

SpringBoot 第一课(Ⅲ) 配置类注解

目录 一、PropertySource 二、ImportResource ①SpringConfig &#xff08;Spring框架全注解&#xff09; ②ImportResource注解实现 三、Bean 四、多配置文件 多Profile文件的使用 文件命名约定&#xff1a; 激活Profile&#xff1a; YAML文件支持多文档块&#xff…

Excel(函数篇):COUNTIF与CONUTIFS函数、SUMIF与SUMIFS函数、ROUND函数、MATCH与INDEX函数、混合引用与条件格式

目录 COUNTIF和COUNTIFS函数COUNTIF函数COUNTIFS函数SUMIF和SUMIFS函数SUMIF函数SUMIFS函数SUMIFS函数与控件实现动态年月汇总ROUND、ROUNDUP、ROUNDDOWN函数单元格混合引用条件格式与公式,标记整行数据MATCH和INDEX函数COUNTIF和COUNTIFS函数 COUNTIF函数 统计下“苏州”出现…