14.5.3 query_rules匹配与优先级
在ProxySQL中,读写分离的核心在于mysql_query_rules表,它通过规则匹配将SQL路由到指定的hostgroup。规则匹配遵循“按优先级排序、逐条匹配、命中即停”的原则,因此理解匹配逻辑与优先级控制是确保路由准确的关键。
原理草图:优先级与命中流程#
规则字段与匹配逻辑#
mysql_query_rules常用字段如下:
- rule_id:规则标识,通常与active配合管理规则启停。
- active:是否启用规则,0为禁用,1为启用。
- match_digest:基于SQL规范化后的指纹匹配,适合稳定语句。
- match_pattern:基于正则匹配原始SQL文本,灵活但性能较差。
- flagIN/flagOUT:规则标记传递与串联匹配。
- destination_hostgroup:命中后路由到的目标hostgroup。
- apply:是否终止后续规则匹配,1为终止,0为继续。
- priority:规则优先级,数值越小优先级越高。
匹配顺序由priority决定,若优先级相同则按rule_id排序。命中后若apply=1,立即停止匹配并执行路由;若apply=0,则继续向后匹配,可用于打标或多阶段规则。
priority与规则设计原则#
合理的优先级设计可避免误路由与性能损耗:
1. 高优先级处理例外:如强制主库写、事务内查询、特定表写入等应优先匹配。
2. 中优先级处理通用规则:如SELECT走从库、INSERT/UPDATE/DELETE走主库。
3. 低优先级作为兜底:未匹配规则的SQL统一路由到默认hostgroup。
推荐将priority分区:10–99用于特殊规则,100–199用于常规读写规则,900+用于兜底规则。
match_digest与match_pattern的取舍#
match_digest:基于规范化SQL指纹,稳定且性能好,适合通用规则。match_pattern:基于正则,适合匹配特殊场景,但性能开销更高。
建议优先使用match_digest,仅在规则需要识别具体文本时使用match_pattern。
完整示例:规则配置、加载与验证#
以下示例假设主库hostgroup=10,从库hostgroup=20,默认hostgroup=10。
1)安装与登录(用于执行规则)#
# Debian/Ubuntu
sudo apt-get install -y proxysql
# CentOS/RHEL
sudo yum install -y proxysql
# 登录到ProxySQL管理端(默认端口6032)
mysql -u admin -padmin -h 127.0.0.1 -P6032
命令解释:
mysql -u admin -padmin -h 127.0.0.1 -P6032 用于连接ProxySQL管理接口,执行规则与运行时加载。
2)插入规则(示例含优先级与flag传递)#
-- 清理旧规则(谨慎使用)
DELETE FROM mysql_query_rules;
-- 事务开始打标,flagOUT=1,apply=0 继续匹配
INSERT INTO mysql_query_rules
(rule_id, active, match_pattern, flagOUT, apply, priority)
VALUES
(10, 1, '^BEGIN|^START TRANSACTION', 1, 0, 10);
-- 事务内所有SQL强制主库(flagIN=1)
INSERT INTO mysql_query_rules
(rule_id, active, flagIN, destination_hostgroup, apply, priority)
VALUES
(11, 1, 1, 10, 1, 20);
-- 特定表强制主库(高优先级)
INSERT INTO mysql_query_rules
(rule_id, active, match_digest, destination_hostgroup, apply, priority)
VALUES
(20, 1, '^SELECT .* FROM order_detail', 10, 1, 30);
-- 写请求走主库(中优先级)
INSERT INTO mysql_query_rules
(rule_id, active, match_digest, destination_hostgroup, apply, priority)
VALUES
(100, 1, '^(INSERT|UPDATE|DELETE)', 10, 1, 100);
-- 读请求走从库(中优先级)
INSERT INTO mysql_query_rules
(rule_id, active, match_digest, destination_hostgroup, apply, priority)
VALUES
(110, 1, '^SELECT', 20, 1, 120);
-- 兜底规则(低优先级)
INSERT INTO mysql_query_rules
(rule_id, active, destination_hostgroup, apply, priority)
VALUES
(900, 1, 10, 1, 900);
命令解释:
- flagOUT=1 将事务打标;flagIN=1 命中事务内SQL。
- apply=1 表示命中后停止匹配;priority越小越先匹配。
3)加载与保存#
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
命令解释:
- LOAD ... TO RUNTIME 让规则立即生效
- SAVE ... TO DISK 持久化规则,重启不丢失
4)验证与预期效果#
-- 查看运行时规则
SELECT rule_id, priority, active, match_digest, match_pattern,
flagIN, flagOUT, destination_hostgroup, apply
FROM runtime_mysql_query_rules
ORDER BY priority, rule_id;
-- 观察规则命中次数
SELECT rule_id, hits, last_match
FROM stats_mysql_query_rules
ORDER BY hits DESC;
-- 观察SQL指纹与路由统计
SELECT hostgroup, digest_text, count_star
FROM stats_mysql_query_digest
ORDER BY count_star DESC
LIMIT 5;
预期效果:
- 事务内查询路由到hostgroup=10
- 普通SELECT路由到hostgroup=20
- INSERT/UPDATE/DELETE路由到hostgroup=10
排错清单(常见问题与定位命令)#
- 规则不生效:是否忘记
LOAD MYSQL QUERY RULES TO RUNTIME - 优先级错乱:检查
priority与rule_id排序 - 规则命中为0:验证
match_digest是否与实际指纹一致 - 误路由到默认hostgroup:检查是否缺少兜底规则
定位命令:
-- 查看SQL规范化指纹与原始SQL
SELECT digest_text, query
FROM stats_mysql_query_digest
ORDER BY count_star DESC
LIMIT 5;
-- 查看当前连接的hostgroup
SELECT hostgroup, srv_host, srv_port, status
FROM stats_mysql_connection_pool;
练习#
- 将
SELECT * FROM user_profile强制路由到主库(priority=40),验证是否优先于通用SELECT规则。 - 使用
flagIN/flagOUT实现“事务内全部走主库”,并观察stats_mysql_query_rules的命中次数变化。 - 设计一条兜底规则,将未匹配SQL路由到hostgroup=10,观察命中统计。