Bug 1 : wrapper.conf 数字类型参数配置有误,多了末尾的单位 M
https://wrapper.tanukisoftware.com/doc/english/prop-java-initmemory.html
wrapper.log
产生警告:
WARN | wrapper | 2023/04/20 22:42:00 | Encountered an invalid numerical value for configuration property wrapper.java.initmemory=256M. Resolving to 256.
WARN | wrapper | 2023/04/20 22:42:00 | Encountered an invalid numerical value for configuration property wrapper.java.maxmemory=2048M. Resolving to 2048.
Bug 2 : 执行错误的指令也不会报错
在 Mycat2 终端中执行任一满足 SQL 语法规则的 SQL 语句均不会报错,Mycat2 似乎不会去做语义分析验证对象的有效性。
例如,笔者并没有创建 ttt
数据库,但却可以 use ttt
且不报错。
mysql> use ttt;
Database changed
mysql> show tables;
Empty set (0.05 sec)
mysql> show databases;
+--------------------+
| `Database` |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| testdb |
+--------------------+
4 rows in set (0.00 sec)
Bug 3 : 逻辑库名错误识别为物理库名
最初,我认为 schemaName
是指逻辑库(方案)名,测试发现 Mycat 启动时报错,但最后却启动成功了。问了 Mycat 社区 并没有解决。
后来我将其配置为逻辑库对应的物理库名,启动时就不报错了。这让我认为 schemaName
是指物理库名。
再后来,当我发现 Bug 5 时,确信了 schemaName
是指逻辑库名,只是当前版本的 Mycat2 解析器有问题,要求原型库或数据源中必须存在与该逻辑库同名的物理库。
另外,当配置的逻辑库名与实际物理库名相同时,Mycat2 会自动获取表信息;否则不会自动获取表信息,需要为每一个逻辑表配置映射关系。
[root@ic-source conf]$ cat schemas/mycat_db.schema.json
{
"customTables": {},
"globalTables": {},
"normalTables": {
"logical_t1": {
"createTableSQL":"CREATE TABLE `logical_t1` (\n `id` int DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", // 可选
"locality": {
"schemaName": "testdb", // 物理库,可选
"tableName": "t1", // 物理表,可选
"targetName": "cls02" // 指向集群,或者数据源
}
}
},
"name": "mycat_db", // Mycat2 暂不支持
"schemaName": "mycat_db",
"shardingTables": {},
"targetName": "cls02"
}
当我将最外层的 schemaName
设置为 mycat_db
时,除了显式配置逻辑表 t2
,无论怎么配置,Mycat2 都不会获取到 testdb.t2
表的信息。
[root@ic-source conf]$ cat schemas/mycat_db.schema.json
{
"customTables": {},
"globalTables": {},
"normalTables": {
"logical_t1": {
"createTableSQL": null, // 可选
"locality": {
"schemaName": "testdb", // 物理库,可选
"tableName": "t1", // 物理表,可选
"targetName": "cls02" // 指向集群,或者数据源
}
},
"logical_t2": {
"locality": {
"schemaName": "testdb", // 物理库,可选
"tableName": "t2", // 物理表,可选
"targetName": "cls02" // 指向集群,或者数据源
}
}
},
"name": "mycat_db", // Mycat2 暂不支持
"schemaName": "mycat_db",
"shardingTables": {},
"targetName": "cls02"
}
不支持自动获取逻辑库中未配置而在物理库中存在的表,例如 testdb.t2
。
下图是我为了说明问题伪造的。
不知 Mycat2 是这块具体怎么实现的。
修改建议
- 将
schemaName
改名为name
或logicalSchemaName
属性以作区分,避免逻辑库名与物理库名混淆不清。而且,没必要要求必须存在与逻辑库同名的物理库。 - 增加三个属性:一个
defaultLocality
属性,包含两个子属性:defaultSchemaName
和defaultTargetName
。它们用于当没有为逻辑表配置locality
属性时,为其指定默认的映射关系。 - 支持动态调整 Schema 配置文件,而不是每次修改都要重启。Schema 级别应该设计得与 集群 和 数据源 级别不同,支持动态调整。最好全都支持动态调整,毕竟 Mycat 整体是个逻辑结构。
Bug 4 : 无法识别JSON 文件名中的逻辑库名称,且配置文件内缺少相应属性
Mycat2 服务启动没有任何报错。
$MYCAT_BASE/conf/schemas/mycat_db.schema.json
如下,其中 $MYCAT_BASE
为 Mycat2 的安装目录:
[root@ic-source conf]$ cat schemas/mycat_db.schema.json
{
"customTables": {},
"globalTables": {},
"normalTables": {
"logical_t1": {
"createTableSQL":"CREATE TABLE `logical_t1` (\n `id` int DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", // 可选
"locality": {
"schemaName": "testdb", // 物理库,可选
"tableName": "t1", // 物理表,可选
"targetName": "cls02" // 指向集群,或者数据源
}
}
},
"schemaName": "testdb", //物理库名,而非逻辑库名
"shardingTables": {},
"targetName": "cls02"
}
可以看到,该 JSON 配置文件名中的“方案名”为 mycat_db
,而在配置文件内容中却并没有相应的配置,其中的 schemaName
经测试是指物理库名。建议新增一个属性 name
或 logicalSchemaName
表示逻辑库名,与 clusters/prototype.cluster.json
和 datasources/prototypeDs.datasource.json
的配置规则(配置文件内包含 name
属性,与 JSON 文件名称一致)保持一致。
clusters/prototype.cluster.json
内容如下:
datasources/prototypeDs.datasource.json
内容如下:
而目前即便我配置了 `name· 属性,Mycat2 当前版本仍无法识别。
登录 Mycat2 终端,查看逻辑库名仍为物理库名 testdb
,期望为 mycat_db
。
所以,当前版本应将 JSON 文件名称中的“方案名”(即“数据库名”)设置为与数据源的实际物理库中的“方案名”相同,因为即便你配置得不同,Mycat2 也不识别。
-
如果采用某个读写数据源指向的物理库作为原型库,应该会报错,这个笔者以后有时间测试后补上。
-
如果未配置原型库,则在 Mycat2 终端中创建的所有数据库及内部对象只是 JSON 文件及其内容。
Bug 5 : 使用独立的原型库时造成混淆和冲突报错
此外,当配置一个独立的原型库时,会造成混淆。因为即便存在物理库 testdb
,仍可创建新的 testdb
(实际创建在独立的原型库中)造成混淆。
测试过程如下:
- 在 Mycat2 独立的原型库使用 MySQL 终端 mysql 查看:
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mycat | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec)
- 在 Mycat2 终端 执行:
mysql> create database testdb; Query OK, 0 rows affected (0.78 sec) mysql> show databases; +--------------------+ | `Database` | +--------------------+ | information_schema | | mysql | | performance_schema | | testdb | +--------------------+ 4 rows in set (0.08 sec) mysql> show tables from testdb; +------------------+ | Tables_in_testdb | +------------------+ | logical_t1 | | t1 | | t2 | +------------------+ 3 rows in set (0.05 sec)
- 在 Mycat2 独立的原型库使用 MySQL 终端 mysql 查看:
可以看到,在原型库中创建了mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mycat | | mysql | | performance_schema | | sys | | testdb | +--------------------+ 6 rows in set (0.00 sec)
testdb
数据库。
此操作还会再 Mycat2 服务器上的conf/schemas
目录下产生testdb
的配置文件:
这俩配置文件内容几乎一样,会在重启 Mycat 时因冲突报错。[root@ic-source conf]$ ll schemas/ 总用量 24 -rw-r--r--. 1 root root 2463 4月 21 15:49 information_schema.schema.json -rw-r--r--. 1 root root 529 4月 29 21:29 mycat_db.schema.json -rw-r--r--. 1 root root 3984 4月 22 19:26 mycat.schema.json -rw-r--r--. 1 root root 5299 4月 21 15:49 mysql.schema.json -rw-r--r--. 1 root root 962 4月 29 21:53 testdb.schema.json [root@ic-source conf]$ cat schemas/testdb.schema.json { "customTables":{}, "globalTables":{}, "normalProcedures":{}, "normalTables":{ "logical_t1":{ "createTableSQL":"CREATE TABLE `logical_t1` (\n `id` int DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", "locality":{ "schemaName":"testdb", "tableName":"t1", "targetName":"cls02" } }, "t1":{ "createTableSQL":"CREATE TABLE `testdb`.`t1` (\n\t`id` int DEFAULT NULL\n) ENGINE = InnoDB CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci", "locality":{ "schemaName":"testdb", "tableName":"t1", "targetName":"cls02" } }, "t2":{ "createTableSQL":"CREATE TABLE `testdb`.`t2` (\n\t`id` int NOT NULL,\n\t`name` varchar(30) NOT NULL,\n\tPRIMARY KEY (`id`)\n) ENGINE = InnoDB CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci", "locality":{ "schemaName":"testdb", "tableName":"t2", "targetName":"cls02" } } }, "schemaName":"testdb", "shardingTables":{}, "views":{} }
重启 Mycat2 时会失败,报错:
修改 Mycat2 自动生成的 schemas/testdb.schema.json
配置后,内容如下:
[root@ic-source conf]$ cat schemas/testdb.schema.json
{
"customTables":{},
"globalTables":{},
"normalProcedures":{},
"normalTables":{},
"schemaName":"testdb",
"shardingTables":{},
"views":{},
"targetName":"prototype"
}
重启 Mycat2 仍然报错。
此时,证实了 schemaName
属性实际上就是我所说的 name
或 logicalSchemaName
。兜兜转转,证明还是 Mycat2 SQL 解析器的问题。我认为此处不应该报错产生 [Error]
日志,而应产生 [INFO]
或 [WARN]
日志,提醒用户这么配置将导致逻辑库与物理库名称不一致。
Bug 6 : 逻辑表与物理表非同名时会看到“幻象”
使用上面 Bug 4 中的 $MYCAT_BASE/conf/schemas/mycat_db.schema.json
配置。
在 Mycat2 终端 查看:
在 MySQL 终端 查看:
Bug 7 : Mycat2 用户配置中 IP 无法识别 DNS 和主机名
users/root.user.json
文件内容如下:
[root@ic-source conf]$ cat users/root.user.json
{
"dialect":"mysql", // SQL 方言
"ip":null,
"username":"root", // Mycat 用户名
"password":"123456", // 上面的 Mycat 用户名的密码
"transactionType":"proxy",
}
当笔者将 ip
属性限制为只有 IP 地址 为 192.168.52.6
、主机名为 replica3
主机能访问时,分别使用 IP 地址和主机名却产生了不同的结果。
以下为 /etc/hosts
部分内容:
[root@ic-source ~]$ cat /etc/hosts
192.168.52.6 replica3
设置为 IP 地址或网段
修改 users/root.user.json
文件内容:
"ip":192.168.52.,
重启 Mycat 。
在非 replica3
主机上连接 Mycat2 报错:
在 replica3
主机上连接 Mycat2 成功:
配置为 IP 网段时 Mycat2 也可以识别。此处不加赘述。
设置为主机名
修改 users/root.user.json
文件内容:
"ip":"replica3",
重启 Mycat 。
在 replica3
主机上连接 Mycat2 报错:
笔者认为 Mycat2 的原型库设计有问题,只需要设计为元数据库即可。而开发者还试图将其作为处理数据库管理语句、DDL 语句等 SQL 语句的默认数据库。所有 MySQL 分库分表中间件的最终目的都是构建一个完整的 SQL 解析器,既要解析中间件自定义的语法,又要解析 MySQL 不断更新的所有语法,无疑会带来很高的实现复杂度。Mycat2 则选择了一种折中的办法,将无法解析处理的 SQL 在原型库上执行,以提高业务连续性,但他们没有考虑到用户很少使用、甚至不要该功能。在底层为复制拓扑,Mycat2 原型库为复制拓扑的 (复制)源(Source/Master) 时,还算有点用处。
首先,使用数据库中间件是需要一定的学习成本的,尤其是涉及到复杂的分库分表规则时。
其次使用 Mycat 中间件的用户,主要需求就是分库分表、分布式事务,对于 DDL、数据库管理语句等,基本不会在 Mycat 上操作。
最后,当前的原型库设计即便运行了DDL、数据库管理语句这些无法解析的语句,但却违背了用户本意,实属无用功,用户还要去处理 Mycat 因误解而带来的后果,比如删除在原型库中创建的数据库。