1.关于ProxySQL路由的简述
当ProxySQL收到前端app发送的SQL语句后,它需要将这个SQL语句(或者重写后的SQL语句)发送给后端的MySQL Server,然后收到SQL语句的MySQL Server执行查询,并将查询结果返回给ProxySQL,再由ProxySQL将结果返回给客户端(如果设置了查询缓存,则先缓存查询结果)。
ProxySQL可以实现多种方式的路由:基于ip/port、username、schema、SQL语句。其中基于SQL语句的路由是按照规则进行匹配的,匹配方式有hash高效匹配、正则匹配,还支持更复杂的链式规则匹配。
本文将简单演示基于端口、用户和schema的路由,然后再详细介绍基于SQL语句的路由规则。不过需要说明的是,本文只是入门,为后面ProxySQL的高级路由方法做铺垫。
角色 主机IP server_id 数据状态
Proxysql 192.168.100.21 null 无
Master 192.168.100.22 110 刚安装的全新MySQL实例
Slave1 192.168.100.23 120 刚安装的全新MySQL实例
Slave2 192.168.100.24 130 刚安装的全新MySQL实例
该实验环境已经在前面的文章中搭建好,本文不再赘述一大堆的内容。环境的搭建请参考前面给出的1、2、3。
2.ProxySQL基于端口的路由
我前面写了一篇通过MySQL Router实现MySQL读写分离的文章,MySQL Router实现读写分离的方式就是通过监听不同端口实现的:一个端口负责读操作,一个端口负责写操作。这样的路由逻辑非常简单,配置起来也很方便。
虽然基于端口实现读写分离配置起来非常简单,但是缺点也很明显:必须在前端app的代码中指定端口号码。这意味着MySQL的一部分流量权限被开发人员掌控了,换句话说,DBA无法全局控制MySQL的流量。此外,修改端口号时,app的代码也必须做出相应的修改。
虽说有缺点,但为了我这个ProxySQL系列文章的完整性,本文还是要简单演示ProxySQL如何基于端口实现读写分离。
首先修改ProxySQL监听SQL流量的端口号,让其监听在不同端口上。
admin> set mysql-interfaces=‘0.0.0.0:6033;0.0.0.0:6034’;
admin> save mysql variables to disk;
然后重启ProxySQL。
[root@xuexi ~]# service proxysql stop
[root@xuexi ~]# service proxysql start
[root@xuexi ~]# netstat -tnlp | grep proxysql
tcp 0 0 0.0.0.0:6032 0.0.0.0:* LISTEN 27572/proxysql
tcp 0 0 0.0.0.0:6033 0.0.0.0:* LISTEN 27572/proxysql
tcp 0 0 0.0.0.0:6034 0.0.0.0:* LISTEN 27572/proxysql
监听到不同端口,再去修改mysql_query_rules表。这个表是ProxySQL的路由规则定制表,后文会非常详细地解释该表。
例如,插入两条规则,分别监听在6033端口和6034端口,6033端口对应的hostgroup_id=10是负责写的组,6034对应的hostgroup_id=20是负责读的组。
insert into mysql_query_rules(rule_id,active,proxy_port,destination_hostgroup,apply)
values(1,1,6033,10,1), (2,1,6034,20,1);
load mysql query rules to runtime;
save mysql query rules to disk;
这样就配置结束了,是否很简单?
其实除了基于端口进行分离,还可以基于监听地址(修改字段proxy_addr即可),甚至可以基于客户端地址(修改字段client_addr字段即可,该用法可用于采集数据、数据分析等)。
无论哪种路由方式,其实都是在修改mysql_query_rules表,所以下面先解释下这个表。
3.mysql_query_rules表
可以通过show create table mysql_query_rules语句查看定义该表的语句。
下面是我整理出来的字段属性。
COLUMN | TYPE | NULL? | DEFAULT |
---|---|---|---|
rule_id (pk) | INTEGER | NOT NULL | |
active | INT | NOT NULL | 0 |
username | VARCHAR | ||
schemaname | VARCHAR | ||
flagIN | INT | NOT NULL | 0 |
client_addr | VARCHAR | ||
proxy_addr | VARCHAR | ||
proxy_port | INT | ||
digest | VARCHAR | ||
match_digest | VARCHAR | ||
match_pattern | VARCHAR | ||
negate_match_pattern | INT | NOT NULL | 0 |
re_modifiers | VARCHAR | ‘CASELESS’ | |
flagOUT | INT | ||
replace_pattern | VARCHAR | ||
destination_hostgroup | INT | NULL | |
cache_ttl | INT | ||
reconnect | INT | NULL | |
timeout | INT | ||
retries | INT | ||
delay | INT | ||
mirror_flagOU | INT | ||
mirror_hostgroup | INT | ||
error_msg | VARCHAR | ||
sticky_conn | INT | ||
multiplex | INT | ||
log | INT | ||
apply | INT | NOT NULL | 0 |
comment | VARCHAR |
各个字段的意义如下:有些字段不理解也无所谓,后面会分析一部分比较重要的。
rule_id:规则的id。规则是按照rule_id的顺序进行处理的。
active:只有该字段值为1的规则才会加载到runtime数据结构,所以只有这些规则才会被查询处理模块处理。
username:用户名筛选,当设置为非NULL值时,只有匹配的用户建立的连接发出的查询才会被匹配。
schemaname:schema筛选,当设置为非NULL值时,只有当连接使用schemaname作为默