14.10.3 路由与读写分离不生效

路由与读写分离不生效通常由“规则未生效、匹配失败、会话被固定到写库、读库不可用”引起。建议先用最小化示例复现实验环境,再按顺序排查。

文章图片

1) 规则是否加载到运行内存#

运行内存无规则时,路由不会生效。

-- 对比配置表与运行时
SELECT rule_id,active,match_pattern,regex,destination_hostgroup
  FROM mysql_query_rules;

SELECT rule_id,active,match_pattern,regex,destination_hostgroup
  FROM runtime_mysql_query_rules;

若 runtime 为空或缺失规则,执行加载与持久化:

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

验证:

SELECT COUNT(*) FROM runtime_mysql_query_rules;

预期:返回值大于 0。

2) 规则优先级与匹配条件#

rule_id 小优先,active=1 必须开启;match_pattern/regex 必须命中真实 SQL(注意大小写、空白、注释)。

示例:最小读写分离规则

DELETE FROM mysql_query_rules;

INSERT INTO mysql_query_rules
(rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES
(10, 1, '^SELECT .*', 20, 1),
(20, 1, '^INSERT|^UPDATE|^DELETE|^REPLACE', 10, 1);

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

命令解释:
- rule_id: 规则优先级,越小越先匹配
- match_pattern: 正则匹配 SQL 语句
- destination_hostgroup: 路由目标组
- apply=1: 匹配即停止后续规则

验证命中:

SELECT * FROM stats_mysql_query_rules;

预期:hits 增长,且 destination_hostgroup 变为 20(读)或 10(写)。

3) 用户与默认主机组#

用户默认主机组错误会把所有请求固定到写库。

SELECT username,default_hostgroup,transaction_persistent
  FROM mysql_users;

default_hostgroup 不是写组(通常 10),或 transaction_persistent=1 导致会话固定写库,调整示例:

UPDATE mysql_users
SET default_hostgroup=10, transaction_persistent=0
WHERE username='app';

LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

4) 读库是否在线与健康检查#

读库不在线会导致读流量回落到写库。

SELECT hostgroup_id,hostname,status,weight,max_connections
  FROM mysql_servers;

预期:读组(如 20)服务器 status=ONLINE

查看健康检测:

SELECT * FROM stats_mysql_server_ping;
SELECT * FROM stats_mysql_replication_hostgroups;

若发现读库被标记 SHUNNED 或延迟超阈值,修复主从或调整阈值后再观察。

5) 会话行为导致固定写库#

事务会强制同一连接走写库。

-- 应用侧排查示例(MySQL 客户端)
SELECT @@autocommit;  -- 0 会固定到写库
BEGIN;                -- 开启事务
SELECT * FROM t1;     -- 会走写库
COMMIT;

建议:业务显式区分读写连接,或使用连接池拆分读写。

6) 关键排错命令清单#

-- 命中统计
SELECT * FROM stats_mysql_query_rules;

-- 连接路由
SELECT * FROM stats_mysql_connections;

-- 归一化 SQL 与路由
SELECT * FROM stats_mysql_query_digest ORDER BY count_star DESC LIMIT 5;

7) 可执行排错脚本(逐步验证)#

#!/usr/bin/env bash
# 文件: /opt/proxysql/check_rw.sh
# 说明: 快速检查规则与读库状态

MYSQL="mysql -h127.0.0.1 -P6032 -uadmin -padmin -e"

$MYSQL "SELECT COUNT(*) AS runtime_rules FROM runtime_mysql_query_rules;"
$MYSQL "SELECT rule_id,active,match_pattern,destination_hostgroup FROM runtime_mysql_query_rules;"
$MYSQL "SELECT username,default_hostgroup,transaction_persistent FROM mysql_users;"
$MYSQL "SELECT hostgroup_id,hostname,status FROM mysql_servers;"
$MYSQL "SELECT * FROM stats_mysql_query_rules;"

运行:

bash /opt/proxysql/check_rw.sh

预期:runtime 规则非空,读库 ONLINE,命中统计有增长。

8) 实战练习#

  1. 在测试环境创建读写组(写=10,读=20),为读写组各加一台 MySQL。
  2. 添加上述读写规则并加载到 runtime。
  3. 通过 ProxySQL 发送 SELECTINSERT,使用 stats_mysql_connections 验证路由。
  4. 手动把读库状态改为 OFFLINE_SOFT,观察读请求是否回落到写库。

练习命令示例:

UPDATE mysql_servers SET status='OFFLINE_SOFT'
WHERE hostgroup_id=20 AND hostname='10.0.0.2';

LOAD MYSQL SERVERS TO RUNTIME;

预期:SELECT 请求回落到写组。