mysql router 不能真正实现读写分离,它仅按配置路由连接而不解析sql;proxysql通过query rules支持语句级读写分离,但需手动配置规则、健康检查和权重,且事务中select需特殊处理避免一致性问题。

MySQL Router 本身不解析 SQL,不能自动识别 SELECT 或 INSERT 并据此路由——它只按配置把连接发给指定角色的实例。读写分离必须靠应用层主动连不同端口,或驱动配合(如 Connector/J 的 loadBalance 模式),Router 只负责“映射”。
必须先确认 MySQL 集群是否支持 Router 自动发现
Router 不是万能代理,它依赖后端集群提供准确的角色元数据:
- 推荐使用
InnoDB Cluster(基于 Group Replication);单主从复制环境需手动补全mysql_innodb_cluster_metadata库,否则启动报Failed to fetch cluster metadata - Router 所在机器必须能直连所有 MySQL 实例的业务端口(如
3306)和组复制端口(默认33061),防火墙常在这里卡住 - 配置中指定的用户要有
SELECT权限访问performance_schema.replication_group_members和mysql_innodb_cluster_metadata,否则元数据拉不到,默认 fallback 到全走PRIMARY
mysqlrouter.conf 里最关键的三个 section 必须配对
错一个名字或少一个段,读写分离就失效。重点不是写得多,而是语义一致:
-
[metadata_cache:mycluster]:名字必须和后面 routing 段里引用的完全一致;bootstrap_server_addresses至少填一个在线实例地址,如mysql://10.0.1.10:3306;ttl=5推荐,太长会导致故障转移延迟 -
[routing:read_write]:绑定端口建议用6446(行业惯例),destinations=metadata-cache://mycluster/default?role=PRIMARY——注意是PRIMARY,不是MASTER -
[routing:read_only]:绑定端口建议用6447,destinations=metadata-cache://mycluster/default?role=SECONDARY——Router 不认SLAVE或READ_ONLY这类词
应用层必须自己区分读写连接地址
Router 不会拦截、重写或重定向你的 SQL。它只管“连上来的是哪个端口”,然后转发到对应角色的实例:
- 写操作必须连
localhost:6446(或你配的read_write端口) - 读操作必须连
localhost:6447(或你配的read_only端口) - 如果应用用了 ORM,得确认它是否支持多数据源(如 Spring Boot 的
@Primary+@Qualifier),或改连接字符串逻辑 - 事务中混用读写?Router 无法感知,必须由应用保证整个事务连同一个端口(通常连
6446)
别指望 Router 处理复制延迟或 SELECT ... FOR UPDATE
Router 对 SQL 语义完全无感,也不检查从库延迟:
- 从库延迟高时,Router 不会自动剔除节点(除非配合 InnoDB Cluster 的故障转移机制)
-
SELECT ... FOR UPDATE是写意图,但 Router 仍会把它发到6447(如果应用连了这个端口),结果要么报错,要么读到旧数据 - 真正需要语句级路由(比如把带锁读、事务内读都强制走主库),得换
ProxySQL,并配mysql_query_rules表规则











