本文演示使用ProxySQL来完成读写分离和后端分库的一个实际配置过程,安装及配置项介绍见前文 ProxySQL之安装及配置详解。
环境
|
|
现在想达到这样一个目的:客户端应用连接上 proxysql 的ip:port,连接时指定分库db名,执行sql时自动路由到对应的实例、对应的库。考虑下面的部署结构:
任何一个proxysql节点都是对等的,路由请求到后端instance的各个database上。
1. 配置后端DB
|
|
比如 100 是主库,则 1000 是从库,同时主库也可以处理 1/10 的读请求。
2. 配置用户
|
|
这里将 transaction_persistent 设置为1,如果不知道它的含义,请参考前文。
要确保用户有能够登陆到后端的所有db的权限。
3. 修改全局变量
|
|
需要提前给 monitor 账号开通权限,一般共用监控数据库的权限就足够了。
让上面所有的修改生效:
|
|
4. 添加路由规则
一般配置ProxySQL规则步骤是 issues #653 :
- 配置proxysql,将所有sql都发到主库
- 分析表
stats_mysql_query_digest
里面哪几种查询占比高 - 筛选哪些些占比高的SELECT,可以路由到从库
- 修改
mysql_query_rules
里面的规则,使其生效。不要一味的把所有查询都路由到主库
|
|
逐个解释:
以 select 开头并且不是 for update 类型的SQL,进入到新的规则链flagOUT=20;
其它诸如 insert, delete, update, replace, set, show 等语句,都进入到规则链flagOUT=21。 注:’^(?select’ 规则匹配以select
或(select
开头的查询,但目前proxysql(1.3.6, 1.4.1)版本对以(
开头的查询不记录 stats_mysql_query_digest 表。#issue 1100有个小技巧,mysql_query_rules 表的rule_id有自增,但最好从中间某个数开始,因为一旦后续可能需要紧急在前面插入规则,从1开始就没空位了。
这里大家可能有个顾虑,从库上可以执行
set NAMES xxx
,set session sql_mode=xxx
,SET autocommit=?
,commit
,rollback
,START TRANSACTION
,use dbx
这样的语句,不能全路由到主库吧?对此,另起了一篇文章 http://xgknight.com/2017/04/17/mysql-proxysql-multiplexing 。flagIN=20 是 只读链 的入口
根据连接时指定的dbname,路由到对应的分库上。db0, db4, db8, db12 路由到 hostgroup_id=1000 ,db1, db5, db9, db16 路由到 hostgroup_id=1002 ,依次类推。 flagIN=flagOUT 则结束匹配。flagOUT=21 是 读写链的入口
与上面的 [2] 类似,但是根据dbname路由到主库。当建立连接的时候没有指定dbname时,分两种情况
- 使用连接的时候
use db0
,因为mysql协议在每次 use dbname 时都会发送一个SELECT DATABASE()
命令,第一次由于没有连接上后端任何DB,命令会执行超时失败,再次 use db0 是才成功。具体参考我所提的 issue #988 。 因此这里我为它添加了一个规则 [6],遇到这种情况马上处理,而不用等待失败。 - 使用连接时从未有默认schema,添加规则 [5],使用
schemaname.tablename
的形式匹配 schemaname,然后路由到对应的 hostgroup 。
- 因为没有定义 hostgroup 0,在意外情况什么规则都没匹配上时也依旧会等待失败,所以默认规则(默认路由)返回一个错误。
5. 效果演示
|
|
切换数据库继续:
|
|
达到了读写分离和分实例分库的目的。
6. 另一种规则写法
从上面可以看到,客户端应用在使用的时候,最好都要指定 database name ,上面是因为加了第 5 类规则才避免由于不指定db时所带来的问题,但始终要求对每个 分db 建立自己连接,或者查询之前 use dbname ,当然也可以在获取连接的时候,传递dbname过去,拿到带正确db的连接过来。
那么其实还有一种办法,不需要指定连接db,而是采用注释 hint 的形式,传递给proxysql,然后来自动路由。将第 4 节的规则 [2],[3] 改成下面的形式:
|
|
注意这里[2][3]用的是 match_pattern
,而上节用的是match_digest
,因为proxysql在处理fingerprint的时候,会去掉注释。如果在命令行测试,要加 -c
避免 HINT 被过滤掉。
使用时Hint放sql最后面,每个sql都要带mod或者指定实例:select * from db5.tbl_0 /* shard_corp_mod=5 */
,真正实施起来,应用端的复杂度以及proxysql的性能,还是有待考虑的。
关于这些路由规则的写法对ProxySQL性能的影响,欢迎继续阅读这边文章 ProxySQL之性能测试对比
参考:
- https://severalnines.com/blog/how-proxysql-adds-failover-and-query-control-your-mysql-replication-setup
- https://www.percona.com/blog/2016/08/30/mysql-sharding-with-proxysql/
原文连接地址:http://xgknight.com/2017/04/17/mysql-proxysql-route-rw_split/