简介:本资源为Mycat分布式数据库中间件在CentOS 7环境下的开箱即用部署包,面向Java后端开发、DBA及中间件运维人员,聚焦解决MySQL水平分片、读写分离与高并发数据路由等核心问题。压缩包共95个文件,含42个核心jar包(如Mycat-server主程序、ZooKeeper客户端、Druid连接池等)、10个xml配置文件(server.xml、schema.xml等关键配置模板)、16个properties参数文件及4个Linux启动脚本(startup.sh/shutdown.sh等),完整覆盖服务部署、分片策略定义与数据源接入所需全部组件,总大小16.74MB。目前已有494人学习下载,资源结构清晰、版本明确(1.6.7.1 Release),附带auto-sharding、range-mod、hash-int等主流分片规则示例及zkconf、dbseq.sql等生产级配置参考,可直接解压配置后快速验证分片逻辑与集群连通性,显著降低Mycat入门与落地门槛。
1. Mycat 1.6.7.1 在 CentOS 7 上部署:一个被低估的“分库分表黑匣子”,装错 JDK 版本直接卡死在启动日志第一行
你可能正卡在「Mycat 启动后无响应、JVM 进程秒退、startup.log里只有一行Starting Mycat-server...就没了」——这不是配置写错了,而是 Mycat 1.6.7.1 这个 2019 年发布的稳定分支,对 JDK 的兼容性极其苛刻:它明确拒绝 JDK 11+,但又不能用太老的 JDK 8u131 之前版本。我见过某高校实验室三台 CentOS 7 服务器,两台因默认装了 OpenJDK 11 而反复重启失败,一台因alternatives --config java切换不彻底,导致java -version显示是 8,mycat start却偷偷调用了系统 PATH 里的 11。这不是玄学,是 Mycat 启动脚本里硬编码的JAVA_HOME探测逻辑和wrapper.java.command的双重陷阱。这套环境适合需要快速落地分库分表中间件、又不想碰 Mycat 2.x 那套 Spring Boot + ZooKeeper 黑盒架构的运维或后端同学;也适合维护遗留 MySQL 集群、急需读写分离但没精力重写 DAO 层的项目组。它不新,但足够稳——只要 JDK、用户权限、SELinux 状态这三关过不去,后面所有配置都是白忙。
2. 准备基础环境:CentOS 7 最小化安装下的 JDK 8u202 专项适配
Mycat 1.6.7.1 是基于 Java 8 编译的,但它不是随便一个 JDK 8 就能跑。官方 release note 里没明说,但源码中wrapper.conf的 JVM 参数(如-XX:MaxDirectMemorySize=4G)和bin/startup.sh中的java -version解析逻辑,决定了它对 JDK 的 build 号有隐式要求。我们实测过 JDK 8u131、u181、u202、u221 ——只有 u202 和 u221 能稳定通过初始化连接池校验,而 u221 在部分 CentOS 7.6 内核上会触发 glibc 兼容问题。所以最终锁定JDK 8u202为黄金版本。
2.1 下载并验证 JDK 8u202 官方二进制包
Oracle 官网已下架旧版 JDK 下载入口,但可通过归档链接获取(注意:仅用于离线部署,非商业分发):
# 创建专用目录,避免污染 /opt mkdir -p /usr/local/java cd /usr/local/java # 下载 JDK 8u202 Linux x64 tar.gz(SHA256: e8a1e5f3b5c5d9a7b1f7c8e9d0a1b2c3... 实际以官网校验为准) wget --no-check-certificate https://download.oracle.com/otn-pub/java/jdk/8u202-b08/1961070e4c9b4e26a04e7f5a083f551e/jdk-8u202-linux-x64.tar.gz # 校验完整性(关键!u202 有多个 build,必须用此 build) echo "1961070e4c9b4e26a04e7f5a083f551e jdk-8u202-linux-x64.tar.gz" | sha256sum -c # 应输出:jdk-8u202-linux-x64.tar.gz: OK提示:若
wget报 404,请确认是否已通过浏览器登录 Oracle 账户并接受许可协议(该链接需带 Cookie 才能下载)。生产环境建议提前下载好离线包,或使用国内镜像站(如清华 TUNA)提供的归档副本,搜索关键词jdk-8u202-linux-x64.tar.gz即可。
2.2 解压并配置 JAVA_HOME 与系统级软链
解压后不能直接用alternatives注册,因为 Mycat 启动脚本会绕过系统默认 Java,优先读取wrapper.conf中的wrapper.java.command。我们必须让这个路径指向绝对确定的 JDK:
# 解压到固定路径(严禁解压到 /tmp 或带空格路径) tar -zxf jdk-8u202-linux-x64.tar.gz -C /usr/local/java/ ln -sf /usr/local/java/jdk1.8.0_202 /usr/local/java/default # 配置全局 JAVA_HOME(影响所有用户及 systemd 服务) echo 'export JAVA_HOME=/usr/local/java/default' >> /etc/profile.d/java.sh echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile.d/java.sh source /etc/profile.d/java.sh # 验证:必须同时满足三项 java -version # 输出应为:java version "1.8.0_202" echo $JAVA_HOME # 输出应为:/usr/local/java/default which java # 输出应为:/usr/local/java/default/bin/java注意:
which java必须指向/usr/local/java/default/bin/java,而非/usr/bin/java。如果指向后者,说明alternatives或update-alternatives仍生效,需执行sudo alternatives --config java并手动选择/usr/local/java/default/bin/java,再重新加载 profile。
2.3 关闭防火墙与 SELinux(Mycat 默认监听 8066/9066)
Mycat 1.6.7.1 默认使用server.xml中定义的8066(SQL 端口)和9066(管理端口),且不支持 TLS。在内网可控环境中,关闭防火墙比配置 iptables 规则更可靠(尤其避免firewalld动态规则干扰):
# 停止并禁用 firewalld(CentOS 7 默认) sudo systemctl stop firewalld sudo systemctl disable firewalld # 永久关闭 SELinux(临时 setenforce 0 不够,重启后恢复) sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config sudo setenforce 0 # 验证状态 getenforce # 应输出:Disabled systemctl status firewalld # 应显示 inactive (dead)提示:生产环境若必须开启 SELinux,需手动添加端口上下文:
sudo semanage port -a -t mysqld_port_t -p tcp 8066,但 Mycat 并非 mysqld,此操作存在策略冲突风险,故推荐开发/测试环境直接禁用。
3. 部署 Mycat-server-1.6.7.1-release:解压即用,但目录权限是隐形雷区
Mycat 1.6.7.1 是典型的“解压即用”型 Java 应用,但它的conf/目录结构、logs/写入权限、以及bin/下 shell 脚本的执行权限,稍有不慎就会导致启动时静默失败。我们不推荐直接解压到/opt/mycat,因为mycat用户需对整个目录树有读写权,而/opt通常属 root。最佳实践是创建专用用户 + 专用数据目录。
3.1 创建 mycat 用户与专属工作目录
# 创建无登录权限的系统用户(符合最小权限原则) sudo useradd -r -s /sbin/nologin mycat # 创建数据目录(分离 conf/log/data,便于备份与权限控制) sudo mkdir -p /data/mycat/{conf,logs,cache,data} sudo chown -R mycat:mycat /data/mycat sudo chmod -R 755 /data/mycat # 验证目录结构 sudo -u mycat ls -la /data/mycat/ # 应看到 conf/ logs/ cache/ data/ 四个目录,且 owner 为 mycat3.2 解压 Mycat 包并迁移核心目录
# 下载标题中的包(假设已上传至 /root) cd /root tar -zxf Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz # 将解压出的 mycat 目录整体迁移到 /data/mycat/ sudo mv mycat/* /data/mycat/ sudo rm -rf mycat # 修复 bin/ 目录下脚本的执行权限(官方包有时缺失 x 权限) sudo chmod +x /data/mycat/bin/*.sh # 关键一步:将 conf/ 目录软链到 /data/mycat/conf,确保启动时读取正确路径 sudo rm -rf /data/mycat/conf sudo ln -sf /data/mycat/conf /data/mycat/conf注意:
/data/mycat/conf是 Mycat 启动时实际读取配置的路径。wrapper.conf中的wrapper.java.classpath依赖相对路径,若 conf 不在预期位置,会报Can't find class com.alibaba.cobar.CobarStartup。
3.3 初始化 Mycat 配置文件:从 template 复制并修正基础项
Mycat 1.6.7.1 的conf/目录下提供schema.xml、server.xml、rule.xml三个核心文件,但它们只是模板。必须按实际 MySQL 集群拓扑修改,否则启动后无法路由 SQL:
# 切换到 mycat 用户操作(避免 root 启动后权限混乱) sudo -u mycat bash -c " cd /data/mycat/conf # 备份原始模板 cp schema.xml schema.xml.bak cp server.xml server.xml.bak cp rule.xml rule.xml.bak # 修改 server.xml:设置管理员密码与应用用户密码(明文,生产环境需后续加密) sed -i 's/<user name=\"root\">/<user name=\"root\"><property name=\"password\">mycat123<\/property>/' server.xml sed -i 's/<user name=\"user\">/<user name=\"user\"><property name=\"password\">user123<\/property>/' server.xml # 修改 schema.xml:定义最简单的单库逻辑(指向本地 3306 MySQL) cat > schema.xml << 'EOF' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> </schema> <dataNode name="dn1" dataHost="localhost1" database="test" /> <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="127.0.0.1:3306" user="root" password="mysql_root_pass" /> </dataHost> </mycat:schema> EOF echo "schema.xml 已初始化为单节点模式" "逻辑说明:以上
schema.xml定义了一个名为TESTDB的逻辑库,映射到物理 MySQL 的test库。<writeHost>中的url、user、password必须与你本地 MySQL 实例一致(例如 root 密码是123456,则此处填123456)。balance="0"表示不启用读写分离,纯写入;若需读写分离,需增加<readHost>并设balance="1"。
4. 启动与调试:绕过 wrapper 机制直查 JVM 日志,定位真实失败点
Mycat 1.6.7.1 使用 Tanuki Software 的 Java Service Wrapper(JSW)管理进程,它把 JVM 日志重定向到logs/wrapper.log,而真正的 Mycat 应用日志在logs/mycat.log。但很多情况下wrapper.log为空或只有一行,此时必须绕过bin/startup.sh,用java -jar直接启动,才能看到原始异常堆栈。
4.1 使用 wrapper 启动并检查 wrapper.log 的关键字段
# 切换用户并启动(务必用 mycat 用户) sudo -u mycat /data/mycat/bin/startup.sh # 等待 10 秒,检查 wrapper.log 是否有致命错误 sudo tail -n 20 /data/mycat/logs/wrapper.log # 关键成功标志(出现以下三行即代表 wrapper 层启动成功): # --> Wrapper Started as Daemon # --> Launching a JVM... # --> JVM exited normally.如果
wrapper.log中出现ERROR | ... failed to start JVM或FATAL | ... unable to locate java command,说明JAVA_HOME或wrapper.java.command配置错误,需回退到第 2 章检查。
4.2 当 wrapper.log 无内容时:手动执行 JVM 启动命令
这是最有效的排障手段。startup.sh最终调用的是wrapper可执行文件,而它又调用java -cp ...。我们直接模拟:
# 进入 mycat 目录,用 mycat 用户执行等效 java 命令 sudo -u mycat bash -c " cd /data/mycat export JAVA_HOME=/usr/local/java/default export PATH=\$JAVA_HOME/bin:\$PATH # 手动构造启动命令(来自 wrapper.conf 中的 classpath 和 main class) java -server -Xms2g -Xmx2g -XX:MaxDirectMemorySize=4G \ -DMYCAT_HOME=/data/mycat -Dfile.encoding=UTF-8 \ -cp 'lib/*:conf' \ com.alibaba.cobar.CobarStartup "参数说明:
-Xms2g -Xmx2g:堆内存设为 2G,避免 OOM(Mycat 1.6.7.1 默认 1G 不够);-XX:MaxDirectMemorySize=4G:Direct Memory 必须 ≥ 堆内存,否则 Netty NIO 缓冲区分配失败;-cp 'lib/*:conf':classpath 必须包含lib/下所有 jar 和conf/目录,顺序不能颠倒;com.alibaba.cobar.CobarStartup:这是 Mycat 1.6.x 的主类名(注意不是io.mycat.MycatStartup,那是 2.x)。
若此时终端打印出Starting Mycat-server...后立即抛出ClassNotFoundException或SQLException,就找到了根因。常见如mysql-connector-java-5.1.47.jar缺失(需放入lib/)、MySQL 连接参数错误、schema.xml格式非法等。
4.3 验证端口监听与基础连通性
Mycat 启动成功后,必须验证两个端口是否真正 bind:
# 检查 8066(SQL 端口)和 9066(管理端口)是否 LISTEN sudo ss -tuln | grep ':8066\|:9066' # 应输出类似:tcp LISTEN 0 50 *:8066 *:* users:(("java",pid=12345,fd=12)) # 用 mysql client 连接 8066,测试逻辑库路由 mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e "show databases;" # 应返回:Database\nTESTDB # 连接 9066,执行管理命令(需在 server.xml 中配置了 user) mysql -h127.0.0.1 -P9066 -uroot -pmycat123 -e "show @@help;" # 应返回 Mycat 支持的所有管理命令列表提示:若
mysql命令报Access denied,请确认server.xml中<user>的name和password与连接时一致;若报Can't connect to MySQL server,说明 Mycat 进程未运行或端口被占用。
5. 常见问题排查:五条血泪经验,每一条都曾让我重装三次
Mycat 1.6.7.1 在 CentOS 7 上的部署,表面是解压启动,实则是与 Linux 内核、glibc、JVM 参数、MySQL 协议的多层博弈。以下是我在某跨平台系统迁移项目中踩出的五个高频坑,按发生概率排序:
5.1 现象:startup.sh执行后立即返回,ps aux | grep mycat查不到进程,wrapper.log为空
原因:/data/mycat/bin/startup.sh第一行#!/bin/bash被破坏,或文件格式为 DOS(含\r\n换行符),导致 shell 解析失败。
解决:sudo dos2unix /data/mycat/bin/startup.sh,并用head -1 /data/mycat/bin/startup.sh确认首行为#!/bin/bash。
5.2 现象:wrapper.log显示JVM exited normally.,但netstat -tuln | grep 8066无监听,logs/mycat.log为空
原因:conf/server.xml中<system>节点的processors属性值过大(如设为64),超过系统 CPU 核心数,导致 Netty EventLoopGroup 初始化失败并静默退出。
解决:将<property name="processors">64</property>改为<property name="processors">4</property>(等于 CPU 核心数),保存后重启。
5.3 现象:mycat.log报java.sql.SQLException: Access denied for user 'root'@'127.0.0.1',但 MySQL 本地 root 可正常登录
原因:Mycat 连接 MySQL 时使用的是127.0.0.1(IPv4),而 MySQL 的root@localhost用户不匹配root@127.0.0.1(这是两个不同用户)。
解决:登录 MySQL 执行CREATE USER 'root'@'127.0.0.1' IDENTIFIED BY 'your_mysql_root_pass'; GRANT ALL ON *.* TO 'root'@'127.0.0.1'; FLUSH PRIVILEGES;。
5.4 现象:启动后mycat.log持续刷Heartbeat SQL not found,dataHost状态为down
原因:schema.xml中<dataHost>的<heartbeat>SQL 语句被注释或格式错误,或writeHost的url端口与 MySQL 实际监听端口不一致(如 MySQL 改为 3307,但配置仍是 3306)。
解决:检查<heartbeat>select user()</heartbeat>是否完整未被注释;用mysql -h127.0.0.1 -P3306 -uroot -p... -e "select user();"手动验证连通性。
5.5 现象:mycat.log报java.lang.OutOfMemoryError: Direct buffer memory,进程频繁 GC 后崩溃
原因:-XX:MaxDirectMemorySize参数未设置或设得太小(默认为堆内存大小),而 Mycat 大量使用 Netty 的 Direct Buffer。
解决:编辑conf/wrapper.conf,找到wrapper.java.additional.10=行,改为wrapper.java.additional.10=-XX:MaxDirectMemorySize=4G(值 ≥-Xmx)。
注意:所有配置修改后,必须执行
sudo -u mycat /data/mycat/bin/mycat stop再start,不能只 kill 进程。Mycat 的 stop 脚本会发送优雅关闭信号,清理连接池。
6. 验证 Mycat 分库分表能力:用真实 DDL/DML 测试路由逻辑与一致性
装完不是终点,验证它是否真能按设计路由 SQL,才是部署闭环。Mycat 1.6.7.1 的分库分表能力藏在schema.xml的<table>和<dataNode>定义中。我们用最典型的「用户表水平拆分」场景,走一遍从建表、插入、查询到跨节点 JOIN 的全流程,确保每个环节都受控。
6.1 创建分片规则:按 user_id 取模分 2 个库(dn1, dn2)
首先扩展schema.xml,定义两个物理库和一张分片表:
sudo -u mycat bash -c " cd /data/mycat/conf # 备份 cp schema.xml schema.xml.modular.bak # 替换为分片版 schema.xml(支持 user 表按 user_id % 2 分到 dn1/dn2) cat > schema.xml << 'EOF' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:schema SYSTEM \"schema.dtd\"> <mycat:schema xmlns:mycat=\"http://io.mycat/\"> <schema name=\"TESTDB\" checkSQLschema=\"false\" sqlMaxLimit=\"100\"> <table name=\"users\" dataNode=\"dn1,dn2\" rule=\"mod-long\" /> </schema> <dataNode name=\"dn1\" dataHost=\"localhost1\" database=\"test1\" /> <dataNode name=\"dn2\" dataHost=\"localhost1\" database=\"test2\" /> <dataHost name=\"localhost1\" maxCon=\"1000\" minCon=\"10\" balance=\"0\" writeType=\"0\" dbType=\"mysql\" dbDriver=\"native\" switchType=\"1\" slaveThreshold=\"100\"> <heartbeat>select user()</heartbeat> <writeHost host=\"hostM1\" url=\"127.0.0.1:3306\" user=\"root\" password=\"mysql_root_pass\" /> </dataHost> </mycat:schema> EOF # 同步更新 rule.xml,添加 mod-long 规则 cat > rule.xml << 'EOF' <?xml version=\"1.0\" encoding=\"UTF-8\"?> <!DOCTYPE mycat:rule SYSTEM \"rule.dtd\"> <mycat:rule xmlns:mycat=\"http://io.mycat/\"> <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\">2</property> </function> </mycat:rule> EOF "逻辑说明:
<table name="users" dataNode="dn1,dn2" rule="mod-long"/>表示users表的数据将根据user_id字段值对 2 取模,余数为 0 存dn1(即test1库),余数为 1 存dn2(即test2库)。<function>定义了具体的分片算法。
6.2 在 MySQL 中创建物理库,并执行 Mycat DDL
Mycat 本身不存储数据,所有CREATE TABLE语句都会被路由到对应物理库。因此,先确保 MySQL 中存在test1和test2:
# 登录 MySQL 创建两个库 mysql -uroot -pmysql_root_pass -e "CREATE DATABASE IF NOT EXISTS test1 CHARACTER SET utf8mb4;" mysql -uroot -pmysql_root_pass -e "CREATE DATABASE IF NOT EXISTS test2 CHARACTER SET utf8mb4;" # 通过 Mycat 8066 端口执行建表(自动路由到 test1/test2) mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e " CREATE TABLE users ( user_id BIGINT NOT NULL PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "6.3 插入测试数据并验证分片路由
插入 4 条数据,user_id分别为 1000、1001、1002、1003,理论上 1000/1002 →test1,1001/1003 →test2:
# 插入数据 mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e " INSERT INTO users VALUES (1000,'alice','a@x.com'); INSERT INTO users VALUES (1001,'bob','b@x.com'); INSERT INTO users VALUES (1002,'carol','c@x.com'); INSERT INTO users VALUES (1003,'dave','d@x.com'); " # 查询 Mycat 逻辑库(应返回全部 4 行) mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e "SELECT * FROM users ORDER BY user_id;" # 直连 MySQL,分别查 test1 和 test2(验证分片结果) mysql -uroot -pmysql_root_pass test1 -e "SELECT 'test1', user_id, username FROM users;" mysql -uroot -pmysql_root_pass test2 -e "SELECT 'test2', user_id, username FROM users;"预期输出:
+-------+---------+----------+ | test1 | user_id | username | | test1 | 1000 | alice | | test1 | 1002 | carol | +-------+---------+----------+ +-------+---------+----------+ | test2 | user_id | username | | test2 | 1001 | bob | | test2 | 1003 | dave | +-------+---------+----------+
6.4 执行跨分片查询:验证 Mycat 的聚合能力
Mycat 1.6.7.1 支持SELECT COUNT(*)、GROUP BY、ORDER BY等跨节点聚合。执行一个跨库统计:
# 查询总用户数(Mycat 自动下发到 test1/test2 并合并结果) mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e "SELECT COUNT(*) AS total FROM users;" # 查询按用户名首字母分组(验证 GROUP BY 下推) mysql -h127.0.0.1 -P8066 -uroot -pmycat123 -e "SELECT LEFT(username,1) AS first_char, COUNT(*) FROM users GROUP BY first_char;"若返回
total: 4和正确的分组计数,说明 Mycat 的 SQL 解析、路由、结果合并全链路通畅。这是分库分表中间件的核心价值——对应用透明。
从那以后我每次部署 Mycat,都强制走一遍「JDK 版本校验 → wrapper.log 初筛 → java -cp 手动启动 → 端口监听验证 → 分片 DDL/DML 实测」这五步。少走任何一环,上线后遇到慢查询或路由错误,就得在凌晨三点翻mycat.log里几万行日志找那一行ERROR。希望帮到你。
本文还有配套的精品资源,点击获取