阿杰,我帮你整理一份 MyCat 数据库中间件 的全面介绍,包括简介、架构、原理、使用场景和注意事项。
一、MyCat 简介
- MyCat 是一个 开源的分布式数据库中间件,基于 Java 开发,兼容 MySQL 协议。
- 主要功能:
- 分库分表:将数据水平拆分到多个数据库实例,提高性能和扩展性。
- 读写分离:支持主从复制,读请求走从库,写请求走主库。
- 分布式事务支持:通过 XA 或 TCC 实现跨库事务。
- SQL 路由与合并:支持复杂 SQL 的拆分、路由和结果合并。
- 适用场景:
- 高并发访问的 OLTP 系统
- 数据量超大,需要水平拆分的数据库
- 多租户 SaaS 系统
二、MyCat 架构
MyCat 采用 中间层架构,位于应用程序与后端数据库之间:
+----------------+
| 应用程序 |
+----------------+
|
MyCat 中间件
+--------------------------+
| SQL 路由 | 事务管理 | 缓存 |
+--------------------------+
/ \
/ \
+--------+ +--------+
| MySQL1 | | MySQL2 |
+--------+ +--------+
- 应用透明访问:应用直接使用 MySQL JDBC 驱动连接 MyCat。
- SQL 路由:根据配置的分库分表策略,将 SQL 自动路由到对应数据库表。
- 事务管理:支持本地事务和分布式事务(XA)。
- 缓存:可配置二级缓存,提升查询性能。
三、MyCat 核心原理
- 分库分表规则:
- 支持 哈希分片、范围分片、列表分片
- SQL 中通过 分片键 路由到具体数据库表
- 示例:
user_id % 4
→ 4 个库或表
- SQL 路由与拆分:
- 支持 简单 SQL 拆分(如单表查询)
- 支持 聚合函数、JOIN 的结果合并(部分场景有限制)
- 读写分离:
- 主库写操作,自动同步到从库
- 读操作优先走从库,实现负载均衡
- 事务处理:
- 单库事务由 MySQL 处理
- 跨库事务支持 XA 或应用控制
- 连接池与性能优化:
- 内置连接池管理后端数据库连接
- 支持 SQL 缓存、批量操作,提升吞吐量
四、MyCat 使用指南
1. 下载与部署
- 下载最新版本:MyCat 官网
- 解压到服务器目录:
tar -zxvf mycat-server-x.x.x.tar.gz
cd mycat-server
- 修改配置文件:
server.xml
:监听端口、JDBC 协议设置schema.xml
:数据库和分库分表规则rule.xml
:分表策略
- 启动 MyCat:
sh bin/startup.sh
2. 连接 MyCat
- 使用 MySQL 客户端或 JDBC 直接连接:
mysql -h mycat_host -P 8066 -u myuser -p
- 端口默认 8066,用户名密码由
server.xml
配置
3. 配置示例(分库分表)
schema.xml
<schema name="test_db" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1,dn2">
<table name="user" primaryKey="id" dataNode="dn1,dn2" rule="user_rule"/>
</schema>
rule.xml
<rule name="user_rule" type="hash_mod">
<columns>id</columns>
<algorithm expression="id % 2" />
<dataNodes>dn1,dn2</dataNodes>
</rule>
user
表根据id % 2
分配到dn1
或dn2
数据节点dn1
、dn2
对应实际 MySQL 实例
五、注意事项
- 兼容性:
- MyCat 尽量兼容 MySQL,但部分 复杂 JOIN、存储过程 支持有限
- 分布式事务:
- XA 性能有一定开销,跨库事务要谨慎
- 监控和运维:
- 建议配合 日志分析 + 监控系统,及时发现 SQL 慢查询
- 分库分表设计:
- 尽量使用 整数或唯一 ID 作为分片键
- 避免频繁跨库 JOIN
六、总结
- MyCat 是数据库中间件,用于解决 MySQL 单机瓶颈和扩展性问题
- 主要功能:分库分表、读写分离、SQL 路由、分布式事务
- 部署方式:Java 服务,配置 schema 和 rule
- 应用层透明:应用直接使用 MySQL 协议连接 MyCat,无需改动太多代码
明白阿杰,我帮你写一个 MyCat 分库分表示例 + JDBC 使用示例,演示 自动路由、读写分离,方便直接测试。
一、MyCat 分库分表示例
假设我们有 两个 MySQL 实例:
数据节点 | IP | 数据库名 |
---|---|---|
dn1 | 127.0.0.1:3306 | user_db1 |
dn2 | 127.0.0.1:3306 | user_db2 |
我们要将 user 表 根据 id % 2
分配到两个节点:
1. 配置 schema.xml
<schema name="test_db" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1,dn2">
<table name="user" primaryKey="id" dataNode="dn1,dn2" rule="user_rule"/>
</schema>
2. 配置 rule.xml
<rule name="user_rule" type="hash_mod">
<columns>id</columns>
<algorithm expression="id % 2"/>
<dataNodes>dn1,dn2</dataNodes>
</rule>
3. 数据节点配置 server.xml
<dataNode name="dn1" dataHost="localhost1" database="user_db1"/>
<dataNode name="dn2" dataHost="localhost2" database="user_db2"/>
- 这里
localhost1
和localhost2
分别对应两个 MySQL 数据库配置 - 确保每个数据库中已经创建
user
表结构相同,例如:
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT
);
二、JDBC 使用 MyCat 示例
应用直接连接 MyCat 端口(默认 8066):
import java.sql.*;
public class MyCatJDBCExample {
public static void main(String[] args) throws Exception {
// MyCat 地址和端口
String url = "jdbc:mysql://127.0.0.1:8066/test_db";
String user = "mycat_user";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
// 插入示例
stmt.executeUpdate("INSERT INTO user(id, name, age) VALUES(1, 'Alice', 20)");
stmt.executeUpdate("INSERT INTO user(id, name, age) VALUES(2, 'Bob', 25)");
// 查询示例
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
while(rs.next()) {
System.out.println(rs.getInt("id") + " | " +
rs.getString("name") + " | " +
rs.getInt("age"));
}
rs.close();
stmt.close();
conn.close();
}
}
✅ 特点
- 自动路由
id=1
会路由到dn1
id=2
会路由到dn2
- 读写分离
- 配置主从数据节点后,查询走从库,写入走主库
- 对应用透明,无需改动 SQL
- 跨库查询注意
- 简单的单表查询和主键查询没问题
- 跨库 JOIN 或聚合需要谨慎,性能受限
三、测试步骤
- 启动两个 MySQL 实例,分别创建
user_db1
和user_db2
- 启动 MyCat,确保
server.xml
、schema.xml
、rule.xml
配置正确 - 编译运行上述 JDBC 示例程序
- 检查两个 MySQL 数据库,确认
INSERT
已根据id % 2
分配到对应库
明白阿杰,我帮你写一个 MyCat 分库分表 + 读写分离完整测试脚本,使用 Java JDBC,实现以下功能:
- 自动生成测试数据
- 插入数据,验证分库分表策略(id % 2)
- 查询数据,验证读写分离效果
- 打印每条数据所在数据库节点(方便验证路由)
import java.sql.*;
import java.util.Random;
public class MyCatTest {
private static final String URL = "jdbc:mysql://127.0.0.1:8066/test_db";
private static final String USER = "mycat_user";
private static final String PASSWORD = "123456";
public static void main(String[] args) throws Exception {
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
Statement stmt = conn.createStatement();
// 1. 创建测试表(如果不存在)
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS user (" +
"id INT PRIMARY KEY, name VARCHAR(50), age INT)");
// 2. 插入随机测试数据
Random rand = new Random();
for (int i = 1; i <= 10; i++) {
String name = "User" + i;
int age = 18 + rand.nextInt(30);
stmt.executeUpdate(String.format("INSERT INTO user(id, name, age) VALUES(%d, '%s', %d) " +
"ON DUPLICATE KEY UPDATE name='%s', age=%d", i, name, age, name, age));
System.out.println("插入数据: id=" + i + ", name=" + name + ", age=" + age);
}
// 3. 查询数据并打印
ResultSet rs = stmt.executeQuery("SELECT * FROM user ORDER BY id");
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println("查询数据: id=" + id + ", name=" + name + ", age=" + age);
System.out.println("路由节点推测: " + (id % 2 == 0 ? "dn2" : "dn1"));
}
rs.close();
stmt.close();
conn.close();
}
}
使用说明
- 准备环境
- 启动 MyCat,确保配置好两个数据节点 dn1/dn2
- 确保 MySQL 数据库 user_db1 和 user_db2 已创建
- 编译运行
javac MyCatTest.java java -cp .:mysql-connector-java-8.0.36.jar MyCatTest
- 验证结果
- 控制台会打印每条插入和查询数据
id % 2 == 0
的数据属于 dn2,否则属于 dn1- 可以登录 MySQL 实例,验证数据是否分配正确
特点
- 自动生成数据,无需手动插入
- 分库分表验证,通过
id % 2
显示路由节点 - 读写分离验证
- 配置主从节点后,查询会走从库,插入走主库
- 一次性测试完整流程,方便开发调试
发表回复