ProxySQL 支持链式路由规则,具体来说是,匹配完一条规则后,再接着匹配指定的其它规则。链式路由指定方式是通过mysql_query_rules表中的两个字段来实现的:flagOUT, flagIN,官方的解释很绕,看了几遍,模模糊糊不能明了,也许是语言方面的障碍吧:

lagIN, flagOUT, apply - these allow us to create “chain of rules” that get applied one after the other. An input flag value is set to 0, and only rules with flagIN=0 are considered at the beginning. When a matching rule is found for a specific query, flagOUT is evaluated and if NOT NULL the query will be flagged with the specified flag in flagOUT. If flagOUT differs from flagIN , the query will exit the current chain and enters a new chain of rules having flagIN as the new input flag. If flagOUT matches flagIN, the query will be re-evaluate again against the first rule with said flagIN. This happens until there are no more matching rules, or apply is set to 1 (which means this is the last rule to be applied)

经过一番测试,发现也不难理解,用通俗的汉语解释一下:

flagIN 指定匹配入口,即一条规则得到匹配后,如果flagOUT不为NULL,且apply不等于1, 则根据flagOUT的值,在后续的规则中查找flagIN与之相等的规则进行匹配。

  • 如果一条规则flagIN=0(默认),则任意请求都要匹配这条规则,它是一级路由规则;
  • 如果一条规则flagIN=xx, 则只有flagOUT=xx的规则得到成功匹配后,才会匹配这条规则,它属于次级路由规则。

ProxySQL对某条SQL进行匹配时,是按照mysql_query_rule.rule_id,从小到大,依次取每条规则进行匹配,直到匹配成功,并且该规则的apply=1就不再匹配剩余的规则了!

要想理解这一特性还是要通过测试,简单举个列子。下面插入了一条规则,用于屏蔽select, 但不想屏蔽所有的select, 因此指定flagIN=100。(proxysql 中可以通过指定路由规则的error_msg来屏蔽某条SQL)

1
insert into mysql_query_rules(rule_id,match_digest,flagIN,error_msg,apply)values(19,'^select',100,'You can not select this',1);

接下来我们再插入一条规则,指定其flagOUT=100

1
insert into mysql_query_rules(rule_id,match_pattern,flagOUT,apply)values(18,'select \* from sbtest1 limit 5$',100,0);

这条规则匹配到SQL :select from sbtest1 limit 5, 就会进入匹配flagIN=100的规则,也就是上面我们定义的那一条,那一条规则会屏蔽执行这一SQL。这条规则执行完并不应用(apply=0),这很关键。如果apply=1就不再找其余的规则了,而是立马就应用,然后退出匹配链。这两条规则结合起来就是屏蔽SQL select from sbtest1 limit 5。 当然如果你想屏蔽其它select SQL,还可以继续插入规则,指定flagOUT=100。

ProxySQL的大部分功能都是通过mysql_query_rules表来实现,这个表现在已经有许多字段了,而且有些字段在官方文档中并没有解释。如果你仔细看,你会发现还有一个next_query_flagIN字段,这是个什么鬼?

搜索了下issue,发现它是专门为特定场景实现的。比如你想再某条规定的规则得到匹配后,该session所发送的下一条SQL指定规则匹配。这使得解释起来很绕,我觉得这种场景应该很少,在pull825中作者的解释也很费劲。对于klinometr 所提的问题,使用mysql_users.transaction_persistent可以实现啊?
有兴趣可以详细研读一下!

参考:
https://github.com/sysown/proxysql/pull/825