Mycat分库分表实战指南
前言
在互联网业务高速发展的背景下,单数据库的性能瓶颈逐渐凸显——数据量激增导致查询变慢、写入性能下降、单机存储容量不足等问题层出不穷。分库分表作为解决数据库水平扩展的核心方案,成为后端开发的必备技能。Mycat 作为一款开源的数据库中间件,凭借兼容MySQL协议、丰富的分片规则、完善的高可用特性,成为分库分表落地的主流选择。本文将从Mycat核心原理、部署、配置、实战技巧到问题排查,全方位讲解Mycat分库分表的落地过程。
一、Mycat核心认知
1.1 什么是Mycat?
Mycat 脱胎于阿里Cobar,是一款基于Java开发的开源分布式数据库中间件,核心定位是“数据库代理”:
- 对前端应用而言,Mycat 完全兼容MySQL原生协议,应用连接Mycat的方式与连接原生MySQL无任何差异;
- 对后端存储而言,Mycat 根据配置的分片规则,将数据路由到不同的物理数据库/表中,实现数据的分布式存储与查询;
- 核心价值:屏蔽底层分库分表细节,让开发人员像操作单库单表一样操作分布式数据库。
1.2 Mycat核心特性(补充完善)
Mycat 之所以能成为主流分库分表中间件,核心在于其丰富且实用的特性:
- 协议兼容:完全遵守MySQL原生协议,跨语言、跨平台、跨数据库(支持MySQL/Oracle/DB2/SQL Server等);
- 高可用能力:基于心跳检测的自动故障切换,支持MySQL主从、Galera Cluster集群,可配置读写分离;
- 高性能架构:基于NIO实现网络模块,优化Buffer内核,高效管理线程池,支撑高并发场景;
- 灵活的分片能力:支持按范围、哈希、日期、模运算、ER关系等多种分片规则,插件化开发易扩展;
- 查询能力:支持SQL92标准,支持单库任意JOIN、跨库2表JOIN,通过全局表/ER表优化多表关联查询;
- 附加能力:分布式事务(弱XA)、全局序列号(解决分布式主键)、多租户、密码加密、IP白名单、SQL黑名单(防注入)、服务降级等;
- 运维友好:提供Web/命令行监控,支持配置热重载、在线扩容、集群化管理(基于ZooKeeper)。
二、Mycat部署(优化完善)
2.1 环境准备
- 操作系统:Linux(CentOS7+/Ubuntu18.04+)
- Docker环境:已安装Docker & Docker Compose(推荐Docker部署,简化环境依赖)
- 网络:确保Mycat容器能访问后端MySQL集群,开放8066(业务连接端口)、9066(管理端口)
2.2 Docker部署(修正&补充)
# 1. 创建工作目录,统一管理配置/日志
mkdir -p /root/data/mycat/{conf,logs}
cd /root/data/mycat
# 2. 下载Mycat安装包(仅提取配置文件)
wget http://dl.mycat.org.cn/1.6.7.6/20201126013625/Mycat-server-1.6.7.6-release-20201126013625-linux.tar.gz -O mycat1.6.7.6.tar.gz
tar -zxvf mycat1.6.7.6.tar.gz --strip-components=2 -C ./conf mycat/conf/ # 仅解压conf目录
# 3. 编写Dockerfile(补充完整内容,避免依赖缺失)
cat > Dockerfile << EOF
FROM openjdk:8-jre-alpine
MAINTAINER zengchengjie
# 安装依赖(解决MySQL客户端连接问题)
RUN apk add --no-cache mysql-client
# 下载并解压Mycat
WORKDIR /usr/local
RUN wget http://dl.mycat.org.cn/1.6.7.6/20201126013625/Mycat-server-1.6.7.6-release-20201126013625-linux.tar.gz -O mycat.tar.gz && \
tar -zxvf mycat.tar.gz && \
rm -f mycat.tar.gz && \
chmod +x /usr/local/mycat/bin/mycat
# 暴露端口
EXPOSE 8066 9066
# 启动Mycat
CMD ["/usr/local/mycat/bin/mycat", "console"]
EOF
# 4. 构建镜像
docker build -t mycat:1.6.7.6 .
# 5. 启动容器(补充重启策略、时区配置)
docker run --privileged=true \
-p 8066:8066 -p 9066:9066 \
--name mycat \
--restart=always \
-v /etc/localtime:/etc/localtime:ro \
-v /root/data/mycat/conf:/usr/local/mycat/conf \
-v /root/data/mycat/logs:/usr/local/mycat/logs \
-d mycat:1.6.7.6
# 6. 验证启动
docker logs -f mycat
# 连接管理端口验证
mysql -h127.0.0.1 -P9066 -umycat -pmycat
2.3 源码部署(补充,适合定制化场景)
若需调试源码、定制Mycat功能,可通过源码编译部署:
# 1. 克隆源码
git clone https://gitee.com/MycatOne/Mycat-Server.git
cd Mycat-Server
# 2. 编译(需Maven 3.6+、JDK 8)
mvn clean package -DskipTests
# 3. 解压编译产物
tar -zxvf target/Mycat-server-*.tar.gz -C /usr/local/mycat
# 4. 启动
/usr/local/mycat/bin/mycat start
三、Mycat核心配置(修正&完善)
Mycat的核心配置集中在conf目录下的3个文件:server.xml(系统/用户配置)、schema.xml(逻辑库/表/分片映射)、rule.xml(分片规则)。
3.1 server.xml:系统参数&用户授权
3.1.1 系统参数配置
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<!-- SQL解析器:druidparser兼容性更强 -->
<property name="defaultSqlParser">druidparser</property>
<!-- 业务连接端口(默认8066) -->
<property name="serverPort">8066</property>
<!-- 管理端口(默认9066) -->
<property name="managerPort">9066</property>
<!-- 字符集(与后端MySQL保持一致) -->
<property name="charset">utf8mb4</property>
<!-- 关闭SQL注释解析(避免注释导致解析异常) -->
<property name="parseComment">false</property>
</system>
<!-- 用户配置:应用连接Mycat的账号 -->
<user name="mycat_app">
<property name="password">Mycat@123456</property>
<!-- 关联逻辑库(多个用逗号分隔) -->
<property name="schemas">user,pay</property>
<!-- 只读权限控制(可选) -->
<!-- <property name="readOnly">true</property> -->
</user>
<!-- 管理员账号:用于执行管理命令(如重载配置) -->
<user name="mycat_admin">
<property name="password">Mycat@Admin123</property>
<property name="schemas">user,pay</property>
<property name="privileges">*:*</property>
</user>
</mycat:server>
3.1.2 关键参数说明
defaultSqlParser:推荐使用druidparser,兼容更多SQL语法;charset:必须与后端MySQL的字符集一致(如utf8mb4),避免乱码;parseComment:关闭注释解析可避免因SQL注释导致的解析错误;- 权限控制:可通过
readOnly、privileges精细控制用户权限,生产环境避免使用弱密码。
3.2 schema.xml:逻辑库&分片映射
schema.xml是Mycat配置的核心,定义了逻辑库、逻辑表、分片(dataNode)、物理库(dataHost)的映射关系。
3.2.1 完整配置示例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!-- 逻辑库:user(用户库,垂直分片) -->
<schema name="user" checkSQLschema="false" sqlMaxLimit="1000" dataNode="user_dn">
<!-- 逻辑表:t_user(按用户ID模2分片) -->
<table name="t_user" dataNode="user_dn1,user_dn2" rule="sharding-by-userid-mod" primaryKey="id"/>
<!-- ER表:t_user_address(关联t_user,自动路由到同一分片) -->
<table name="t_user_address" primaryKey="id">
<childTable parentTable="t_user" parentKey="id" childKey="user_id"/>
</table>
</schema>
<!-- 逻辑库:pay(支付库,混合分片) -->
<schema name="pay" checkSQLschema="false" sqlMaxLimit="1000">
<!-- 订单表:按创建时间+订单ID哈希分片 -->
<table name="t_order" dataNode="pay_dn1,pay_dn2,pay_dn3" rule="sharding-by-order-time-hash" primaryKey="id"/>
<!-- 全局表:t_dict(字典表,全部分片同步) -->
<table name="t_dict" type="global" dataNode="pay_dn1,pay_dn2,pay_dn3"/>
</schema>
<!-- 分片(dataNode):关联物理库+数据库 -->
<dataNode name="user_dn1" dataHost="mysql_cluster" database="user_db1"/>
<dataNode name="user_dn2" dataHost="mysql_cluster" database="user_db2"/>
<dataNode name="pay_dn1" dataHost="mysql_cluster" database="pay_db1"/>
<dataNode name="pay_dn2" dataHost="mysql_cluster" database="pay_db2"/>
<dataNode name="pay_dn3" dataHost="mysql_cluster" database="pay_db3"/>
<!-- 物理库集群(dataHost):配置MySQL主从/读写分离 -->
<dataHost name="mysql_cluster" maxCon="1000" minCon="20" balance="1"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<!-- 心跳检测:确保后端数据库可用 -->
<heartbeat>select user()</heartbeat>
<!-- 主库(写库) -->
<writeHost host="master1" url="192.168.0.2:3306" user="mycat_user" password="Mycat@Mysql123">
<!-- 从库(读库) -->
<readHost host="slave1" url="192.168.0.3:3306" user="mycat_user" password="Mycat@Mysql123"/>
</writeHost>
<!-- 备用主库(故障自动切换) -->
<writeHost host="master2" url="192.168.0.4:3306" user="mycat_user" password="Mycat@Mysql123"/>
</dataHost>
</mycat:schema>
3.2.2 核心标签说明
| 标签 | 关键属性 | 说明 |
|---|---|---|
schema |
checkSQLschema |
设为false:避免应用SQL中带库名导致解析错误 |
schema |
sqlMaxLimit |
默认添加LIMIT,防止全表扫描拖垮集群(生产建议设1000以内) |
table |
type="global" |
全局表:全部分片同步数据,用于字典表、配置表等 |
table |
childTable |
ER表:关联父表,自动路由到同一分片,解决跨分片JOIN问题 |
dataHost |
balance |
读写分离策略:0=仅写主库;1=读请求分摊到主库+从库;2=读仅从库 |
dataHost |
switchType |
故障切换:1=基于心跳自动切换;-1=不切换 |
writeHost |
嵌套readHost |
主从架构:写走writeHost,读走readHost |
3.3 rule.xml:分片规则配置
Mycat支持数十种分片规则,核心是通过tableRule绑定“分片字段+算法”,function定义具体分片逻辑。
3.3.1 常用规则配置示例
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://org.opencloudb/">
<!-- 规则1:按用户ID模2分片 -->
<tableRule name="sharding-by-userid-mod">
<rule>
<columns>id</columns> <!-- 分片字段:用户ID -->
<algorithm>mod2</algorithm> <!-- 关联算法 -->
</rule>
</tableRule>
<!-- 规则2:按订单创建时间+ID哈希分片 -->
<tableRule name="sharding-by-order-time-hash">
<rule>
<columns>create_time,id</columns> <!-- 复合分片字段 -->
<algorithm>hash-by-time-id</algorithm>
</rule>
</tableRule>
<!-- 规则3:按小时分片(日志表专用) -->
<tableRule name="sharding-by-hour">
<rule>
<columns>create_time</columns>
<algorithm>latest-month-partion</algorithm>
</rule>
</tableRule>
<!-- 算法1:模2算法 -->
<function name="mod2" class="org.opencloudb.route.function.PartitionByMod">
<property name="count">2</property> <!-- 分片数量 -->
</function>
<!-- 算法2:哈希分片(适配3个分片) -->
<function name="hash-by-time-id" class="org.opencloudb.route.function.PartitionByHash">
<property name="partitionCount">3</property> <!-- 分片数 -->
<property name="partitionLength">1</property> <!-- 分片长度 -->
</function>
<!-- 算法3:按小时分片(近30天,按小时拆分) -->
<function name="latest-month-partion" class="org.opencloudb.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property> <!-- 一天拆分为24片(按小时) -->
<property name="beginDate">2024-01-01</property> <!-- 起始日期 -->
</function>
</mycat:rule>
3.3.2 常用分片规则推荐
| 规则类型 | 适用场景 | 对应Class |
|---|---|---|
| 模运算(Mod) | 用户ID、订单ID等整型字段 | PartitionByMod |
| 哈希(Hash) | 均匀分布数据 | PartitionByHash |
| 日期(Date) | 日志表、流水表 | LatestMonthPartion/PartitionByDate |
| 范围(Range) | 按ID段分片 | AutoPartitionByLong |
| ER关联 | 订单-订单项、用户-地址 | 配合childTable标签 |
四、Mycat运维实战
4.1 配置热重载(优雅生效配置)
修改配置文件后,无需重启Mycat,通过管理端口执行命令即可重载:
#!/bin/bash
# 重载Mycat配置脚本(避免重启)
MYCAT_HOST="127.0.0.1"
MYCAT_PORT="9066"
MYCAT_USER="mycat_admin"
MYCAT_PWD="Mycat@Admin123"
# 重载所有配置(schema/server/rule)
sql="reload @@config_all;"
echo "执行配置重载:$sql"
mysql -h${MYCAT_HOST} -P${MYCAT_PORT} -u${MYCAT_USER} -p${MYCAT_PWD} -e "$sql"
if [ $? -eq 0 ]; then
echo "配置重载成功!"
else
echo "配置重载失败,请检查配置文件语法!"
exit 1
fi
4.2 常用管理命令
| 命令 | 说明 |
|---|---|
reload @@config_all |
重载所有配置 |
reload @@schema |
仅重载schema.xml |
show @@datanode |
查看分片状态 |
show @@datahost |
查看物理库连接状态 |
show @@connection |
查看当前连接数 |
stop @@mycat |
停止Mycat |
4.3 数据迁移&扩容
4.3.1 分片扩容原则
- 模运算分片:扩容需重新分配数据(如2分片→4分片,需将原数据按新模值迁移);
- 范围分片:扩容只需新增分片,修改rule.xml的范围配置即可;
- 全局表:扩容后需同步全量数据到新分片。
4.3.2 数据迁移工具
- Mycat自带工具:
mycat-data-migration(适合小数据量); - 第三方工具:DataX、Canal(适合大数据量、在线迁移)。
4.4 监控与日志
- 日志位置:
logs/mycat.log(业务日志)、logs/manager.log(管理日志)、logs/wrapper.log(启动日志); - 监控方式:
- Mycat自带Web监控:访问
http://MycatIP:8080(默认账号:admin/123456); - 第三方监控:结合Prometheus+Grafana(需部署Mycat_exporter)。
- Mycat自带Web监控:访问
五、Mycat避坑指南(补充完善)
5.1 SQL语法限制
- 不支持
SELECT * FOR UPDATE(行锁失效); - 不支持
GROUP BY多字段+HAVING复杂条件; - 跨分片JOIN仅支持2表,且需关联字段为分片字段;
- 避免使用
SELECT *,需明确字段(减少Mycat解析压力)。
5.2 联表查询问题
- ER表解决方案:通过
childTable标签绑定关联表,确保父子表数据在同一分片; - 全局表解决方案:字典表设为全局表,全部分片同步,解决跨分片JOIN;
- 避免跨分片JOIN:复杂关联查询建议在应用层拆分(先查主表,再查子表)。
5.3 分布式主键问题
Mycat提供全局序列号解决分布式主键冲突,配置示例(sequence_db_conf.properties):
# 使用数据库方式生成全局ID
SEQ_USER.HIS=0
SEQ_USER.MIN=10000000
SEQ_USER.MAX=99999999
SEQ_USER.CURRENT=0
SEQ_USER.DB=user_dn1
5.4 性能优化
- 关闭
sqlMaxLimit:若应用已显式指定LIMIT,可设为-1避免重复添加; - 调整连接池:
dataHost的maxCon/minCon根据业务并发调整(建议maxCon≤500); - 禁用不必要的解析:关闭
parseComment、sqlInterceptor等非必需功能; - 读写分离优化:
balance=1时,确保从库延迟在可接受范围内(建议≤1s)。
5.5 高可用注意事项
- 心跳语句优化:避免使用
select 1(部分MySQL集群不兼容),推荐select user(); - 备用主库配置:至少配置2个
writeHost,确保主库故障时自动切换; - 监控物理库:Mycat仅检测连接可用性,需额外监控MySQL主从同步状态。
六、总结
Mycat作为成熟的分库分表中间件,能有效解决单库性能瓶颈,但核心是“合理设计分片规则+规范SQL写法”。在落地过程中,需注意:
- 分片规则需结合业务场景(如日志表按日期、用户表按ID模);
- 尽量避免跨分片操作(JOIN、事务),减少性能损耗;
- 运维层面做好配置热重载、监控、故障切换,保障稳定性;
- 小步迭代:先垂直分库,再水平分表,逐步扩容。
参考资料
- Mycat官方文档:http://mycatone.top/
- Mycat 1.6权威指南:https://www.yuque.com/books/share/0576de75-ffc4-4c34-8586-952ae4636944
- Mycat源码:https://gitee.com/MycatOne/Mycat-Server
声明:本文基于Mycat 1.6.7.6编写,不同版本配置略有差异,请以官方文档为准。