简介Mycat2 基础安装包面向需要在本地或服务器上搭建分布式数据库中间件的开发者与运维人员针对大数据量、高并发下单一数据库扩展受限的问题适合具备一定 Java 环境基础、希望实践数据分片与读写分离的中级学习者。压缩包共 51 个文件、约 1.2MB以多平台 wrapper 启动库so、dll、jnilib、a 等二进制、SQL 初始化脚本、JSON 与 XML 配置、可执行启动脚本及 jar 依赖为主覆盖 Windows、Linux、macOS、AIX、Solaris 等系统的启动适配解压后按目录完成配置即可运行。已有 1072 人学习下载具备参考与验证价值。包内分片规则、服务端参数、数据源与序列等配置模块相对完整可帮助读者理解 SQL 路由、读写分离、动态扩容与故障切换的落地方式也便于本地复现实验、排查启动问题或作为二次改造的基础模板。1. 解压后已经回了 successstatus 却显示 not running把 mycat2 基础安装包解压到 /opt执行bin/mycat start脚本回了一句 success再status却是 not running。这个场景我见过不止一次最离谱的一回是在一台预装了 JDK 17 的机器上日志里只留了一行InaccessibleObjectException查了半天才发现跟配置一点关系都没有是 JDK 版本选错了。mycat2 是跑在 JVM 上的 MySQL 中间件一个安装包、一个 JDK、一个能连上的 MySQL看起来比装数据库还省事。可真上手就会发现端口、账号、字符集、逻辑库名任何一处对不上客户端要么连不进来要么连进来查出来一堆乱码。这套环境适合手上有分库分表或读写分离需求、又不想动业务代码的团队也适合想在本机先跑通一套中间件再接业务的人。下面按我实际装的顺序走先定 JDK 和元数据库再解压首启然后逐个改配置最后把踩过的坑和验证方法一起交代清楚。2. 装前把三个硬条件定下来JDK、元数据库、端口内存安装包里不带 JRE也不带 MySQL。这两样东西的版本没定后面改多少遍 json 都是白费功夫。2.1 JDK 选 8 还是 11 还是 17看 jar 的编译版本不看心情mycat2 整个进程就是一个 java 进程启动脚本里最终执行的是java -jar或者java -cp。所以第一件事不是解压是搞清楚包里的 class 文件是按哪个 JDK 编译的。JDK 版本低于编译目标启动直接抛UnsupportedClassVersionErrorJDK 版本高出太多模块系统会把反射访问内部类的地方拦下来报InaccessibleObjectException。两种报错长得完全不一样但根子是同一件事。先看启动脚本里引用了什么这一步能顺带把 JVM 参数的落点找到# 看启动脚本里的 java 命令、堆参数和 jar 引用 grep -nE JAVA|Xmx|Xms|jar|classpath /opt/mycat2/bin/mycat | head -20再确认 jar 的编译目标。最省事的办法是看 MANIFEST里面通常会写Build-Jdk或Created-By# 从 MANIFEST 里读构建时用的 JDK unzip -p /opt/mycat2/lib/mycat2.jar META-INF/MANIFEST.MF | grep -iE Build-Jdk|Created-By如果 MANIFEST 里没写就扒一个 class 文件出来读字节码主版本号这个数字是硬的不会骗人# 取第一个 class读 major version unzip -Z1 /opt/mycat2/lib/*.jar | grep -m1 \.class$ unzip -p /opt/mycat2/lib/mycat2.jar io/mycat/某个类.class /tmp/probe.class javap -verbose /tmp/probe.class | grep major version对照关系记住这一张表就够了major version对应 JDK常见表现52JDK 8最稳老包基本都是这个55JDK 11一般能起偶发反射告警61JDK 17缺--add-opens就起不来我一般的原则是major 是 52 就用 JDK 8是 61 就老实上 JDK 17 并把模块参数补齐别拿 JDK 17 去跑给 JDK 8 编的包也别拿 JDK 8 去跑 61 的包。同一台机器上要留多个 JDK 时用系统自带的 alternatives 切换别去改全局的JAVA_HOME中间件和别的服务抢环境变量是运维事故的常见起点。JDK 11 和 17 上最常见的补救是把被模块系统封住的包重新打开参数加在启动脚本的 java 命令后面# JDK 9 反射访问内部类需要显式开放 java --add-opens java.base/java.langALL-UNNAMED \ --add-opens java.base/java.nioALL-UNNAMED \ --add-opens java.base/java.utilALL-UNNAMED \ -jar mycat2.jar--add-opens后面是「模块/包目标模块」ALL-UNNAMED表示对 classpath 上所有未命名模块开放。逐条加很烦但报错信息里会把缺哪个包直接写出来照着补就行。2.2 元数据库mycat2 自己不存元数据它得连一个 MySQLmycat2 的 schema、数据源、分片规则这些定义一部分在 conf 目录的 json 里一部分落在它自己连的那个 MySQL 库上包里配置通常叫 prototype 的那个数据源。所以顺序不能反先有能连的 MySQL再启动 mycat2。常见做法是单独建一个库专门放元数据别跟业务库混在一起-- 元数据库和中间件连接账号字符集必须和业务库一致 CREATE DATABASE mycat_meta DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER mycat_rw% IDENTIFIED BY 换成你的强密码; GRANT ALL PRIVILEGES ON *.* TO mycat_rw%; FLUSH PRIVILEGES;授权范围写*.*是因为中间件要代理多个物理库只给单个库的权限后面加分片就得回来补。生产上更稳妥的做法是按库授权但装环境阶段先打通链路权限可以后面收紧。MySQL 8.0 有个必须提前处理的点默认认证插件是caching_sha2_password包里有些老版本驱动不认连接时报Unable to load authentication plugin。要么把账号降级成mysql_native_password要么确认lib下的驱动是 8.x 的新版本。这一步在装之前做比启动后翻日志快得多。2.3 内存和端口2C4G 起8066 和 8067 别被占JVM 进程吃内存是刚性的1G 内存的机器上跑中间件还没等连业务库就被 OOM killer 干掉了。我一般给 2C4G 起步堆开到 1G 到 2G。堆参数在 bin 下的启动脚本里grep Xmx就能找到。端口方面mycat2 对外提供两个8066 是客户端连的 SQL 端口8067 是管理端口。装之前先探一遍最怕的是机器上残留着上一版进程端口占着新进程起来就退# 确认端口空闲以及机器内存够不够 ss -lntp | grep -E :(8066|8067)\b free -gss输出里如果已经有进程占着 8066先看清楚是哪个 pid是旧的 mycat 还是别的中间件别直接 kill 了别人的服务。云主机上还要记得安全组和本机防火墙放行 8066只在内网用的话就别对公网开。3. 解压与首启把安装包落到 /opt/mycat2 这个固定路径包解开之后路径选得随不随意直接决定后面要改多少配置。启动脚本里大量相对路径最忌讳的是放在带空格的目录、软链接目录、或者用户家目录下。3.1 目录结构和环境变量三处路径写错就白装解压、改名、固定到一个不带空格的绝对路径# 解压到 /opt 并统一目录名避免带版本号导致后面脚本要跟着改 unzip -q mycat2-basic.zip -d /opt mv /opt/mycat2* /opt/mycat2 ls /opt/mycat2解出来的结构大致是这几个目录先认一遍再动手目录/文件作用装的时候要不要动bin启动、停止、状态脚本改堆参数时才动conf服务端、数据源、schema 配置必动核心工作量在这lib依赖 jar基本不动换驱动时动logs运行日志不动排错靠它然后是环境变量。这里有个很隐蔽的坑JAVA_HOME必须在拼PATH之前 export顺序反了PATH里拼进去的是一个空目录java命令找到的是系统里另一个版本# /etc/profile.d/mycat2.sh export JAVA_HOME/usr/local/jdk8 export PATH$JAVA_HOME/bin:$PATH export MYCAT_HOME/opt/mycat2 export PATH$MYCAT_HOME/bin:$PATH写成 profile.d 下的独立文件比直接往/etc/profile里塞好维护删的时候也好删。写完source /etc/profile.d/mycat2.sh再用三条命令验一遍三条都对不上就别往下走echo $MYCAT_HOME # 应该是 /opt/mycat2 which java # 应该指向 $JAVA_HOME/bin/java java -version # 版本要和 2.1 里定的一致用 root 跑还是用普通用户跑也要先定。用普通用户跑更安全但要把/opt/mycat2的 logs 目录和 data 目录给它否则启动时写日志失败报错信息还藏在 wrapper 日志里。3.2 首启用 console别用 start第一次启动我一定用前台模式因为start是后台拉起的进程秒退时脚本只会给你一句 success 或者 failed真正的报错留在日志里还得回头翻。前台模式直接把日志打屏幕上一眼就能看出问题在第几行cd $MYCAT_HOME bin/mycat console启动过程里重点看几类信息端口有没有监听成功、prototype 数据源有没有连上、schema 加载了几个、有没有异常堆栈。不同构建的措辞不一样但这几个关键词基本都会出现抓关键字比逐行读快。日志同时会写进 logs 目录前台窗口滚没了还能回去翻。堆参数要改的话在 bin 下的启动脚本里找Xmx按机器内存给# 4G 内存的机器堆给 1G留够给操作系统和页缓存 JAVA_OPTS-Xms1g -Xmx1g -XX:UseG1GC-Xms和-Xmx设成一样避免运行中反复扩堆G1 在中间件这种长连接场景比 CMS 稳。改完先前台起一次确认没问题再切后台。确认能起来之后用后台方式管理顺手挂个 systemd比nohup靠谱得多机器重启也能自动拉起来# /etc/systemd/system/mycat2.service [Unit] Descriptionmycat2 middleware Afternetwork.target [Service] Typesimple Usermycat EnvironmentJAVA_HOME/usr/local/jdk8 EnvironmentMYCAT_HOME/opt/mycat2 ExecStart/opt/mycat2/bin/mycat console Restarton-failure LimitNOFILE65535 [Install] WantedBymulti-user.targetLimitNOFILE这行不能省中间件撑的是大量客户端连接默认 1024 的文件句柄很快就打满现象是连到一定数量后新连接全部超时日志里一堆 too many open files。写完systemctl daemon-reload再 enable之后就用systemctl status mycat2看状态。4. 三个配置文件决定能不能连进来server、datasource、schemaconf 目录下的 json 是这个环境真正的核心。结构上分三层服务端本身怎么对外、连哪些物理库、逻辑库怎么映射到物理库。三层任意一层断掉客户端都进不来。4.1 server.json端口、版本号伪装和字符集服务端配置管的是「我是谁、我在哪个端口上等」。关键键位就几个{ server: { port: 8066, managerPort: 8067, serverVersion: 5.7.31-mycat, charset: utf8mb4, idleTimeout: 300000 } }参数含义调整建议port客户端连的 SQL 端口冲突时改改完记得同步客户端配置managerPort管理端口只在内网开别对外serverVersion返回给客户端的版本号报 5.7.x 兼容性最好charset服务端字符集跟物理库保持一致统一 utf8mb4idleTimeout空闲连接回收毫秒小于后端 MySQL 的 wait_timeoutserverVersion这个参数容易被忽略但它很关键客户端驱动和一些 GUI 工具会按这个版本号决定用哪套语法和特性。报一个太新的版本号某些 ORM 会尝试用 8.0 的语法结果中间件这层不认报一个太老的连接池又可能不走预编译。我一般写成5.7.x-mycat这种形式兼容性最广。字符集这里的取舍要说清楚charset只决定服务端默认值真正决定中文会不会乱码的是四处是否一致包括客户端连接、server.json、JDBC url 里的characterEncoding、物理库和表的字符集。四处里有一处是 latin1中文就会出现一半正常一半问号的情况非常费时间。4.2 datasource.jsonJDBC URL 里四个必带参数数据源配置是中间件连后端 MySQL 的连接串。这一段写错启动时看着挺正常客户端一连就超时。{ dbType: mysql, url: jdbc:mysql://10.0.0.11:3306/order_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruerewriteBatchedStatementstrue, user: mycat_rw, password: 换成你的密码, instanceType: READ_WRITE, maxCon: 100, minCon: 10 }四个必带参数分别是useUnicode和characterEncoding保证编码链路一致useSSLfalse在内网直连时省掉握手开销公网链路另说别照抄serverTimezone不写就会踩时间字段差 8 小时的坑allowPublicKeyRetrievaltrue是给 MySQL 8.0 的caching_sha2_password用的不写会报公钥检索失败。maxCon要算一下再填后端 MySQL 的max_connections除以连同一个库的中间件实例数再留 20% 余量。一个实例随手写 500三个实例挂上去就把后端连接数打满现象是所有业务一起报连接超时比单个服务挂掉还难查。json 里不用转义直接写没问题但如果哪天把这段挪到 properties 或者 yaml 里和?就得处理编码类问题十有八九是挪配置时带进来的。4.3 schema 与 cluster逻辑库名对不上客户端连进来就是 Unknown database这一层管的是「客户端说要用 A 库中间件怎么把 A 库翻译成物理库 B」。结构示意大致是这样{ schemaName: order_db, targetName: cluster_order, shardingTable: [order_item] }schemaName是客户端-D后面跟的名字targetName指向 clustercluster 里再列出这个逻辑库落到哪些数据源上。不同构建的键名会有差异最终以包内 conf 下自带的示例为准照抄示例改值最稳。这里有四个名字必须对齐错一个就是Unknown database或者查不到表名字出现在哪常见错法逻辑库名schema.json 的 schemaName跟客户端 -D 不一致数据源名datasource.json 的文件名/ID和 cluster 里引用的对不上物理库名JDBC url 末尾那段建库时少写前缀表名shardingTable 列表大小写敏感环境里写错一个字母MySQL 在部分系统上表名大小写敏感本地开发不报错挪到服务器就报「表不存在」这类问题基本都出在这张表上。5. 排查启动秒退、连不上、认证失败怎么定位装中间件最花时间的不是装是出问题之后不知道看哪儿。下面五条是我这几年重复遇到次数最多的按「现象、原因、解决」记下来。5.1 启动阶段进程起不来的三种典型第一条脚本回 successstatus却显示 not running。现象是执行bin/mycat start之后提示成功但进程列表里没有端口也没监听。原因是后台脚本只负责把进程拉起来拉起来之后进程立刻退了脚本拿不到退出状态。真实原因全在日志里绝大多数是 JDK 版本不对或者 classpath 里缺东西。解决办法是改用bin/mycat console前台启动或者直接看 logs 下最新的日志文件找异常堆栈的第一行。十有八九是UnsupportedClassVersionError或者ClassNotFoundException前者换 JDK后者看 lib 目录是不是解压不全。第二条日志里InaccessibleObjectException。现象是 JDK 17 上启动报反射访问被拒绝堆栈指向java.base里的某个内部类。原因是 JDK 9 之后模块系统默认封装内部 API而中间件和一些序列化库大量用反射。解决办法是补--add-opens参数缺哪个包补哪个报错信息里写得很明白。如果补到第四五个还起不来就别硬撑了换回 JDK 8 或者 11中间件这类基础组件稳定比新更重要。第三条Address already in use。现象是启动失败日志里明确说端口被占用。原因是机器上残留着上一版进程或者同机部署了两个实例用了同一套端口。解决办法是先ss -lntp | grep 8066找到 pid确认是废弃进程再 kill要保留两个实例就把 server.json 里两个端口都改掉管理端口也要一起改只改一个照样冲突。还有一种更隐蔽的启动之后不报错但日志停在连接后端库那一步不动。这时候查三样东西——网络通不通telnet后端 3306、账号密码对不对、url 里的库名存不存在。卡在这一步说明服务端本身没问题问题在链路。5.2 连接阶段能连上但认证不过、查不到库第四条Unable to load authentication plugin caching_sha2_password。现象是客户端连接 8066 时直接报这个错连用户名密码都没走到。原因是后端 MySQL 8.0 默认用caching_sha2_password而包里的 JDBC 驱动是老版本不认这个插件。解决办法有两条路把账号改成mysql_native_password或者把 lib 下的驱动换成 8.x 版本。我一般选前者因为换驱动要重启进程改账号只需要一条 SQL-- 把中间件连接用的账号降级成兼容插件 ALTER USER mycat_rw% IDENTIFIED WITH mysql_native_password BY 换成你的密码; FLUSH PRIVILEGES;第五条Access denied for user xxx...但账号密码明明是对的。现象是用同一套账号密码直连物理 MySQL 没问题走 8066 就是进不去。原因是这中间有两套账号体系连 8066 用的是 conf 下 users 目录里的客户端账号连物理库用的是 datasource 里的后端账号很多人改错了一套。以为改的是中间件密码其实改的是后端库密码。解决办法是先分清当前在改哪一套客户端账号在 users 目录的 json 里后端账号在 datasource 里。确认之后再看 hosts 白名单有的配置里只允许特定来源 IP 登录本地能连、远程连不上就是这里卡住。6. 装完怎么验证一条落分片的 SQL 跑通才算数端口起来不算装好console里没报错也不算。我判断这套环境算不算跑通看的是三步缺一步都不敢交给业务方。第一步探端口两个端口都得是 LISTEN 状态而且进程是刚起的那个 pid# 两个端口都应该是 LISTEN进程号指向同一个 java 进程 ss -lntp | grep -E :(8066|8067)\b ps -ef | grep mycat | grep -v grep第二步登录 8066看逻辑库列表。客户端连中间件用的是 users 配置里的账号不是后端库账号这一点最容易混# -P 大写8066 是中间件端口-D 后面跟逻辑库名 mysql -h127.0.0.1 -P8066 -umycat_client -p -D order_db -e show databases;第三步是真落数据建一张分片表插一条记录然后绕开中间件直连物理库看这条数据到底落在哪个节点上。这一步验的是路由规则有没有生效只看中间件里能查出来是不够的——数据全落在第一个分片上中间件也能查出来。检查项命令或动作期望结果端口监听ss -lntp查 8066/8067两个都在 LISTEN服务端连通mysql -P8066登录能进交互界面逻辑库可见show databases;能看到配置的 schema分片生效插数据后直连物理库核对数据分布在不同节点中文正常插入含中文的记录再查不出现问号或乱码三步都过这套环境才算能交出去。中间哪一步失败日志都在 logs 下按第 5 章那五条对着看基本能定位到是配置层还是链路层。从那以后我每次装完 mycat2 都强制走一遍这个清单哪怕是给自己本机装的也不跳过分片落库那一步——曾经有一次偷懒只验了登录结果路由规则写错数据全压在一个分片上压测那天才发现代价比多花十分钟大得多。希望帮到你装的时候少走两个弯路就够了。本文还有配套的精品资源点击获取