分片键选错致vschema失效、外键与自增主键在分片后失效、垂直拆分后跨keyspace join报错、直连切vitess后连接池超时频发——四大隐式假设陷阱需逐一规避。

分片键选错导致 VSchema 无法生效
Vitess 的 VSchema 不会自动校验分片键是否真实存在于表结构中,也不会检查其是否被正确索引。一旦把非主键、无索引、或类型不匹配的字段设为 sharded 表的 shard_key,后续所有路由都会失败——查询可能随机打到某个分片,写入则大概率报 vttablet: rpc error: code = InvalidArgument desc = no keyspace specified 或更隐蔽的 no matching shard。
实操建议:
- 确认分片键字段在 MySQL 表中存在、类型与
VSchema中声明一致(比如INT别写成BIGINT) - 该字段必须有单列索引(
KEY或PRIMARY KEY),Vitess 不接受联合索引中的第二列作分片键 - 用
vreplication迁移前,先在源库执行EXPLAIN SELECT * FROM t WHERE shard_col = ?,确保走索引 - 测试时用
vtctlclient GetSchema keyspace_name确认VSchema已加载,再查vtctldUI 的 “Routing Rules” 标签页看是否标绿
MySQL 外键和自增主键在分片后失效
Vitess 不支持跨分片外键约束,也不保证全局自增唯一性。如果原 MySQL 库用了 FOREIGN KEY 或依赖 AUTO_INCREMENT 值做业务逻辑(比如“订单号=用户ID+自增ID”),上线分片后立刻出问题:插入报 ERROR 1105 (HY000): vtgate: ... foreign key constraint not supported,或自增 ID 在不同分片重复。
实操建议:
- 迁移前必须删掉所有
FOREIGN KEY定义,改用应用层一致性校验或最终一致的异步检查 -
AUTO_INCREMENT字段不能作为分片键;若必须保留编号语义,改用vitess_sequence表 +SELECT ... FOR UPDATE模拟,或直接用 UUID/雪花 ID - 已有数据含外键关联?用
vtctlclient MoveTables时加--source-read-only=false并提前停写,否则外键校验会阻塞复制
垂直拆分后跨 keyspace 关联查询报错 “table not found”
Vitess 的 VSchema 支持 vertical_split,但不会自动代理跨 keyspace 的 JOIN。哪怕两个 keyspace 都在同一个集群,写 SELECT * FROM user u JOIN order o ON u.id = o.user_id 仍会报 ERROR 1105 (HY000): vtgate: ... table order not found in keyspace user——因为 vtgate 默认只查当前 keyspace。
实操建议:
- 禁止在 SQL 中跨 keyspace 写裸
JOIN;必须用UNION ALL或应用层两次查询拼接 - 若需强一致关联,把相关表合并在同一 keyspace 下,用
sharded+ 合理分片键对齐(如都按user_id分) - 临时调试可用
/* vt+ SCATTER */hint 强制广播,但仅限小表且不推荐上生产
从 MySQL 直连切到 Vitess 后连接池超时频发
直连 MySQL 时连接池配置(如 maxIdleTimeMs=30000)在 Vitess 下容易触发频繁重连:vtgate 默认空闲连接 15 秒断开,而很多客户端库(如 Go 的 database/sql)默认心跳间隔是 30 秒,中间这 15 秒差就会让连接池复用已断连句柄,抛出 io: read/write on closed pipe 或 connection refused。
实操建议:
- 客户端侧把连接池
maxIdleTimeMs设为10000(10 秒),小于 vtgate 的-queryserver-config-idle-timeout(默认 15s) - 检查 vtgate 启动参数,确认没意外调低了
-queryserver-config-pool-size(默认 1000),高并发下不够用会排队超时 - 别复用老 MySQL 的
wait_timeout思维——Vitess 的连接生命周期由 vtgate 控制,不是后端 MySQL 实例
分片迁移最耗神的从来不是 SQL 改写,而是那些“看起来没毛病”的隐式假设:比如以为外键能自动跨片、以为自增 ID 还是全局唯一、或者觉得连接池参数搬过来就能用。这些点不逐个对齐,上线后的问题都是深夜告警级别。










