ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MyCat2安装模板实战:从解压配置到分片与读写分离避坑指南

MyCat2安装模板实战:从解压配置到分片与读写分离避坑指南 简介MyCat 2 的 1.21 版本安装模板压缩包面向需要快速搭建分布式数据库中间件的开发与运维人员。MyCat 2 是 Java 编写的开源分库分表中间件支持读写分离、SQL 路由与分布式事务该模板将启动脚本、核心配置和环境依赖整合在一起省去手工部署时的多处调整。压缩包共 52 个文件大小约 1.19MB以 sql、json、xml、properties 等配置与脚本为主同时附带面向 Linux/Windows/macOS 等系统的 wrapper 可执行文件及动态库便于在不同平台直接启动服务。截至目前已有 640 人学习下载。解压后可看到完整目录结构conf 集中日志、数据源、用户、集群等配置sql 目录提供初始化表结构与序列脚本bin 内置 mycat/mycat.bat 启停命令。对初学者这是一份可运行的部署样例能对照理解各配置项的作用对生产团队也可作为规范化安装和快速排错的基础。1. 为什么还需要一份 MyCat2 安装模板从 1.x 迁移到 2.x 的第一个坑拿到mycat2-install-template-1.21.zip的第一反应很多人会以为里面躺着熟悉的schema.xml、rule.xml结果一解压发现全是.json和一堆wrapper-*可执行文件当场翻车。我当初从 MyCat 1.x 迁到 MyCat 2.x 时就是这样照着老博客改配置启动脚本一跑直接报Unable to start JVM后来才发现模板里的wrapper.conf、conf/datasources、conf/schemas才是 2.x 的核心。这份模板的价值在于它把 MyCat2 部署所需的最小文件集和跨平台启动器打包好了你不需要去源码仓库里一个个找依赖解压、调 JDK、改数据源、起服务就能得到一个可用的分布式数据库中间件。适合第一次接触 MyCat2 的 DBA、需要快速搭测试环境的 Java 后端以及正在维护 1.x 想评估升级成本的运维。2. 拆开 mycat2-install-template-1.21.zip目录结构与每个文件的作用2.1 bin 目录wrapper 脚本和跨平台启动器bin目录是模板里最容易被忽略却又最关键的部分。mycat和mycat.bat是启动/停止/重启的统一入口其他以wrapper-开头的文件则是 Tanuki Java Service Wrapper 的本地守护程序。MyCat2 本身是 Java 应用但直接java -jar启动不利于守护和崩溃自拉起所以官方模板用 Wrapper 把进程包了一层bin/mycat start最终会调用对应平台的wrapper-*可执行文件由它拉起 JVM 并监听退出状态。模板里带了一堆不同 CPU/OS 的 wrapper 可执行文件包括wrapper-aix-ppc-32、wrapper-solaris-sparc-32、wrapper-linux-ppc-64、wrapper-windows-x86-32.exe等。实际部署时你几乎只用得上wrapper-linux-x86-64或wrapper-windows-x86-64.exe其余纯属打包时为跨平台兜底。我一般会把无关平台文件直接删掉只留本机对应的那个这样既节省空间也避免误用导致启动失败。bin/mycat脚本本身是一个标准的 init 风格包装器支持start、stop、restart、status。它做的事很简单检查wrapper.conf是否存在找到 Java 命令然后调用 wrapper 可执行文件。所以如果你换过 JDK 路径优先去wrapper.conf里改而不是改bin/mycat里的逻辑。2.2 conf 目录MyCat2 的 JSON 配置体系MyCat2 最大的变化之一就是放弃了 1.x 的 XML 配置家族全面转向 JSON。conf目录下除了server.json、wrapper.conf、logback.xml这些单文件还出现了schemas、datasources、clusters、users四个子目录。这四个目录分别对应 MyCat2 的逻辑库、物理数据源、集群分组和用户权限职责与 1.x 的schema.xml中的schema、dataHost、dataNode、user一一对应但拆分成了按目录管理的 JSON 文件。server.json是 MyCat 服务本身的配置比如监听 IP、端口、序列生成策略。模板里的server.json默认端口是 8066注意别把它当成 MySQL 的 3306。wrapper.conf是 JVM 参数的大本营wrapper.java.initmemory控制初始堆wrapper.java.maxmemory控制最大堆改错这里启动必挂。logback.xml是日志框架配置MyCat2 用 logback 而不是 log4j所以日志输出格式和滚动策略都在这里调。sequences和dbseq.sql是用来做全局序列的。dbseq.sql是一个建表脚本如果你要使用数据库方式生成分布式 ID就需要先在后端 MySQL 里执行它。sql目录里放着模板自带的初始化 SQL具体内容要看版本但通常包含mycat内部表的建表语句别小看它。2.3 lib 目录与 logswrapper 的本地库到底在干嘛lib目录下是一堆libwrapper-*.so、libwrapper-*.a、libwrapper-*.jnilib、libwrapper-*.dll和一个wrapper.jar。这些是 Wrapper 的本地库作用是在操作系统层做进程控制、信号捕获和输出重定向。简单说bin目录下的 wrapper 可执行文件负责“启动外部进程”libwrapper-*.so负责“和 Java 层对话”wrapper.jar则提供 Java 侧的 Wrapper 接口。版本必须匹配Linux x86_64 平台要同时有wrapper-linux-x86-64和libwrapper-linux-x86-64.so缺失或者混搭会直接导致UnsatisfiedLinkError或者启动后无日志。logs目录默认是空的但第一次启动后会产生wrapper.log和mycat.log。wrapper.log记录 JVM 启动、崩溃、重启这种底层事件mycat.log才是 MyCat 本身的业务日志。排查问题第一步永远是看这两个文件而不是看终端输出。我见过不少同事在bin/mycat start后终端没有任何报错就觉得万事大吉实际上 JVM 根本没起来全在wrapper.log里躺着。# 把模板解压到 /opt/mycat2 unzip mycat2-install-template-1.21.zip -d /opt/mycat2 cd /opt/mycat2 # 查看启动脚本支持的子命令 bin/mycat status上面的命令只是验证脚本能不能跑。注意bin/mycat status输出中如果提示not running说明 Wrapper 框架启动正常但你还没启动服务。如果提示一些cant load wrapper之类的错误就是bin与lib下的 wrapper 版本或平台不匹配优先检查这两个目录里的文件是否来自同一个平台。3. 把模板变成可用实例从解压到启动的完整配置路径3.1 环境准备JDK 版本选择和 wrapper.conf 调整MyCat2 基于 Java 8 开发实测在 JDK 8 和 JDK 11 上都能跑但我一般固定在 JDK 8。原因不是 JDK 11 不行而是很多公司内部运维脚本、监控 agent 都按 JDK 8 路径写死换版本容易触发其他问题。安装模板不会帮你装 JDK它只负责启动已经存在的 Java所以第一步是确认java -version可用并记下java的绝对路径。# 确认 Java 版本 java -version # 查看实际 java 二进制路径 which java拿到路径后编辑conf/wrapper.conf。找到wrapper.java.command如果它默认是java最好改成绝对路径否则bin/mycat start时会因为 PATH 环境变量不一致而找不到 JVM。内存参数也要在这里调wrapper.java.initmemory是初始堆wrapper.java.maxmemory是最大堆。对于 8G 内存的机器我习惯把初始堆设为 512M最大堆设为 2048M超过 2048M 反而容易因为 Full GC 暂停过长导致 Wrapper 误判卡死。# conf/wrapper.conf 关键参数 wrapper.java.command/usr/local/jdk1.8.0_202/bin/java wrapper.java.initmemory512 wrapper.java.maxmemory2048注意wrapper.java.initmemory的单位是 MB直接写数字就行不要写512m或512M否则 Wrapper 解析数字时会抛异常。这是我第一次部署时踩过的坑照着网上博客在数字后面加了个m结果Unable to start JVM。另外wrapper.java.classpath通常已经由模板写好了不需要动它会自动加载../lib/*.jar。3.2 初始化数据库和配置 schema先建库再配 MyCatMyCat2 是一个中间层它不存储数据所有数据都在后端 MySQL 实例上。所以在启动 MyCat 之前要先在后端 MySQL 里把物理库和表建好然后再告诉 MyCat哪个逻辑库对应哪个物理库、哪张表要走分片。顺序反了的话MyCat 能启动但执行 SQL 时会报Table doesnt exist而且这个错误不会出现在启动日志里只会在客户端连接时报。-- 在后端 MySQL 执行创建两个物理库 CREATE DATABASE db_0 DEFAULT CHARACTER SET utf8mb4; CREATE DATABASE db_1 DEFAULT CHARACTER SET utf8mb4; -- 在每个库中建相同的表结构 CREATE TABLE db_0.t_user ( id bigint NOT NULL, name varchar(64) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB; CREATE TABLE db_1.t_user ( id bigint NOT NULL, name varchar(64) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB;建好物理库后进入conf/datasources新建数据源文件。MyCat2 的数据源配置是每个文件对应一个物理连接池文件名氛围prototypeDs.datasource.json这种格式。下面是一个最小化的 JDBC 数据源配置{ name: ds_0, dbType: mysql, type: JDBC, url: jdbc:mysql://127.0.0.1:3306/db_0?useSSLfalsecharacterEncodingutf8, user: root, password: 123456, maxCon: 100, minCon: 1, weight: 1, instanceType: READ_WRITE }这个 JSON 里的name是连接池唯一标识后续 cluster 和 schema 都要引用它instanceType设为READ_WRITE表示这个数据源可以承担读写如果做读写分离只读实例要设为READ。maxCon是最大连接数按后端 MySQL 的max_connections调整minCon是预热连接数。模板里的conf/datasources目录下通常会有一个prototypeDs示例我建议直接复制它再改name和url不要从零手写字段容易漏。接着配置逻辑库。在conf/schemas目录下新建对应逻辑库的 schema 文件{ schemaName: mydb, targetName: ds_0 }schemaName是你给业务方看的数据库名targetName指向刚才的数据源名。这是最简单的一库一映射MyCat2 会把对mydb的所有 SQL 路由到ds_0对应的连接池。到这里最小配置已经具备可启动性。3.3 启动 mycat 并验证端口和状态配置完成后回到模板根目录启动。第一次启动建议在前台跑一次bin/mycat console这样能直接看到 JVM 输出的错误信息而不是被 Wrapper 吞到文件里。确认没问题后再用bin/mycat start转后台。cd /opt/mycat2 # 前台调试启动终端会直接打日志 bin/mycat console # 或者直接后台启动 bin/mycat start # 查看进程状态 bin/mycat statusbin/mycat console会抢占终端看到类似MyCAT Server startup successfully的日志后按CtrlC停掉再执行bin/mycat start让它在后台跑。status命令如果返回running (pid: 12345)说明 Wrapper 已成功拉起 JVM。接下来用 MySQL 客户端验证端口mysql -h127.0.0.1 -P8066 -uroot -p123456注意用户名和密码要对应conf/users目录下配置的用户文件。连接成功后执行SHOW DATABASES;如果能看到你配置的mydb逻辑库那么模板的“解压 → 配置 → 启动 → 连接”链路已经打通。如果SHOW DATABASES为空或者报权限错误去conf/users下检查用户配置的 schema 授权范围。4. 读写分离与分片配置实战server.json、datasource、cluster 的关系4.1 数据源配置从后端 MySQL 到 MyCat 的逻辑映射你可能会问直接让 MyCat 连接 MySQL 不就行了吗为什么还要拆出 datasource、cluster、schema 三层因为 MyCat 需要知道后端有哪些实例、哪些是可写的、哪些是只读的、读写怎么分。datasources是“点”每个文件代表一个物理连接池clusters是“线”把多个数据源串成一组定义读写策略schemas是“面”把逻辑库映射到某个 cluster 或 datasource 上。最开始用模板时我把所有库都配成了一个READ_WRITE数据源读写分离一直没生效。后来才发现读写分离的前提是clusters目录里配一个主从 cluster主节点用READ_WRITE或写专用从节点用READ。MyCat2 的 cluster 配置里有两个关键字段masters和replicas。masters列表里放可写数据源的namereplicas列表里放只读数据源的name。{ clusterName: cluster_0, masters: [ds_master], replicas: [ds_slave1, ds_slave2], readBalanceType: BALANCE_ALL, writeBalanceType: BALANCE_ALL, readType: DEFAULT }readBalanceType控制读请求如何在多个 replica 间分配BALANCE_ALL表示所有可用的只读节点参与负载均衡writeBalanceType对 master 列表做同样的均衡。如果只有一个主节点writeBalanceType设不设都无所谓。readType一般保持DEFAULT表示读请求按路由规则决定是否落从库。这样配置后MyCat 对SELECT会优先路由到ds_slave1或ds_slave2对INSERT/UPDATE/DELETE会路由到ds_master。4.2 分片规则与 cluster让 SQL 路由到正确的分片分片是 MyCat2 最核心的能力但模板不会给你提供现成的分片策略它只提供配置载体。你要在schemas的逻辑表定义里指定分片键和分片算法。这里以最常见的取模分片为例假设t_user表按id分到两个库那么 schema 文件要改成指向一个 cluster而不是单一数据源。{ schemaName: mydb, targetName: cluster_0, shardingTables: { t_user: { sqlMaxLimit: 100, partition: { algorithm: mod_hash, column: id, shardingTargets: [ds_0, ds_1] } } } }这里的shardingTargets列出了t_user的数据分片mod_hash按id取模决定行落在哪个数据源。MyCat2 根据这个配置把 SQL 改写后发往对应后端。原理上MyCat2 会先解析 SQL从 WHERE 条件里提取分片键的值计算出目标分片然后把 SQL 路由过去如果 WHERE 没有分片键它就只能把 SQL 广播到全部分片再把结果合并。所以分片键的选择直接影响查询性能必须把它放到高频查询的过滤条件里。这里有个容易混淆的概念clusters管读写schemas管分片。两者并不冲突。分片表的数据可以分布在一组读写集群上非分片表直接挂在某个 cluster 或 datasource 上。模板的conf/clusters下通常会有一个prototype.cluster.json它就是给非分片表用的默认集群。我一般把非分片表放在normalTables分片表放在shardingTables避免所有表都要走一遍分片计算。4.3 用户权限与 SQL 限制users 目录中的安全配置conf/users目录下每个 JSON 定义一个 MyCat 登录账号对应 1.x 的user标签。最小配置如下{ username: root, password: 123456, ip: 127.0.0.1, dialect: mysql, poolSize: 10 }ip如果不写默认允许所有 IP 连接生产环境一定不要留空。poolSize是当前账号到 MyCat 的并发连接数和maxCon不同maxCon是 MyCat 到后端数据源的连接数poolSize是客户端到 MyCat 的连接数。如果业务有数百个应用实例同时连 MyCatpoolSize设 10 会导致连接排队常见现象是客户端报TooManyConnections但 MyCat 本身没挂。users 和 schema 的权限关系也需要留意。MyCat2 会检查该用户是否对某个逻辑库有访问权如果schemas里配置了mydb但用户 JSON 里没有关联字段那SHOW DATABASES可能看不到它。不同版本对权限关联的写法有差异我习惯在用户 JSON 里显式声明允许访问的 schema 列表字段名为schemas。这样做虽然会多几行配置但能在误操作时保住后端数据源不被无关用户探测到。{ username: app_user, password: app_pass, ip: 10.10.%, dialect: mysql, poolSize: 20, schemas: [mydb] }ip字段支持 MySQL 风格的通配符%比写死单个 IP 灵活。注意dialect必须和后端 MySQL 一致如果填成postgresqlMyCat2 会用 PostgreSQL 协议解析客户端请求直接握手失败。5. 避坑 / 常见问题MyCat2 安装模板使用中的五个典型故障5.1 启动报错 wrapper | Unable to start JVM内存参数写法错误现象bin/mycat start后终端没有输出但logs/wrapper.log里出现wrapper | Unable to start JVM。原因wrapper.conf中wrapper.java.initmemory或wrapper.java.maxmemory写了带单位的值比如1024m或者数值超过机器剩余内存。Wrapper 对这个参数要求纯数字单位由 Wrapper 自己识别为 MB带了字母后解析失败JVM 无法启动。解决打开conf/wrapper.conf把内存参数改成纯数字比如512和2048。改完执行bin/mycat restart。如果还报错用free -m看机器可用内存把wrapper.java.maxmemory调低到物理内存的三分之一以内。5.2 bin/mycat start 后进程秒退logs 里没有任何 Java 堆栈现象执行bin/mycat start后看status显示没有进程logs/wrapper.log只有一两条记录没有异常堆栈。原因最常见的是找不到 Java 命令。模板里的wrapper.java.command默认值是java它依赖JAVA_HOME环境变量。如果你通过 systemd 或 cron 启动 MyCat环境变量可能没有加载Wrapper 找不到java进程直接退出。解决在wrapper.conf里把wrapper.java.command硬编码为绝对路径比如/usr/local/jdk1.8.0_202/bin/java。我不建议只在/etc/profile里 exportJAVA_HOME因为非交互 shell 不一定读它。改完后执行bin/mycat start再bin/mycat status确认。5.3 3306 端口被占MyCat2 默认端口是 8066 还是 3306现象客户端连接时误用-P3306连上了本机 MySQL 而不是 MyCat或者反过来 MyCat 后端连接到了 3306 端口上的 MyCat 自己导致循环连接。原因MyCat2 模板的server.json默认监听 8066不是 3306。很多从 MySQL 直接迁移的同事下意识用 3306 连接结果连到了后端 MySQL而配置 datasource 时又把 MyCat 自己的 8066 当成 MySQL 端口形成自连。解决客户端连接 MyCat 时明确使用-P8066并在conf/datasources中确认所有url指向真正的后端 MySQL 端口。如果业务要求客户端用 3306 端口访问 MyCat可以修改server.json的port为 3306但必须同时停掉本机 MySQL否则端口冲突。5.4 连接 MyCat 报 Unknown database testschema 目录里没有对应库现象mysql -h127.0.0.1 -P8066 -uroot -p能成功登录但执行USE test时报Unknown database test。原因MyCat2 的逻辑库不是从后端 MySQL 自动同步的。后端 MySQL 里CREATE DATABASE test后MyCat2 不会感知除非你在conf/schemas目录下为该库创建了对应的 schema JSON 文件。解决在conf/schemas目录新建test.schema.json内容至少包含schemaName和targetName后端物理库真实存在即可。改完不需要重启 MyCat它会定期加载配置文件如果不生效执行bin/mycat restart。从那以后我每次建库都会先在 conf 目录里同步创建 schema 文件再通知业务方使用否则“库不存在”的报错会让人误以为数据库连接有问题。5.5 分片查询结果错乱分片键没进 WHERE 或者用了不支持的函数现象执行SELECT * FROM t_user返回的数据重复或者缺失插入数据后查不到有些带max(id)、order by的 SQL 结果与预期不一致。原因分片表的路由依赖 WHERE 条件中的分片键。没有分片键时MyCat2 会把 SQL 广播到全部分片再对结果做合并。部分聚合函数和排序在合并阶段可能无法正确处理导致结果错乱。另外如果分片键字段类型不匹配比如字符串id和整数id混用取模结果也会乱。解决要求业务 SQL 必须带分片键等值条件例如WHERE id 100或WHERE id IN (100, 101)。对于必须全表扫描的场景把表改成非分片表或者使用 MyCat2 的全局表机制让每张分片都保留完整副本再走广播路由。我在模板初始化时就会在schemas的normalTables里声明这类小表避免后患。6. 验证安装的进阶套路用 explain 和状态表确认路由与读写分离生效安装模板本身不生产业务数据但它把所有验证手段都留好了logs目录记录执行过程conf目录让配置可追踪。我最常用的一套验证方法是先看进程再看端口最后用 MyCat 自己的 explain 能力检查 SQL 路由。6.1 用 SQL 的 explain 查看路由结果MyCat2 支持在 SQL 前加explain来输出路由计划而不是 MySQL 那种传统的执行计划。比如EXPLAIN SELECT * FROM mydb.t_user WHERE id 1;返回结果会显示这条 SQL 被路由到了哪个数据源和目标分片。如果id 1按mod_hash应该落在ds_0但 explain 显示目标为ds_1说明分片算法或分片键类型有问题需要立刻检查。我一般把这个输出和业务日志里的实际慢查询做对照很快就能定位是否发生了不必要的全分片广播。6.2 通过状态命令检查读写分离连接 MyCat 后执行SHOW datasource;这个命令会列出所有后端数据源的状态包括连接数、负载、心跳是否正常。如果replicas里配了从库但SHOW datasource中完全看不到该数据源说明 cluster 配置没有被加载读请求永远不会落到从库。还有一个技巧在 MySQL 主库和从库分别执行SHOW PROCESSLIST发一些查询观察哪个实例的Command多为Query。写只到主库是正常读全到主库则要检查clusters配置里的readBalanceType是否为BALANCE_ALL。实际排查时我会先把wrapper.conf改好再启动然后按顺序执行bin/mycat status、mysql -h127.0.0.1 -P8066 -uroot -p、SHOW DATABASES、EXPLAIN这几步。如果任何一步没达到预期优先去看logs/mycat.log里最近 50 行里面的路由错误或配置加载错误通常比终端提示更详细。有一次我因为datasources目录下残留了一个旧的.json文件里面用户密码和集群中引用不一致导致 MyCat 启动时加载了这个文件看起来是“核对了配置”实际上用了脏数据。从那以后我每次修改任何配置前都强制先备份整个conf目录改完重启后跑一遍上面的验证流程确认无误才交给业务同事。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进