当前位置: 首页 > news >正文

从 0 到 1:用 MyCat 打造可水平扩展的 MySQL 分库分表架构

一、为什么要分库分表?

单机 MySQL 的极限大致在:

维度经验值
单表行数≤ 1 000 万行(B+ 树三层)
单库磁盘≤ 2 TB(SSD)
单机 QPS≤ 1 万(InnoDB)

当业务继续增长,数据量和并发量都会突破单机天花板,此时就需要 水平拆分
业内常见方案:

  • Client 模式:ShardingSphere-JDBC、TDDL
  • Proxy 模式:MyCat、ShardingSphere-Proxy、Vitess

今天的主角是 MyCat —— 轻量级、配置简单、社区成熟,适合中小团队快速落地。


二、MyCat 是什么?

一句话:
MyCat 是 MySQL 协议的代理中间件,对外表现为“一台”大 MySQL,内部帮你把 SQL 路由到真正的分片。

核心概念:

名词作用
schema逻辑库(业务代码看到的)
table逻辑表(可配置分片规则)
dataNode分片节点(逻辑库+物理库名)
dataHost物理实例(主从/集群)
rule分片算法(取模、范围、哈希等)

三、实战目标

  • 3 台 MySQL 物理机
  • 订单表 t_order 按 user_id 取模 分成 6 张分表
  • 商品表 t_product 数据量少 → 全局广播表
  • 配置表 t_config 全局广播
  • Java 代码零侵入,只连 MyCat 8066 端口

四、环境准备

角色IP:Port备注
MyCat 节点192.168.1.10:8066 / 9066代理端口/管理端口
MySQL-1192.168.1.100:3306主库
MySQL-2192.168.1.101:3306主库
MySQL-3192.168.1.102:3306主库

4.1 安装 MyCat

wget http://dl.mycat.org.cn/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
tar -zxvf Mycat-server-1.6-RELEASE-*.tar.gz
cd mycat

目录结构:

mycat├─ bin/mycat       # 启停脚本├─ conf/*.xml      # 配置文件└─ logs            # 日志

五、MySQL 端建库建表

每台机执行:

CREATE DATABASE IF NOT EXISTS db1 DEFAULT CHARSET utf8mb4;
CREATE DATABASE IF NOT EXISTS db2 DEFAULT CHARSET utf8mb4;
CREATE DATABASE IF NOT EXISTS db3 DEFAULT CHARSET utf8mb4;-- 订单分表
CREATE TABLE db1.t_order_0 (id BIGINT AUTO_INCREMENT PRIMARY KEY,user_id BIGINT NOT NULL,amount DECIMAL(10,2) NOT NULL,create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE db1.t_order_1 LIKE db1.t_order_0;CREATE TABLE db2.t_order_2 LIKE db1.t_order_0;
CREATE TABLE db2.t_order_3 LIKE db1.t_order_0;CREATE TABLE db3.t_order_4 LIKE db1.t_order_0;
CREATE TABLE db3.t_order_5 LIKE db1.t_order_0;-- 广播表(每台库一份)
CREATE TABLE db1.t_product (id INT PRIMARY KEY,name VARCHAR(100),price DECIMAL(8,2)
);
CREATE TABLE db2.t_product LIKE db1.t_product;
CREATE TABLE db3.t_product LIKE db1.t_product;CREATE TABLE db1.t_config (k VARCHAR(50) PRIMARY KEY,v VARCHAR(200)
);
CREATE TABLE db2.t_config LIKE db1.t_config;
CREATE TABLE db3.t_config LIKE db1.t_config;

六、MyCat 配置

6.1 server.xml —— 用户、逻辑库

<user name="root" defaultAccount="true"><property name="password">123456</property><property name="schemas">shop</property>
</user>

6.2 schema.xml —— 逻辑表、节点、主机

<schema name="shop" checkSQLschema="false" sqlMaxLimit="100"><!-- 1) 分片表 --><table name="t_order" dataNode="dn1,dn2,dn3" rule="mod-long" /><!-- 2) 广播表 --><table name="t_product" dataNode="dn1,dn2,dn3" type="global" /><table name="t_config"  dataNode="dn1,dn2,dn3" type="global" />
</schema><!-- 数据节点 -->
<dataNode name="dn1" dataHost="host1" database="db1" />
<dataNode name="dn2" dataHost="host2" database="db2" />
<dataNode name="dn3" dataHost="host3" database="db3" /><!-- 物理主机 -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql"><heartbeat>select user()</heartbeat><writeHost host="hostM1" url="192.168.1.100:3306" user="root" password="mysql123" />
</dataHost>
<dataHost name="host2" ...> ... </dataHost>
<dataHost name="host3" ...> ... </dataHost>

6.3 rule.xml —— 取模算法

<tableRule name="mod-long"><rule><columns>user_id</columns><algorithm>mod-long</algorithm></rule>
</tableRule><function name="mod-long" class="io.mycat.route.function.PartitionByMod"><property name="count">3</property> <!-- 3 节点 × 2 表 = 6 分片 -->
</function>

七、启动 MyCat

bin/mycat start   # 启动
tail -f logs/mycat.log  # 观察 “success”

测试连通:

mysql -uroot -p123456 -h127.0.0.1 -P8066 -Dshop

八、Java 代码示例(零侵入)

8.1 Maven 依赖

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version>
</dependency>

8.2 连接池配置

spring:datasource:url: jdbc:mysql://192.168.1.10:8066/shop?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

8.3 订单 DAO(MyBatis 示例)

@Mapper
public interface OrderMapper {@Insert("INSERT INTO t_order(user_id,amount) VALUES(#{userId},#{amount})")void insert(@Param("userId") Long userId, @Param("amount") BigDecimal amount);@Select("SELECT * FROM t_order WHERE user_id = #{userId}")List<Order> findByUserId(Long userId);
}

8.4 商品 DAO

@Select("SELECT * FROM t_product WHERE id = #{id}")
Product getProduct(Integer id);

商品表全局广播,JOIN 时不会跨库:

SELECT o.id, o.amount, p.name
FROM t_order o
JOIN t_product p ON o.product_id = p.id
WHERE o.user_id = 123;   -- 只在 1 个分片执行

九、扩容与运维

9.1 水平扩容(从 3 → 6 节点)

  1. 新增 3 台 MySQL,建 db4/db5/db6,建相同 6 张分表 t_order_6 … t_order_11
  2. 修改 rule.xmlcount 改成 6。
  3. mysqldump / mydumper 把旧数据按 user_id mod 6 重新分布。
  4. 灰度切流 → 观察 → 下线旧节点。

9.2 一致性校验(广播表)

# 1. 安装 percona-toolkit
pt-table-checksum h=192.168.1.100,u=checksum_user,p=xxx \--databases=db1,db2,db3 --tables=t_product,t_config
# 2. 差异行修复
pt-table-sync --print --execute ...  # 自动生成修复 SQL

十、踩坑与最佳实践

说明解决方案
全局序列自增主键在分片后冲突雪花算法 / MyCat 全局序列
深分页LIMIT 1000000,10 会拉全表游标分页 / ES 搜索
跨分片 JOINMyCat 只能内存合并反范式冗余或应用层拼装
广播表 DDL漏执行导致查询报错统一脚本 + pt-osc

十一、小结

  • MyCat = 透明代理 + 路由规则 + 全局表 + 读写分离,几分钟就能把单机 MySQL 扩展到百节点百亿行
  • 小表全局广播,大表水平拆分,业务代码零改动。
  • 监控、扩容、一致性校验要提前规划,否则 3 个月后追悔莫及。

参考资料
MyCat 官方文档 https://www.yuque.com/books/share/05b6e74e-9a1a-4e5d-a21e-4f93e9e3d5a3

http://www.lryc.cn/news/617888.html

相关文章:

  • Linux-常用命令
  • 深入解析 resolv.conf 文件:DNS 配置的核心
  • 驱动_ConfigFS多级目录操作
  • 光功率dBm为何是负数?一文详解
  • Google OAuth 配置步骤指南,实现Google Drive文件同步功能。
  • UVM验证—UVM 简述
  • 快速了解TF-IDF算法
  • 逐际动力开源运控 tron1-rl-isaacgym 解读与改进
  • 自由学习记录(81)
  • 5B 参数,消费级显卡可部署:Wan2.2-TI2V-5B 本地部署教程,9分钟跑出电影级大片!
  • 【运维进阶】WEB 服务器
  • GB17761-2024标准与电动自行车防火安全的技术革新
  • Redis 数据结构及特点
  • 【工作笔记】Wrappers.lambdaQuery()用法
  • ROS2学习(1)—基础概念及环境搭建
  • JavaEE 初阶第十七期:文件 IO 的 “管道艺术”(下)
  • vscode新建esp32工程,没有sample_project怎么办?
  • 计算机网络:ovn数据通信都是用了哪些协议?
  • 应用层模拟面试题
  • C语言(06)——二、八、十、十六进制的相互转换
  • Effective C++ 条款35:考虑 virtual函数以外的其他选择
  • 【已解决】报错:WARNING: pip is configured with locations that require TLS/SSL
  • HarmonyOS 开发入门 第一章
  • 一文读懂 C# 中的 Lazy<T>
  • Python 在自动化办公汇总和脚本示例
  • 本地文件夹与 GitHub 远程仓库绑定并进行日常操作的完整命令流程
  • 【基本有序数组中找到有且仅有的一个无序元素并进行排序之顺序法】2022-10-12
  • Linux线程——线程控制及理解
  • Transformer前传:Seq2Seq与注意力机制Attention
  • Haystack:面向大模型应用的模块化检索增强生成(RAG)框架