Skip to content

规则过滤与重写

Jesse edited this page Aug 31, 2020 · 2 revisions

介绍

Arkproxy支持对所执行的SQL语句的过滤,改写,拦截以及匹配等功能。也可以通过这个功能来做路由定制,比如指定分发到从节点,还是主节点。也可以通过这个功能,来指定要不要将被执行的语句记录日志,最有用的功能是可以设置相应语句执行的最长时间,如果超过这个时间了,就自动将其杀掉。

规则过滤功能,需要依赖Trace的缓存,因为需要通过Trace模块来生成digest,并且依赖它来做日志。但要求仅限于不要主动地通过 config trace cache close 来将其关闭即可,如果已经关闭,则通过命令 config trace cache create创建即可。这里依赖的是Trace缓存空间,与proxy_digest_trace无关。在Arkproxy启动的时候,会默认创建digest缓存空间,而创建SQL缓存空间是需要参数proxy_sql_trace是打开状态的。

Arkproxy的配置包括用户、规则都存储在proxy_namespace参数所指定的数据库中,可以通过参数proxy_config_host、proxy_config_passwd、proxy_config_port、proxy_config_user来配置这个数据库创建在什么地方。如果不配置的话,默认存储到Arkproxy后端主库的mysql库中。针对rule的存储,对应的表是proxy_rules,表结构如下:

CREATE TABLE `proxy_rules` ( 
`rule_id` int(11) NOT NULL AUTO_INCREMENT, 
`active` int(11) NOT NULL DEFAULT '0', 
`username` varchar(256) DEFAULT NULL, 
`schemaname` varchar(256) DEFAULT NULL,`client_addr` varchar(256) DEFAULT NULL, 
`proxy_addr` varchar(256) DEFAULT NULL, 
`proxy_port` int(11) DEFAULT NULL, 
`digest` varchar(256) DEFAULT NULL, 
`match_digest` text, 
`match_pattern` text, 
`negate_match_pattern` int(11) NOT NULL DEFAULT '0', 
`re_modifiers` varchar(256) DEFAULT 'CASELESS', 
`replace_pattern` text, 
`destination` varchar(256) DEFAULT NULL, 
`timeout` int(10) unsigned DEFAULT NULL, 
`error_msg` varchar(1024) DEFAULT NULL, 
`log` int(11) DEFAULT NULL, 
`comment` text, 
PRIMARY KEY (`rule_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='rule config table' 

各字段含义如下:

Column 说明
rule_id 表示规则ID,唯一,主键,以这个值从小到大的规则来匹配,匹配到一个之后,不会再继续做匹配了。
active 表示当前规则是不是开启状态,只有为1的时候,才会去匹配这个规则,默认为0
username 用来匹配一个客户端连接的用户名
schemaname 用来匹配客户端在主动显式地设置为use db之后,所指定的库名
client_addr 用来匹配客户端连接的来源IP,这里只匹配IP,而不会匹配域名,支持通配符%
proxy_addr 用来匹配当前连接访问的 Arkproxy 地址,因为 Arkproxy 可以配置多套,但规则只有一套,所以需要匹配到具体哪一个中间层。这里只匹配IP,不会匹配域名,支持通配符%
proxy_port 与上面的 proxy_addr 对应,用来匹配中间层服务的端口
digest 用来匹配一个HASH值,这个值是通过被访问的数据库,用户名及SQL语句对应的 digest text 算出来的,这个值需要从 query_digest 表中的digest字段来获取。
match_digest 用来匹配当前访问的SQL语句的,不过这个语句是被参数化的,也就是说常量需要写为?,而不是原本的值。匹配都是正则匹配,该值为字符串
match_pattern 用来匹配当前访问的SQL语句,与上面的match_digest不同,这个匹配的是原本语句,不需要将常量参数化,当然他还会影响到replace_pattern,对于匹配到的match_pattern,会被替换为replace_pattern,这样就实现了改写语句的目标,匹配都是正则匹配,该值为字符串
re_modifiers 有两个值,默认是CASELESS,表示匹配时大小写不敏感。另一个值为GLOBAL,表示在替换时,是全局替换。
replace_pattern 如果当前规则成功被匹配,用来指定被替换的新字符串。
destination 如果当前规则成功被匹配,则这个用来指定当前语句被分发到读节点,还是写节点,所以这个列有两个值,分别是read和write,大小写不区分。
timeout 如果当前规则成功被匹配,这个值用来表示当前语句最多被执行多久,如果超过这个时间值,则自动杀掉。单位为秒。误差在1秒之内
error_msg 如果当前规则成功被匹配,这个列的作用是将当前语句拦截,并且抛一个异常给客户端。ERROR 1148 (42000): The command is intercepted by arkproxy('error_msg')
log 如果当前规则成功被匹配,这个列用来指定,即使参数proxy_digest_trace与proxy_sql_trace未开启,也会被记录下来。存储到表proxy_digest与proxy_sql中

这个表是以rule_id为主键的,每一个rule_id,代表一条规则,并且不能重复,规则匹配是以rule_id为顺序的,从小到大来匹配,如果匹配到一个规则,就不会再继续向后匹配了。

配置rule语法规则如下:

config {add | delete | update} rule rule_options [,rule_options] ... 

rule_options: 
{number_rule_options|text_rule_options|null_rule_options} 

number_rule_options: 
rule_id|active|timeout|log|apply|negate_match_pattern|proxy_port=number 

text_rule_options: 
username | digest | re_modifiers | destination | comment | 
schemaname | error_msg | client_addr | proxy_addr |match_digest |match_pattern = 'string'text_rule_options: 
username | digest | re_modifiers | destination | comment | 
schemaname | error_msg | client_addr | proxy_addr | match_digest|match_pattern = NULL 

通过上面的语法,就可以对rule进行操作了,操作包括三种方式,包括增加、更新、删除,因为proxy_rules表的主键是rule_id,所以在上面语句操作时,必须要指定rule_id,不然会报错。

mysql> config update rule error_msg=NULL; 
ERROR 2084 (HY000): proxy config error: 'rule update config need and not only need rule_id'. 

对于值为string的设置项,如果想要取消,或者将其值清空,则可以通过将其值设置为NULL的方式,来清空。比如:

mysql> config update rule rule_id=1, match_digest='SELECT ?', 
error_msg=NULL; 
mysql> config flush;  

非string类型的属性,直接设置为对应的0或者其它无意义值即可。

设置SQL最大执行时间规则

设置SQL最大执行时间,超过该时间SQL会被kill掉

操作步骤

  1. 设置规则
config add rule rule_id=1, active=1,error_msg=NULL, digest=NULL, 
client_addr='%', proxy_addr='%', proxy_port=15002, 
match_digest='SELECT sleep(?)', match_pattern=NULL, 
negate_match_pattern=0, re_modifiers=NULL, replace_pattern=NULL, 
destination='read', comment ="I'm test", timeout=1, log=1; 
  1. 查看规则状态
show config cache;
  1. 此时的设置还处于线程级别,还没有生效,需要刷新
config flush;
  1. 查看当前生效规则列表
show rule status;
  1. 登录业务端执行SQL
SELECT sleep(10);

本来是要执行100秒的,结果在1.35秒就返回了,说明已经被Arkproxy的规则杀掉了。0.35秒属于误差。

mysql> SELECT sleep(10);
+-----------+
| sleep(10) |
+-----------+
|         0 |
+-----------+
1 row in set (1.35 sec)

设置SQL改写规则

匹配规则的SQL会按照规则改写

操作步骤

  1. 设置规则
config add rule rule_id=2, active=1,error_msg=NULL, digest=NULL, 
client_addr='%', proxy_addr='%', proxy_port=15002, 
match_digest='SELECT ?', match_pattern='10', 
negate_match_pattern=0, re_modifiers=NULL, replace_pattern='10000', 
destination='read', comment ="SQL rewrite", log=1;  
  1. 查看规则状态
show config cache;
  1. 此时的设置还处于线程级别,还没有生效,需要刷新
config flush;
  1. 查看当前生效规则列表
show rule status;
  1. 登录业务端执行SQL
SELECT 10;

SELECT 10 被改写为SELECT 10000;

mysql> SELECT 10;
+-------+
| 10000 |
+-------+
| 10000 |
+-------+
1 row in set (0.00 sec)

设置SQL拦截规则

匹配规则的SQL会拦截,不会执行

操作步骤

  1. 设置规则
config add rule rule_id=3, active=1,error_msg="DROP TABLE is dangerous!!!", digest=NULL, 
client_addr='%', proxy_addr='%', proxy_port=15002, 
match_digest='DROP TABLE ?', re_modifiers=NULL, replace_pattern=NULL, 
destination='write', comment ="SQL reject", log=1;  
  1. 查看规则状态
show config cache;
  1. 此时的设置还处于线程级别,还没有生效,需要刷新
config flush;
  1. 查看当前生效规则列表
show rule status;
  1. 登录业务端执行SQL
DROP TABLE arkproxy_test1.ts;

结果如下:

mysql> DROP TABLE arkproxy_test1.ts;
ERROR 1148 (42000): The command is intercepted by arkproxy('DROP TABLE is dangerous!!!')
mysql>
Clone this wiki locally