文章目录
- 前言
- 什么是MyCat
- 为什么需要分库分表
- 场景说明
- MySQL准备
- MyCat安装配置
- 启动MyCat
- 测试验证
- 常见分片算法
- 注意事项
-
- [1. 跨分片查询](#1. 跨分片查询)
- [2. 主键生成](#2. 主键生成)
- 总结
前言
随着业务量的增长,单库单表往往会遇到性能瓶颈。当一张表的数据量达到千万级别时,查询效率会明显下降。这时候就需要考虑分库分表了。本文将介绍如何使用MyCat中间件来实现MySQL的分库分表。
什么是MyCat
MyCat是一个开源的数据库中间件,可以看作是一个数据库代理。应用程序连接MyCat就像连接MySQL一样,而MyCat会将SQL请求路由到后端的真实数据库。通过MyCat,我们可以轻松实现读写分离、分库分表等功能。
为什么需要分库分表
单表数据量过大的问题:
查询变慢:索引树层级变深,检索效率降低
写入变慢:页分裂频繁,锁竞争加剧
备份恢复慢:数据量大,备份和恢复时间长
分库分表的好处:
提高查询性能:数据分散,单次查询数据量减少
提高并发能力:请求分散到多个数据库
便于扩展:可以通过增加节点来提升性能
场景说明
假设我们有一个订单表order
,数据量巨大。我们的分库分表策略是:
- 分库:按用户ID哈希分成2个库(db1、db2)
- 分表:每个库中按订单ID模3分成3张表(order_0、order_1、order_2)
最终会有6张物理表分布在2个数据库中。
MySQL准备
创建数据库
在两台MySQL服务器上分别创建数据库:
sql
-- MySQL 1 (192.168.1.101)
CREATE DATABASE db1;
-- MySQL 2 (192.168.1.102)
CREATE DATABASE db2;
创建分表
在每个数据库中创建3张订单表:
sql
-- 在db1和db2中都执行
CREATE TABLE order_0 (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
product_name VARCHAR(100),
amount DECIMAL(10,2),
create_time DATETIME,
INDEX idx_user_id(user_id)
) ENGINE=InnoDB;
CREATE TABLE order_1 LIKE order_0;
CREATE TABLE order_2 LIKE order_0;
MyCat安装配置
下载安装
bash
wget http://dl.mycat.org.cn/1.6.7.6/20210303094759/Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz
tar -zxvf Mycat-server-1.6.7.6-release-20210303094759-linux.tar.gz -C /usr/local/
配置server.xml
编辑conf/server.xml
,配置MyCat的用户和逻辑库:
xml
<?xml version="1.0" encoding="UTF-8"?>
<mycat:server xmlns:mycat="http://io.mycat/">
<!-- 配置用户 -->
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">orderdb</property>
</user>
<user name="user">
<property name="password">user123</property>
<property name="schemas">orderdb</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
配置schema.xml
这是MyCat的核心配置文件,定义了逻辑库、逻辑表和分片规则:
xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 定义逻辑库 -->
<schema name="orderdb" checkSQLschema="false" sqlMaxLimit="100">
<!-- 定义逻辑表,rule指定分片规则 -->
<table name="order" dataNode="dn1,dn2" rule="order-hash-rule" />
</schema>
<!-- 定义数据节点 -->
<dataNode name="dn1" dataHost="host1" database="db1" />
<dataNode name="dn2" dataHost="host2" database="db2" />
<!-- 定义数据主机 -->
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.1.101:3306"
user="root" password="123456">
</writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.1.102:3306"
user="root" password="123456">
</writeHost>
</dataHost>
</mycat:schema>
配置rule.xml
定义分片规则:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<!-- 定义分片规则 -->
<tableRule name="order-hash-rule">
<rule>
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<!-- 定义分片算法 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- 数据节点数量 -->
<property name="count">2</property>
</function>
</mycat:rule>
启动MyCat
bash
# 启动
/usr/local/mycat/bin/mycat start
# 查看状态
/usr/local/mycat/bin/mycat status
# 查看日志
tail -f /usr/local/mycat/logs/wrapper.log
MyCat默认监听:
- 8066端口:数据服务端口,应用连接这个端口
- 9066端口:管理端口,用于管理MyCat
测试验证
连接MyCat
bash
mysql -uroot -p123456 -h127.0.0.1 -P8066 -Dorderdb
插入数据
sql
-- 插入测试数据
INSERT INTO `order`(id, user_id, product_name, amount, create_time)
VALUES (1, 1001, 'iPhone 14', 5999.00, NOW());
INSERT INTO `order`(id, user_id, product_name, amount, create_time)
VALUES (2, 1002, 'MacBook Pro', 12999.00, NOW());
INSERT INTO `order`(id, user_id, product_name, amount, create_time)
VALUES (3, 1003, 'iPad Air', 4799.00, NOW());
查看数据分布
分别登录到两个MySQL实例查看数据:
sql
-- 在MySQL 1上
USE db1;
SELECT * FROM order_0;
SELECT * FROM order_1;
SELECT * FROM order_2;
-- 在MySQL 2上
USE db2;
SELECT * FROM order_0;
SELECT * FROM order_1;
SELECT * FROM order_2;
你会发现数据已经按照user_id的哈希值分散到不同的库和表中了。
查询数据
通过MyCat查询时,就像操作单表一样:
sql
-- 查询指定用户的订单(会路由到特定分片)
SELECT * FROM `order` WHERE user_id = 1001;
-- 查询所有订单(会聚合所有分片的结果)
SELECT * FROM `order` ORDER BY create_time DESC LIMIT 10;
-- 统计订单总数
SELECT COUNT(*) FROM `order`;
常见分片算法
MyCat支持多种分片算法:
- 取模分片:根据字段值取模
- 范围分片:根据字段值的范围
- 枚举分片:根据枚举值映射
- 时间分片:按日期分片
- 字符串哈希分片:字符串哈希
注意事项
1. 跨分片查询
sql
-- 不带分片键的查询会扫描所有分片,性能差
SELECT * FROM `order` WHERE product_name = 'iPhone';
-- 带分片键的查询只会路由到对应分片
SELECT * FROM `order` WHERE user_id = 1001 AND product_name = 'iPhone';
2. 主键生成
分库分表后不能使用MySQL的自增ID,需要使用分布式ID生成方案:
- 雪花算法(Snowflake)
- 数据库序列表
- Redis生成
- MyCat自带的序列号
总结
MyCat是一个功能强大的数据库中间件,可以帮助我们快速实现分库分表。使用MyCat的优势在于:
- 对应用透明:应用程序无需修改代码,只需改一下连接地址
- 配置灵活:支持多种分片策略和路由规则
- 功能丰富:支持读写分离、分库分表、SQL拦截等
在实际使用中,建议先做好容量规划和性能测试,确保分片方案能满足业务需求。