Mycat分库分表

Posted by     "zengchengjie" on Tuesday, April 19, 2022

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注释导致的解析错误;
  • 权限控制:可通过readOnlyprivileges精细控制用户权限,生产环境避免使用弱密码。

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(启动日志);
  • 监控方式
    1. Mycat自带Web监控:访问http://MycatIP:8080(默认账号:admin/123456);
    2. 第三方监控:结合Prometheus+Grafana(需部署Mycat_exporter)。

五、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避免重复添加;
  • 调整连接池:dataHostmaxCon/minCon根据业务并发调整(建议maxCon≤500);
  • 禁用不必要的解析:关闭parseCommentsqlInterceptor等非必需功能;
  • 读写分离优化:balance=1时,确保从库延迟在可接受范围内(建议≤1s)。

5.5 高可用注意事项

  • 心跳语句优化:避免使用select 1(部分MySQL集群不兼容),推荐select user()
  • 备用主库配置:至少配置2个writeHost,确保主库故障时自动切换;
  • 监控物理库:Mycat仅检测连接可用性,需额外监控MySQL主从同步状态。

六、总结

Mycat作为成熟的分库分表中间件,能有效解决单库性能瓶颈,但核心是“合理设计分片规则+规范SQL写法”。在落地过程中,需注意:

  1. 分片规则需结合业务场景(如日志表按日期、用户表按ID模);
  2. 尽量避免跨分片操作(JOIN、事务),减少性能损耗;
  3. 运维层面做好配置热重载、监控、故障切换,保障稳定性;
  4. 小步迭代:先垂直分库,再水平分表,逐步扩容。

参考资料

  • 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编写,不同版本配置略有差异,请以官方文档为准。