proxysql基础实践
【0】环境与架构
IP | server-id | db-version | description |
192.168.148.39 | 393306 | 8.0.20 | Master(gtid)、ProxySQL |
192.168.148.27 | 273306 | 8.0.22 | Slave(gtid) |
192.168.148.30 | 1483306 | 8.0.22 | Slave(gtid) |
【1】基本安装
默认配置文件在 /etc/proxysql.cnf ,默认端口 6033、6032(是管理员端口)
ProxySQL 的用户名和密码都是默认的 admin
(1.1)下载安装
参考:https://proxysql.com/documentation/installing-proxysql/
yum:
cat <<EOF | tee /etc/yum.repos.d/proxysql.repo [proxysql_repo] name= ProxySQL YUM repository baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.2.x/centos/$releasever gpgcheck=1 gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key EOF
yum install -y proxysql OR yum install proxysql-version
# 注意这里如有报错,yum源信息请到官网去复制
# 然后 yum clean all , yum makecache
# 最终再次执行该语句
rpm:
# 1.安装proxysql安装依赖包
wget https://github.com/sysown/proxysql/releases/download/v2.2.0/proxysql-2.2.0-1-centos7.aarch64.rpm yum install perl-DBD-MySQL -y rpm -ivh proxysql-2.2.0-1-centos7.aarch64.rpm
# 2.启动 proxysql
rpm -ql proxysql
systemctl start proxysql.service
(1.2)启停与登录
默认配置文件在 /etc/proxysql.cnf ,默认端口 6033、6032(是管理员端口,所有管理配置都是连接该端口)
service proxysql start service proxysql stop service proxysql restart # 也可以使用 systemctl
# 登录, --prompt 只是加个显示前缀而已
mysql -uadmin -padmin -P6032 --prompt='\u@mysqldb \R:\m:\s [\d]>'
# 登陆后启停管理proxysql stop
proxysql restart
注意:如果您的 MySQL 客户端版本是 8.04 或更高版本,请添加--default-auth=mysql_native_password
上述命令以连接到管理界面
ProxySQL 的用户名和密码都是默认的 admin,但该账户只能本机登录;
select @@admin-admin_credentials; # 当前用户名和密码 set admin-admin_credentials='admin:admin;myuser:myuser'; # 添加myuser用户 load admin variables to runtime; # 使修改立即生效 save admin variables to disk; # 使修改永久保存到磁盘
(1.3)查看数据库列表与存储位置
如上图我们可以看到数据目录默认是:/var/lib/proxysql/
(1.4)配置文件初步了解
最顶部部分:
-
admin_variables
: 包含控制管理界面功能的全局变量。 -
mysql_variables
: 包含控制处理传入 MySQL 流量的功能的全局变量。
mysql_servers
:包含mysql_servers
来自管理界面的表的行。
基本上,这些定义了传入的 MySQL 流量被路由到的后端服务器。
行根据.cfg
文件格式进行编码,这是一个示例:
mysql_users
:包含mysql_users
来自管理界面的表的行。基本上,这些定义了可以连接到代理的用户,以及代理可以连接到后端服务器的用户。
根据.cfg
文件格式进行编码,这是一个示例:
mysql_query_rules
:包含mysql_query_rules
来自管理界面的表的行。
基本上,这些定义了用于根据各种标准(匹配的模式、用于运行查询的用户等)对传入的 MySQL 流量进行分类和路由的规则。
行是按照.cfg
文件格式编码的,
这里是一个例子(注意:这个例子是一个非常通用的查询路由规则,建议为查询创建特定的规则,而不是使用这样的通用规则):
【额外】重新初始化、重新加载
# If you are using the init script run: /etc/init.d/proxysql initial # or service proxysql initial # If you are using the systemd unit file run: systemctl start proxysql-initial # or service proxysql-initial start
如果使用该标志执行 ProxySQL 二进制文件--reload
,它会尝试将配置文件中的配置与数据库文件的内容合并。此后,它将使用新合并的配置启动。
无法保证 ProxySQL 在发生冲突时成功合并两个配置源,用户应始终验证合并是否按预期执行。
【2】ProxySQL 内部原理
(2.1)ProxySQL 的多层配置系统
配置结构如下:
参考:https:
//github.com/sysown/proxysql/wiki/Configuring-ProxySQL
整套配置系统分为三层:顶层为 RUNTIME ,中间层为 MEMORY , 底层也就是持久层 DISK 和 CONFIG FILE 。
RUNTIME : 代表 ProxySQL 当前生效的正在使用的配置,无法直接修改这里的配置,必须要从下一层 “load” 进来。
MEMORY: MEMORY 层上面连接 RUNTIME 层,下面连接持久层。这层可以正常操作 ProxySQL 配置,随便修改,不会影响生产环境。
修改一个配置一般都是现在 MEMORY 层完成的,确认正常之后在加载达到 RUNTIME 和 持久化的磁盘上。
DISK 和 CONFIG FILE:持久化配置信息,重启后内存中的配置信息会丢失,所需要将配置信息保留在磁盘中。重启时,可以从磁盘快速加载回来。
层与层之间的移动:
以下命令语法可用于在各个层之间移动 ProxySQL 配置,<item> 是您希望配置的配置项的占位符: [1] `LOAD <item> FROM MEMORY`/`LOAD <item> TO RUNTIME` 将配置项从内存数据库加载到运行时数据结构 [2] `SAVE <item> TO MEMORY` / `SAVE <item> FROM RUNTIME` 将配置项从运行时保存到内存数据库 [3] `LOAD <item> TO MEMORY`/`LOAD <item> FROM DISK` 将持久化的配置项从磁盘数据库加载到内存数据库 [4] `从内存中保存 <item>`/`SAVE <item> 到磁盘` 将配置项从内存数据库保存到磁盘数据库 [5] `从配置中加载 <项目>` 将配置文件中的配置项加载到内存数据库中
(2.2)库表与层级对应关系
各个数据库的作用:
main: 内存配置数据库,即 MEMORY/RUNTIME,表里存放后端 db 实例、用户验证、路由规则等信息。
disk :持久化的磁盘的配置
stats: 统计信息的汇总
monitor:一些监控的收集信息,比如数据库的健康状态等
stats_history: 这个库是 ProxySQL 收集的有关其内部功能的历史指标
如下图:
库下的主要表:
-
mysql_servers
: 后端可以连接 MySQL 服务器的列表 -
mysql_users
: 配置后端数据库的账号和监控的账号。 -
mysql_query_rules
: 指定 Query 路由到后端不同服务器的规则列表。
注: 表名以 runtime_ 开头的表示 ProxySQL 当前 RUNTIME 的配置内容,不能通过 DML 语句修改。
只能修改对应的不以 runtime 开头的表,然后 “LOAD” 使其生效,“SAVE” 使其存到硬盘以供下次重启加载。
层级对应相关库表如下:
一般在内存那层修改 ,然后保存到运行系统,保存到磁盘数据库系统
load xxx to runtime;
save xxx to disk;
(2.3)持久化与配置文件的关系
disk and config file 持久化配置文件
disk -> 是sqlite3 数据库 ,默认位置是$DATADIR/proxysql.db( /var/lib/proxysql/proxysql.db) config file 是一个传统配置文件:一般不更改
- 在内存中动态更改配置,如果重启,没进行持久化(save) 则会丢失。
三则之间关系:
-
proxysql 启动时,首先去找/etc/proxysql.cnf 找到它的datadir,如果datadir下有proxysql.db 就加载proxysql.db的配置
-
如果启动proxysql时带有
--init
标志,会用/etc/proxsql.cnf的配置,把Runtime,disk全部情况重新初始化一下 -
在调用是调用
--reload
会把/etc/proxysql.cnf 和disk 中配置进行合并。如果冲突需要用户干预。disk会覆盖config file。
关于传统的配置文件
传统配置文件默认路径为/etc/proxysql.cnf,也可以在二进制程序proxysql上使用 -c 或 –config 来手动指定配置文件。
默认情况下:几乎不需要手动去配置proxysql.cnf。端口号,管理proxysql用户密码,可以在登录上 ProxySQL 管理员模式 后修改
【3】我的实践
(3.0)前提条件 与 核心表
从库必须 read_only=1;
ProxySQL 会识别该参数,该参数=1时 为读实例,为0时,为写库;也会因此做相应的路由决策;
核心表:流程可以也按这个来
- mysql_servers:服务器注册
- global_variables:全局变量,mysql-monitor_username,mysql-monitor_password
- mysql_users:提供登录 proxysql 的账户密码(同时也要有权限访问对于的 mysql 实例)
- mysql_replication_hostgroups:复制服务器分组,会自动根据 服务器对于mysql实例的 readonly标识,把 =0的归到写组,=1 的归到读组
- mysql_quer_rules:路由规则
(3.1)准备 ProxySQL 监控/连接账户
注意:8.0+版本 要以 mysql_native_password 形式创建
如: create user test@'%' identified with mysql_native_password by '123456';
或配置文件中已经配置:
[mysqld]
default_authentication_plugin=mysql_native_password
我的配置文件中就已经配置过默认的加密方式,所以我的账户建立语句如下:
在 mysql 主库上运行
-- proxysql 的监控账户 create user 'monitor'@'192.168.148.%' identified by '123456'; grant all privileges on *.* to 'monitor'@'192.168.148.%' with grant option; -- proxysql 的对外访问账户 create user 'proxysql'@'192.168.148.%' identified by '123456'; grant all privileges on *.* to 'proxysql'@'192.168.148.%' with grant option; flush privileges;
(3.2)机器注册=》mysql_servers
把我们3个机器的信息都插入到该表(内存层)中去;
我们 use main; show create table mysql_servers; 看看表结构
--------------------------------------------------------------------------------------------------------------------------------------------------------+ | mysql_servers | CREATE TABLE mysql_servers ( hostgroup_id INT CHECK (hostgroup_id>=0) NOT NULL DEFAULT 0, hostname VARCHAR NOT NULL, port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 3306, gtid_port INT CHECK ((gtid_port <> port OR gtid_port=0) AND gtid_port >= 0 AND gtid_port <= 65535) NOT NULL DEFAULT 0, status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE', weight INT CHECK (weight >= 0 AND weight <=10000000) NOT NULL DEFAULT 1, compression INT CHECK (compression IN(0,1)) NOT NULL DEFAULT 0, max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000, max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0, use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0, max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0, comment VARCHAR NOT NULL DEFAULT '', PRIMARY KEY (hostgroup_id, hostname, port) ) |
然后插入我们自己的ip信息即可;
use main; INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'192.168.148.39',3306); INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'192.168.148.27',3306); INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'192.168.148.30',3306); select * from mysql_servers;load mysql servers to runtime;
save mysql servers to disk;
-- 规范 应该把 comment 列也写上
效果如下:
(3.4)ProxySQL 监控 MySQL 节点配置=》global_variables
(1)配置监控账户与参数
(3.1)中我们已经在mysql主库建立起 监控账户 monitor,现在要用 ProxySQL来应用;
-- 方法1 set mysql-monitor_username='monitor'; set mysql-monitor_password='123456';
set mysql-monitor_enabled='true'; -- 方法2
use main; UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username'; UPDATE global_variables SET variable_value='123456' WHERE variable_name='mysql-monitor_password'; -- 修改后,保存到runtime和disk load mysql variables to runtime; save mysql variables to disk; -- 查看监控日志 select * from monitor.mysql_server_connect_log;
然后我们还可以配置各种监控间隔:
SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-monitor_%';
如下图,这里的连接间隔就是60s 我们可以把相关参数改大点
UPDATE global_variables SET variable_value='2000'
WHERE variable_name IN ('mysql-monitor_connect_interval','mysql-monitor_ping_interval','mysql-monitor_read_only_interval');
load mysql variables to runtime;
save mysql variables to disk;
(2) 后端的监控检查
SHOW TABLES FROM monitor;
这里要注意的一件重要的事情是;
甚至在将其加载到 RUNTIME 之前connect
,ping
监控都是基于配置完成的。
mysql_servers
这种方法是有意的:通过这种方式,可以在生产中添加节点之前执行基本的健康检查。
可以在验证服务器被正确监控并且运行良好后,再激活配置(load mysql servers to runtime;)
(3.5)mysql复制主机组=》mysql_replication_hostgroups
show create table mysql_replication_hostgroups ,查看表
| mysql_replication_hostgroups | CREATE TABLE mysql_replication_hostgroups ( writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY, reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>=0), check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only','innodb_read_only','super_read_only','read_only|innodb_read_only','read_only&innodb_read_only')) NOT NULL DEFAULT 'read_only', comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup)) |
集群拓扑更改基于 ProxySQL 中配置的 MySQL 复制主机组进行监控。
ProxySQL 通过监控read_only
配置在主机组中的服务器上的值来理解复制拓扑 mysql_replication_hostgroups
。
且, writer_hostgroup
和reader_hostgroup
写组和读组都要大于0且不能相同,我的环境下,写组定义与10,读组定义为20
此表默认为空,应通过指定一对 READER 和 WRITER 主机组进行配置,如:
insert into mysql_replication_hostgroups ( writer_hostgroup, reader_hostgroup, comment) values (10,20,'proxy'); load mysql servers to runtime; save mysql servers to disk;
那么,一个叫 proxy 的组就形成了;
我们可以通过下面语句来确认 3 层结构是否都写入了
select * from main.runtime_mysql_replication_hostgroups; -- 运行时 select * from main.mysql_replication_hostgroups; -- 内存 select * from mysql_replication_hostgroups; -- 存储
现在,在主机组 10 或 20 中配置的所有 MySQL 后端服务器都将根据它们的 read_only 值放入各自的主机组中:
- 如果有
read_only=0
,它们将被移到主机组 10 - 如果有
read_only=1
,他们将被移到主机组 20
如下图:之前本来都是10的,后面从库(read_only=1)自动变成20了
查看情况,select * from mysql_server_read_only_log limit 10;
证明成功了啊(这个应用要做了 monitor 才能看噢 )
(3.6)ProxySQL对外登录账户=》mysql_user
该表最初是空的,(我们这里插入的 proxysql 账户,是在3.1中创建过的)
INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('root','',10); INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('proxysql','123456',10);load mysql users to runtime;
save mysql users to disk;
admin@127.0.0.1 [admin]>select * from mysql_users\G *************************** 1. row *************************** username: proxysql password: 123456 active: 1 #是否启用该账户,为0表示禁用 use_ssl: 0 default_hostgroup: 10 default_schema: NULL schema_locked: 0 transaction_persistent: 1 #事务透明化 fast_forward: 0 backend: 1 frontend: 1 max_connections: 10000 #用户链接10000,可以修改
mysql_users 表有不少字段,最主要的三个字段username,password,default_hostgroup
username: 前端链接ProxySQL ,以及ProxySQL 将SQL 语句路由给MySQL所使用的的用户名
password:用户名对应的密码,可以是明文密码,也可以是hash密码。如果想使用hash密码,可以先在某个MySQL节点上执行 select password(PASSWORD)
,然后将加密结果复制到该字段。
(1.2.3版本后)默认admin-hash_passwords=true,所以在 runtime_mysql_users 里面会记录的是 hash 密码;但 memory中依然还是记录的是明文,可以 load mysql user from runtime;
default_hostgroup:该用户名默认的路由目标。例如,指定root用户的该字段值为10时,则使用 proxysql 用户发送的SQL语句默认情况下将路由到hostgroup_id=10 组中的某个节点。
一旦事务启动,有可能一些查询会根据查询规则发送到不同的主机组。为了防止这种情况发生,可以启用 transaction_persistent 字段,默认为 true;
我这里 hostgroup_id = 10的组中只有一个节点就是 (mysql_server表中的)master : 192.168.148.39
mysql -uproxysql -p123456 -P6033 -h 192.168.148.39
(3.7)读写分离路由规则=》mysql_query_rules
配置读写分离,就是配置ProxySQL 路由规则,ProxySQL 的路由规则非常灵活,可以基于用户,基于schema,以及单个sql语句实现路由规则定制。
和查询规则有关的表有两个:mysql_query_rules
和 mysql_query_rules_fast_routing
表 mysql_query_rules_fast_routing 是 mysql_query_rules 的扩展,并在以后评估快速路由策略和属性(仅在ProxySQL 1.4.7+中可用)。
介绍一下改表mysql_query_rules的几个字段:
-
rule_id:该表的序列号,会已该顺序匹配读取行,如果 id 更小的已经匹配到,就不继续往下匹配规则了
-
active
:是否启用这个规则,1表示启用,0表示禁用
-
match_pattern:
字段就是代表设置规则
-
destination_hostgroup:
字段代表默认指定的分组
-
apply:
代表比如应用了这个规则,则后面的规则就不必看了 -
weight:权重,比如让某台机器承受更多的请求分配
简单案例:
ProxySQL Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (1,1,'stnduser','^SELECT c FROM sbtest1 WHERE id=\?$',20,1); Query OK, 1 row affected (0.00 sec) ProxySQL Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (2,1,'stnduser','DISTINCT c FROM sbtest1',20,1); Query OK, 1 row affected (0.00 sec)
核心规则要点:
- 查询规则按顺序处理
rule_id
- 仅处理已
active=1
处理的规则 - 第一个规则示例使用插入符号 (
^
) 和美元 ($
) :这些是特殊的正则表达式字符,用于标记模式的开始和结束,即在这种情况下match_digest
或match_pattern
应该完全匹配查询 - 示例中的第二条规则不使用插入符号或美元:匹配可以在查询中的任何位置
- 问号被转义,因为它在正则表达式中具有特殊含义
apply=1
表示如果当前规则匹配,则不应评估进一步的规则
(1)创建路由规则
注意:我这只是试验,只是配置了几个简单的路由规则,实际情况配置路由规则;
不应该是就根据所谓的读、写操作来进行读写分离,而是从收集(慢日志)的各项指标找出压力大,执行频繁的语句单独写规则,做缓存等等。
比如 先在测试几个核心sql语句,分析性能提升的百分比,在逐渐慢慢完善路由规则。
生产中使用读写分离
:建议基于hash code 值做读写分离,不要建太多的规则
查看相关组信息:
这里我创建4个规则:
1、把增删改 insert、delete、update 定位到写组(主库组 10 );我们这里 mysql_server 以及 mysql_replication_hostgroups 表中 主库写入组为10,读组为20;见上图
2、把查询 select 操作定位到 读组(从库组 20 );参考同上
在 proxysql 管理员模式下操作:
-- 写入到主库insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values (1,1,'^select.*for update$',10,1); insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values (2,1,'^select.*LOCK IN SHARE MODE$',10,1); -- 后面这2个 ID 可以相对设置大一点,方便在前面后面插入相关规则(不过也没关系,重新删除掉再在 memory 层设置好,再 load/save 到 runtime 和 disk 也不影响线上) -- 读从库 insert into mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply) values (100,1,'^select',20,1); -- 非规则内的其他操作默认全放到主库,比如其他建库、建表、授权、DDL等等load mysql query rules to runtime; save mysql query rules to disk;
(2)测试读写分离
我们在从库早就已经连接登录到 proxysql的链接,查看看看
(1)中配置可以直接在线生效,而不必重新登录连接;
-- 查询负载均衡
-- 写规则
-- 非规则内定义语句,默认就是全放到主库里去了,如下图,我们在主库开了 general_log 后
-- 查看路由请求信息,在proxysql admin 查看,这个也论证了我们上面说的 非mysql_query_rules 里面的规则,其他所有请求默认都是到写组的
select hostgroup,schemaname,username,digest_text,count_star from stats_mysql_query_digest;
(3.8)查询缓存
如下代码,我们把查询组的缓存设置了 缓存5秒
UPDATE mysql_query_rules set cache_ttl=5000 WHERE active=1 AND destination_hostgroup=20;
修改后,我们发现,我们的计数器被重置了
然后我们5秒内重复查询某个操作,-1 的即为缓存命中
(3.9)查询重写
为了匹配查询的文本,ProxySQL 提供了 2 种机制:
-
match_digest
:将正则表达式与去除 SQL 查询数据的查询摘要进行匹配(例如 `SELECT c FROM sbtest1 WHERE id=?- 如
stats_mysql_query_digest.query_digest
- 如
-
`
match_pattern
:将正则表达式与查询的实际文本匹配(例如,`SELECT c FROM sbtest1 WHERE id=2`
摘要总是比查询本身小,对较小的字符串运行正则表达式会更快,建议(出于性能考虑)使用 match_digest
.
要重写查询或匹配查询文本本身,请使用match_pattern
.
例如:
ProxySQL Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_pattern,replace_pattern,apply) VALUES (30,1,'stnduser','DISTINCT(.*)ORDER BY c','DISTINCT\1',1); Query OK, 1 row affected (0.00 sec) ProxySQL Admin> SELECT rule_id, match_digest, match_pattern, replace_pattern, cache_ttl, apply FROM mysql_query_rules ORDER BY rule_id; +---------+-------------------------------------+------------------------+-----------------+-----------+-------+ | rule_id | match_digest | match_pattern | replace_pattern | cache_ttl | apply | +---------+-------------------------------------+------------------------+-----------------+-----------+-------+ | 10 | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL | NULL | 5000 | 1 | | 20 | DISTINCT c FROM sbtest1 | NULL | NULL | 5000 | 1 | | 30 | NULL | DISTINCT(.*)ORDER BY c | DISTINCT\1 | NULL | 1 | +---------+-------------------------------------+------------------------+-----------------+-----------+-------+
此配置将导致
Admin> SELECT hits, mysql_query_rules.rule_id, match_digest, match_pattern, replace_pattern, cache_ttl, apply FROM mysql_query_rules NATURAL JOIN stats.stats_mysql_query_rules ORDER BY mysql_query_rules.rule_id; +-------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+ | hits | rule_id | match_digest | match_pattern | replace_pattern | cache_ttl | apply | +-------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+ | 48560 | 10 | ^SELECT c FROM sbtest1 WHERE id=\? | NULL | NULL | 5000 | 1 | | 4856 | 20 | DISTINCT c FROM sbtest1 | NULL | NULL | 5000 | 0 | | 4856 | 30 | NULL | DISTINCT(.*)ORDER BY c | DISTINCT\1 | NULL | 1 | +-------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+ 3 rows in set (0.01 sec)
(3.10)查询重写 解决禁止操作、不规范操作
禁止操作:
案例1:select * 类语句直接报查询报错
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, error_msg, apply) VALUES (2,1,'^SELECT \* from t1$','Query not allowed',1);
案例2:杜绝删除整表
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, error_msg, apply) VALUES (3,1,'^DELETE FROM t1$','Query not allowed',1);
替换操作:
案例1:delete 变成 select
INSERT INTO mysql_query_rules (rule_id, active, match_pattern,replace_pattern, apply) VALUES (4,1,'^DELETE FROM t1$','select * from test.t1',1);
(3.11)连接池问题
问题1:多线程并发连接建立了之后,20秒后回收(ping/connect/read_only_interval 都是2 秒)
连接池剩下100个;
【4】常用表查阅、监控
(4.1)main 配置表
mysql_servers -- 服务器注册 global_variables -- 全局变量,mysql-monitor_username,mysql-monitor_password mysql_users -- 提供登录 proxysql 的账户密码(同时也要有权限访问对于的 mysql 实例) mysql_replication_hostgroups -- 复制服务器分组,会自动根据 服务器对于mysql实例的 readonly标识,把 =0的归到写组,=1 的归到读组 mysql_quer_rules -- 路由规则
(4.2)monitor 监控日志
mysql_server_connect_log -- 连接日志,频率根据 global_variables 里面配置 mysql_server_galera_log -- 不知道啥日志 mysql_server_group_replication_log -- 复制组日志 mysql_server_ping_log -- ping 日志 mysql_server_read_only_log -- 只读日志 mysql_server_replication_lag_log -- 复制落后日志
(4.3)stats 状态表
admin@mysqldb 17:52:59 [(none)]>show tables from stats; +--------------------------------------+ | tables | +--------------------------------------+ | global_variables | | stats_memory_metrics | | stats_mysql_commands_counters | | stats_mysql_connection_pool | | stats_mysql_connection_pool_reset | | stats_mysql_errors | | stats_mysql_errors_reset | | stats_mysql_free_connections | | stats_mysql_global | | stats_mysql_gtid_executed | | stats_mysql_prepared_statements_info | | stats_mysql_processlist | | stats_mysql_query_digest | | stats_mysql_query_digest_reset | | stats_mysql_query_rules | | stats_mysql_users | | stats_proxysql_servers_checksums | | stats_proxysql_servers_metrics | | stats_proxysql_servers_status | +--------------------------------------+
几个比较常用的如下:
stats_mysql_connection_pool -- 连接池,状态、次数、网络流量、请求次数 stats_mysql_commands_counters -- 语句命令的次数、执行时间等分布 stats_mysql_query_digest -- 路由查询、响应时间、 计数
【5】深入设计思路
(5.1)不同的端口进行读写拆分
如果您使用 MySQL 的标准 TCP 负载均衡器,您通常会将其配置为侦听两个单独的端口。每个端口都充当端点,一个用于写入,另一个用于读取。
使用类似的方法配置 ProxySQL 很常见,特别是在迁移到另一个已经实现这种机制的 TCP 负载均衡器时。在此配置中,查询路由条件是传入端口。
以下是如何在 ProxySQL Admin 中实现基于传入端口的查询路由的示例。
这假设您已经在正确的主机组中配置了主副本和副本:
主机组 1 中的 MySQL 写入器,主机组 2 中的 MySQL 读取器。如果您使用 Galera 或 Group Replication,将适用类似的方法。步骤如下:
将 ProxySQL 配置为侦听两个端口并重新启动它:mysql-interfaces
是在运行时无法更改且需要重新启动的少数变量之一
SET mysql-interfaces='0.0.0.0:6401;0.0.0.0:6402'; ## save it on disk and restart proxysql SAVE MYSQL VARIABLES TO DISK; PROXYSQL RESTART;
-- 根据传入端口添加路由: INSERT INTO mysql_query_rules (rule_id,active,proxy_port,destination_hostgroup,apply) VALUES (1,1,6401,1,1), (2,1,6402,2,1); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK; # if you want this change to be permanent
现在所有到端口 6401 的查询都将发送到主机组 1 中的 MySQL 服务器,而所有到端口 6402 的查询都将发送到主机组 2 中的一台 MySQL 服务器。
建议老老实实使用正则拆分,毕竟一般不会连2个端口
(5.2)如何更好的 配置 mysql_query_rules
更有效地设置读/写拆分的配置过程如下:
-
首先将 ProxySQL 配置为仅将所有流量发送到一个 MySQL 节点,即主节点(写入和读取)
-
分析
stats_mysql_query_digest
以确定最昂贵的SELECT
语句 -
确定这些语句中哪些是安全的以路由读取器节点(即不易受复制延迟的影响,副本硬件适合支持查询等)
-
配置
mysql_query_rules
为在您的副本上选择性地仅路由这些昂贵的语句
根据下列相关语句分析:
-- 根据总执行时间查找前 5 个查询 SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY sum_time DESC LIMIT 5; -- 根据计数查找前 5 个查询 SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY count_star DESC LIMIT 5; -- 根据最大执行时间查找前 5 个查询 SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time,sum_time/count_star avg_time, min_time, max_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY max_time DESC LIMIT 5; -- 按总执行时间排序的前 5 个查询,并且最短执行时间至少为 1 毫秒 SELECT digest,SUBSTR(digest_text,0,20),count_star,sum_time,sum_time/count_star avg_time, min_time, max_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' AND min_time > 1000 ORDER BY sum_time DESC LIMIT 5; -- 按总执行时间排序的前 5 个查询,平均执行时间至少为 1 秒。还显示总执行时间的百分比 SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time,sum_time/count_star avg_time, ROUND(sum_time*100.00/(SELECT SUM(sum_time) FROM stats_mysql_query_digest),3) pct FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' AND sum_time/count_star > 1000000 ORDER BY sum_time DESC LIMIT 5; -- 总执行时间排序的前 5 个查询,平均执行时间至少为 15 毫秒,并显示占总执行时间的百分比 SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time,sum_time/count_star avg_time, ROUND(sum_time*100.00/(SELECT SUM(sum_time) FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%'),3) pct FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' AND sum_time/count_star > 15000 ORDER BY sum_time DESC LIMIT 5;
可以根据 disgest 编号来,也可以老老实实写 match_digest 或者 match_parttern;
-- disgest INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(1,1,'0x38BE36BDFFDBE638',20,1); -- match_digest INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(1,1,'^SELECT COUNT\(\*\)',20,1); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;
(5.3)ProxySQL 中的分片
官网参考:https://proxysql.com/documentation/how-to-setup-proxysql-sharding/
- 基于用户(user)的分片
- 基于模式(schemaname)的分片:
- mysql_users 下配置好 default_schema
- mysql_query_rules 的 default_schema、default_hostgroup 对应
- 基于数据(data)的分片:
- mysql_users 下设置好 default_hostgroup
- mysql_query_rules 中 default_hostgroup 对应,以及 match_digest / match_parttern 做数据匹配
注意事项:仍然需要在您的应用程序中实现一些逻辑以使其“分片友好”
-
——更简单的基于“用户”或“模式”的方法更易于实现和维护
-
——如果您需要“跨分片”连接,则需要此逻辑应用程序的一部分
-
——当实现基于数据的分片时,需要为每个分片添加额外的规则(例如用于 RW 拆分)
-
——分片不限于基于用户、模式或表的分片——这只是三种主要方法
案例:
-- (1)用户分片 INSERT INTO mysql_users (username, password, active, default_hostgroup, comment) VALUES ('accounts', 'shard0_pass', 1, 0, 'Routed to the accounts shard'), ('transactions', 'shard1_pass', 1, 1, 'Routed to the transactions shard'), ('logging', 'shard2_pass', 1, 2, 'Routed to the logging shard'); LOAD MYSQL USERS RULES TO RUNTIME; SAVE MYSQL USERS RULES TO DISK; -- (2)模式分片 INSERT INTO mysql_query_rules (rule_id, active, schemaname, destination_hostgroup, apply) VALUES (1, 1, 'shard_0', 0, 1), (2, 1, 'shard_1', 1, 1), (3, 1, 'shard_2', 2, 1); LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;
(5.4)read_only配置【最佳实践】
建议每个mysql的配置文件里面 都必须添加 read_only;
然后登录进去主库 在线关闭;
否则如果,以后 如果重启了,会引起双主写入的情况,这样 数据就会错乱;
【6】深入配置文件与配置表
(6.1)配置文件的使用场景
默认配置文件位置: /etc/proxysql.cnf
ProxySQL 使用多层配置系统,特别是3 层配置。
在这个特定的架构中,配置文件中的大部分配置仅在初始引导、初始启动或重新加载启动期间被读取和解析。
详情见(2.3)中的说明;
简单而言:99%情况不需要管配置文件,通过Admin管理接口,可以在线修改几乎所有的配置并使其生效。
实在要用还可以 --reload 合并disk与config,如果冲突需要用户干预,一般 disk会覆盖config file
只有两个变量的配置是必须重启ProxySQL才能生效的,它们是:mysql-interfaces
,mysql-thread(默认4线程,就是说无论有多少并发连到proxysql,proxysql本身顶多用4个线程去连接对应的mysql实例)
和 mysql-stacksize
三个参数修改需要重启实例。
(6.2)general variables
-
datadir (string): 定义ProxySQL datadir的路径,存放数据库文件、日志等文件
-
restart_on_missing_heartbeats(int):如果 MySQL 线程错过
restart_on_missing_heartbeats
心跳,ProxySQL 将发出SIGABRT
信号并重新启动。它的默认值为 10 。请参阅看门狗。 -
execute_on_exit_failure (string):如果设置,ProxySQL 父进程将在每次 ProxySQL 崩溃时执行定义的脚本。建议使用此设置来生成警报或记录事件。请注意,ProxySQL 能够在崩溃的情况下在几毫秒内重新启动,因此其他监控工具可能无法检测到正常故障。
-
errorlog(string):如果设置,ProxySQL 将使用定义的文件作为其错误日志。如果没有传递这样的变量,错误日志将位于
datadir
/proxysql.log -
web_interface_plugin(string):这定义了proxysql将尝试加载的Web界面(UI)插件的完整路径,以用更高级的替换其内置的Web界面
-
sqlite3_plugin(string):这定义了proxysql将尝试加载的SQLite3插件的完整路径,以替换其内置的SQLite3引擎,以添加额外的功能,特别是静态加密
其他的模块变量 global_variables 表中:
mysql-后缀相关名称:对应如果写在配置文件中为 mysql_variables 模块的所有
admin-后缀相关名称:对应如果写在配置文件中为 admin_variables 模块中的所有
比如:
配置文件:
【7】基础监控模块
(7.1)4中监控检查类型
监控模块负责对后端进行一系列检查。
它目前支持 4 种类型的检查:
-
connect:连接所有后端,成功/失败记录在表中
mysql_server_connect_log
; -
ping:它对所有后端执行 ping 操作,成功/失败记录在 table 中
mysql_server_ping_log
。在mysql-monitor_ping_max_failures
丢失心跳的情况下,它会向 MySQL_Hostgroups_Manager 发送信号以终止所有连接; -
max_replication_lag复制滞后:它检查
Seconds_Behind_Master
所有配置max_replication_lag
大于0的后端,并将检查记录在表中mysql_server_replication_lag_log
。如果Seconds_Behind_Master
>max_replication_lag
则回避服务器,直到Seconds_Behind_Master
<max_replication_lag
; -
read_only只读:它检查
read_only
表中主机组中的所有主机mysql_replication_hostgroups
,并将检查记录在表中mysql_server_read_only_log
。如果read_only=1
主机被复制/移动到reader_hostgroup
,而如果read_only=0
主机被复制/移动到writer_hostgroup
.
(7.2)监控变量
全变量参考:https://proxysql.com/documentation/global-variables/mysql-monitor-variables/
-- 一般变量: mysql-monitor_username 指定 Monitor 模块将用于连接到后端的用户名。用户只需要USAGE连接、ping 和检查的权限read_only。REPLICATION CLIENT如果需要监控复制滞后,用户还需要特权。 mysql-monitor_password 用户mysql-monitor_username 的密码 mysql-monitor_enabled 它启用或禁用 MySQL Monitor。由于 MySQL Monitor 可以干扰直接应用在 Admin 界面上的更改,因此此变量允许临时禁用它。 -- 连接变量: mysql-monitor_connect_interval 执行连接检查的频率,以毫秒为单位。 mysql-monitor_connect_timeout 连接超时(以毫秒为单位)。当前实现将此值四舍五入为小于或等于原始间隔的整数秒数,最小为 1 秒。这种惰性舍入是因为 SSL 连接阻塞调用而完成的。 -- ping变量: mysql-monitor_ping_interval 执行 ping 检查的频率,以毫秒为单位。 mysql-monitor_ping_timeout Ping 超时(以毫秒为单位)。 mysql-monitor_ping_max_failures 如果主机连续错过mysql-monitor_ping_max_failures ping,MySQL_Monitor 会通知 MySQL_Hostgroup_Manager 该节点无法访问,并且应该立即终止所有连接。 需要注意的是,如果与后端的连接不可用,MySQL_Monitor 将首先尝试连接以便 ping,因此检测节点关闭的时间可能是以下两个之一: mysql-monitor_ping_max_failures * mysql-monitor_connect_timeout mysql-monitor_ping_max_failures * mysql-monitor_ping_timeout -- 只读变量: mysql-monitor_read_only_interval 执行只读检查的频率,以毫秒为单位。 mysql-monitor_read_only_timeout 只读检查超时(以毫秒为单位)。 mysql-monitor_writer_is_also_reader 当一个节点将其read_only值从 1 更改为 0 时,此变量确定该节点是否应存在于两个主机组中: false : 节点将被移入writer_hostgroup和移除reader_hostgroup true : 节点将被复制writer_hostgroup并保留在reader_hostgroup -- 复制滞后变量: mysql-monitor_replication_lag_interval 执行复制滞后检查的频率,以毫秒为单位。 mysql-monitor_replication_lag_timeout 复制延迟检查超时(以毫秒为单位)。 -- 其他变量: mysql-monitor_history 为了防止日志表无限制地增长,Monitor Module 将自动清除超过mysql-monitor_history毫秒的记录。
由于 ping 检查依赖于历史表来确定节点是否缺少心跳,因此如果mysql-monitor_history的值小于该值,则会自动将其调整为以下值: ( mysql-monitor_ping_max_failures + 1) * mysql-monitor_ping_timeout
(7.3)监控线程与线程池
监控模块有几个内部线程。
目前有5个主线程:
- Monitor:主线程,负责启动和协调所有其他线程
- monitor_connect_thread:连接检查的主线程和调度程序
- monitor_ping_thread:用于 ping 检查的主线程和调度程序
- monitor_read_only_thread:只读检查的主线程和调度程序
- monitor_replication_lag_thread:用于复制滞后检查的主线程和调度程序
直到 v1.2.0 版本,上述线程(不包括Monitor)也负责执行检查
线程池:
v1.2.0 中的实现对 SSL 实现有一个限制:使用 SSL,connect()
是一个阻塞调用,导致线程在执行连接阶段时停止。
v1.2.1 版本试图通过新的实现来克服这个限制。现在:
- Monitor初始化一个worker的Thread Pool并创建一个队列;
- monitor_connect_thread、monitor_ping_thread、monitor_read_only_thread和monitor_replication_lag_thread是生产者,它们生成任务并使用队列将它们发送给工作人员;
- 工人处理任务并执行所需的动作;
- 如果Monitor检测到队列增长过快,它会创建新的临时工作线程
连接清除:
Monitor 实现了自己的连接池。活动时间超过 3 *mysql_thread___monitor_ping_interval
毫秒的连接会被自动清除。
等待超时:
为了防止后端终止连接,Monitor 模块自动配置wait_timeout
= mysql_thread___monitor_ping_interval
* 10
【8】admin变量、mysql变量
ProxySQL 通过允许大多数变量在运行时更改并立即生效来支持最长的正常运行时间,而无需重新启动守护程序。
只有 3x 变量在运行时无法更改 mysql-interfaces
和 mysql-threads,
mysql-stacksize
(8.1)admin变量
全变量参考:https://proxysql.com/Documentation/global-variables/admin-variables/
几个简单常用变量:
admin-admin_credentials:该变量控制的是admin管理接口的管理员账户。默认的管理员账户和密码为admin:admin
,但是这个默认的用户只能在本地使用。
如果想要远程连接到ProxySQL,例如用windows上的navicat连接Linux上的ProxySQL管理接口,必须自定义一个管理员账户。
admin-stats_credentials:该变量控制admin管理接口的普通用户,这个变量中的用户没有超级管理员权限,只能查看monitor库和main库中关于统计的数据,其它库都是不可见的,且没有任何写权限。
admin-mysql_ifaces:网络接口监听地址,默认0.0.0.0:6032
(8.2)mysql变量
官网参考:https://proxysql.com/documentation/global-variables/mysql-variables/
监控变量:参考:https://proxysql.com/documentation/global-variables/mysql-monitor-variables/
【ProxySQL常用命令】
要重新配置 MySQL 用户,可执行下面的其中一个命令:
1
2
3
4
5
6
7
8
9
10
|
1、LOAD MYSQL USERS FROM MEMORY / LOAD MYSQL USERS TO RUNTIME 将内存数据库中的配置加载到 runtime 数据结构,反之亦然。 2、SAVE MYSQL USERS TO MEMORY / SAVE MYSQL USERS FROM RUNTIME 将 MySQL 用户从 runtime 持久化到内存数据库。 3、LOAD MYSQL USERS TO MEMORY / LOAD MYSQL USERS FROM DISK 从磁盘数据库中加载 MySQL 用户到内存数据库中。 4、SAVE MYSQL USERS FROM MEMORY / SAVE MYSQL USERS TO DISK 将内存数据库中的 MySQL 用户持久化到磁盘数据库中。 5、LOAD MYSQL USERS FROM CONFIG 从配置文件中加载 MySQL 用户到内存数据库中。 |
要处理 MySQL server:
1
2
3
4
5
6
7
8
9
10
|
1、LOAD MYSQL SERVERS FROM MEMORY / LOAD MYSQL SERVERS TO RUNTIME 将 MySQL server 从内存数据库中加载到 runtime。 2、SAVE MYSQL SERVERS TO MEMORY / SAVE MYSQL SERVERS FROM RUNTIME 将 MySQL server 从 runtime 持久化到内存数据库中。 3、LOAD MYSQL SERVERS TO MEMORY / LOAD MYSQL SERVERS FROM DISK 从磁盘数据库中加载 MySQL server 到内存数据库。 4、SAVE MYSQL SERVERS FROM MEMORY / SAVE MYSQL SERVERS TO DISK 从内存数据库中将 MySQL server 持久化到磁盘数据库中。 5、LOAD MYSQL SERVERS FROM CONFIG 从配置文件中加载 MySQL server 到内存数据库中 |
要处理 MySQL 的查询规则(mysql query rules):
1
2
3
4
5
6
7
8
9
10
|
1、 LOAD MYSQL QUERY RULES FROM MEMORY / LOAD MYSQL QUERY RULES TO RUNTIME 将 MySQL query rules 从内存数据库加载到 runtime 数据结构。 2、 SAVE MYSQL QUERY RULES TO MEMORY / SAVE MYSQL QUERY RULES FROM RUNTIME 将 MySQL query rules 从 runtime 数据结构中持久化到内存数据库。 3、 LOAD MYSQL QUERY RULES TO MEMORY / LOAD MYSQL QUERY RULES FROM DISK 从磁盘数据库中加载 MySQL query rules 到内存数据库中。 4、 SAVE MYSQL QUERY RULES FROM MEMORY / SAVE MYSQL QUERY RULES TO DISK 将 MySQL query rules 从内存数据库中持久化到磁盘数据库中。 5、 LOAD MYSQL QUERY RULES FROM CONFIG 从配置文件中加载 MySQL query rules 到内存数据库中。 |
要处理 MySQL 变量(MySQL variables):
1
2
3
4
5
6
7
8
9
10
|
1、 LOAD MYSQL VARIABLES FROM MEMORY / LOAD MYSQL VARIABLES TO RUNTIME 将 MySQL variables 从内存数据库加载到 runtime 数据结构。 2、 SAVE MYSQL VARIABLES TO MEMORY / SAVE MYSQL VARIABLES FROM RUNTIME 将 MySQL variables 从 runtime 数据结构中持久化到内存数据中。 3、 LOAD MYSQL VARIABLES TO MEMORY / LOAD MYSQL VARIABLES FROM DISK 从磁盘数据库中加载 MySQL variables 到内存数据库中。 4、 SAVE MYSQL VARIABLES FROM MEMORY / SAVE MYSQL VARIABLES TO DISK 将 MySQL variables 从内存数据库中持久化到磁盘数据库中。 5、 LOAD MYSQL VARIABLES FROM CONFIG 从配置文件中加载 MySQL variables 到内存数据库中。 |
要处理管理变量(admin variables):
1
2
3
4
5
6
7
8
9
10
|
1、 LOAD ADMIN VARIABLES FROM MEMORY / LOAD ADMIN VARIABLES TO RUNTIME 将 admin variables 从内存数据库加载到 runtime 数据结构。 2、 SAVE ADMIN VARIABLES TO MEMORY / SAVE ADMIN VARIABLES FROM RUNTIME 将 admin variables 从 runtime 持久化到内存数据库中。 3、 LOAD ADMIN VARIABLES TO MEMORY / LOAD ADMIN VARIABLES FROM DISK 从磁盘数据库中加载 admin variables 到内存数据库中。 4、 SAVE ADMIN VARIABLES FROM MEMORY / SAVE ADMIN VARIABLES TO DISK 将 admin variables 从内存数据库中持久化到磁盘数据库。 5、 LOAD ADMIN VARIABLES FROM CONFIG 从配置文件中加载 admin variables 到内存数据库中。 |
这里有几个最常用的命令:如何让修改的配置生效(runtime),以及如何持久化到磁盘上(disk)。记住,只要不是加载到 runtime,修改的配置就不会生效。
1
2
3
4
5
6
7
8
9
10
|
LOAD MYSQL USERS TO RUNTIME; 将内存数据库中的配置加载到 runtime 数据结构 SAVE MYSQL USERS TO DISK; 将内存数据库中的 MySQL 用户持久化到磁盘数据库中。 LOAD MYSQL SERVERS TO RUNTIME; 将 MySQL server 从内存数据库中加载到 runtime。 SAVE MYSQL SERVERS TO DISK; 从内存数据库中将 MySQL server 持久化到磁盘数据库中。 LOAD MYSQL QUERY RULES TO RUNTIME; 将 MySQL query rules 从内存数据库加载到 runtime 数据结构。 SAVE MYSQL QUERY RULES TO DISK; 将 MySQL query rules 从内存数据库中持久化到磁盘数据库中。 LOAD MYSQL VARIABLES TO RUNTIME; 将 MySQL variables 从内存数据库加载到 runtime 数据结构。 SAVE MYSQL VARIABLES TO DISK; 将 MySQL variables 从内存数据库中持久化到磁盘数据库中。 LOAD ADMIN VARIABLES TO RUNTIME; 将 admin variables 从内存数据库加载到 runtime 数据结构。 SAVE ADMIN VARIABLES TO DISK; 将 admin variables 从内存数据库中持久化到磁盘数据库。 |
【参考文档】
官方文档:https://proxysql.com/documentation/ProxySQL-Configuration/
mysql中的ProxySQL实现读写分离与读负载均衡【转】
常用运维小技巧:https://blog.csdn.net/weixin_30762363/article/details/113126317
proxysql的概念、使用场景、作用:https://www.modb.pro/db/151458
proxysql mysql_query_rules 规则匹配,replace_pattern 的使用:https://blog.csdn.net/liuhuayang/article/details/106681678