MySQL中间件之ProxySQL_读写分离/查询重写配置
MySQL中间件之ProxySQL_读写分离/查询重写配置
1.闲扯几句
读写分离这是一个扯了好多年的话题,实现方式也也是层出不穷。笔者也曾经使用keepalive+lvs的方式给别人做过读写分离,效果还不错,也不是特别麻烦,用起来蛮好,就是应用有点不喜欢,需要配置读IP和写IP,应用感觉麻烦,不愿用。那么引入中间件,这些都不是事,暴露给应用的还是一个IP一个port,什么读写分离,交给中间件好了,想怎么路由SQL就怎么路由SQL,你开心就好。
2.配个读写分离
2.1准备工作
这里我带领大家配个简单的一主两从,搞个读写分离,配个查询缓存,玩下查询重写。
node1 (192.168.56.101:24801) , mysql master
node2 (192.168.56.101:24802) , mysql slave
node3 (192.168.56.101:24803) , mysql slave
app (192.168.56.101:6033) , app+proxysql
看起来还不错,但是mysql高可用这块还需读者自己去想办法,MHA,MMM,group replication,pxc都可以的哟。
mysql一主两从读者自行搭建。
root@localhost [(none)] 01:43:27>>> show slave hosts;
+-----------+------+-------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+-------+-----------+--------------------------------------+
| 3 | | 24803 | 1 | 87626cdd-c918-11e6-b3a6-0800278bcede |
| 2 | | 24802 | 1 | 81850b66-c918-11e6-b22e-0800278bcede |
+-----------+------+-------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
2.2配置
现在我们把一主两从的mysql数据库信息添加到proxysql中。我们将主库master也就是做写入的节点放到group 0中,salve节点做读放到group1。
登录proxysql
admin@127.0.0.1 [(none)] 01:48:32>>>INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (0,'192.168.56.101',24801);
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 01:48:45>>>INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (1,'192.168.56.101',24802);
Query OK, 1 row affected (0.01 sec) admin@127.0.0.1 [(none)] 01:48:45>>>INSERT INTO mysql_servers(hostgroup_id, hostname, port) VALUES (1,'192.168.56.101',24803);
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 01:48:46>>>select hostgroup_id,hostname,port,status from mysql_servers;
+--------------+----------------+-------+--------+
| hostgroup_id | hostname | port | status |
+--------------+----------------+-------+--------+
| 0 | 192.168.56.101 | 24801 | ONLINE |
| 1 | 192.168.56.101 | 24802 | ONLINE |
| 1 | 192.168.56.101 | 24803 | ONLINE |
+--------------+----------------+-------+--------+
3 rows in set (0.00 sec)
根据安装部署篇的提示,我们在数据库中需要配置好了监控账号(ProxySQL)和应用账号(sbuser)。以下SQL在master节点执行。
CREATE USER 'ProxySQL'@'%' IDENTIFIED BY 'ProxySQLPa55';
GRANT USAGE ON *.* TO 'ProxySQL'@'%';
CREATE USER 'sbuser'@'%' IDENTIFIED BY 'sbpass';
GRANT ALL ON * . * TO 'sbuser'@'%';
FLUSH PRIVILEGES;
确认账号OK:
root@localhost [(none)] 01:57:12>>>select host,user from mysql.user;
+-----------+-----------+
| host | user |
+-----------+-----------+
| % | proxysql |
| % | rpl_user |
| % | sbuser |
| localhost | mysql.sys |
| localhost | root |
+-----------+-----------+
5 rows in set (0.00 sec)
在proxysql中添加账号,
admin@127.0.0.1 [(none)] 01:59:49>>>INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('sbuser','sbpass',0);
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 01:59:50>>>UPDATE global_variables SET variable_value='proxysql' WHERE variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.01 sec) admin@127.0.0.1 [(none)] 01:59:50>>>UPDATE global_variables SET variable_value='ProxySQLPa55' WHERE variable_name='mysql-monitor_password';
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 01:59:51>>>LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)
/*将配置应用于proxysql运行环境*/ admin@127.0.0.1 [(none)] 02:00:45>>>SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.05 sec)
/*将配置存储到sqlite数据库中*/
查看proxysql监控数据库的一些指标
admin@127.0.0.1 [(none)] 02:20:48>>>SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start DESC LIMIT 10;
+----------------+-------+------------+----------------------+---------------+
| hostname | port | time_start | connect_success_time | connect_error |
+----------------+-------+------------+----------------------+---------------+
| 192.168.56.101 | 24803 | 604984013 | 360 | NULL |
| 192.168.56.101 | 24802 | 604983410 | 383 | NULL |
| 192.168.56.101 | 24801 | 604982712 | 472 | NULL |
| 192.168.56.101 | 24803 | 602983284 | 301 | NULL |
| 192.168.56.101 | 24802 | 602982770 | 360 | NULL |
| 192.168.56.101 | 24801 | 602982025 | 576 | NULL |
| 192.168.56.101 | 24803 | 600982931 | 394 | NULL |
| 192.168.56.101 | 24802 | 600982168 | 1540 | NULL |
| 192.168.56.101 | 24801 | 600981405 | 507 | NULL |
| 192.168.56.101 | 24803 | 598982425 | 982 | NULL |
+----------------+-------+------------+----------------------+---------------+
10 rows in set (0.00 sec) admin@127.0.0.1 [(none)] 02:20:50>>>SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start DESC LIMIT 10;
+----------------+-------+------------+-------------------+------------+
| hostname | port | time_start | ping_success_time | ping_error |
+----------------+-------+------------+-------------------+------------+
| 192.168.56.101 | 24803 | 606998231 | 58 | NULL |
| 192.168.56.101 | 24802 | 606997865 | 75 | NULL |
| 192.168.56.101 | 24801 | 606996830 | 93 | NULL |
| 192.168.56.101 | 24803 | 604997051 | 39 | NULL |
| 192.168.56.101 | 24802 | 604996633 | 42 | NULL |
| 192.168.56.101 | 24801 | 604996278 | 54 | NULL |
| 192.168.56.101 | 24803 | 602997075 | 42 | NULL |
| 192.168.56.101 | 24802 | 602996658 | 85 | NULL |
| 192.168.56.101 | 24801 | 602996275 | 63 | NULL |
| 192.168.56.101 | 24803 | 600997230 | 47 | NULL |
+----------------+-------+------------+-------------------+------------+
10 rows in set (0.00 sec)
使用业务用户通过proxysql登录mysql。如果卡住了,可能是DNS解析引起。
[mysql@hpc01 ~]$ mysql -u sbuser -psbpass -h 127.0.0.1 -P6033 -e "select @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
| 24801 |
+--------+
好了,用户通过proxysql登录master,现在初始化数据库。
[mysql@hpc01 ~]$ sysbench --test=oltp --oltp-table-size=4000 --oltp-read-only=off --init-rng=on --num-threads=5 --max-requests=0 --oltp-dist-type=uniform --max-time=36 --mysql-user=sbuser --mysql-password='sbpass' --db-driver=mysql --mysql-port=6033 --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-db=sbtest --oltp-tables-count=5 --report-interval=1 prepare
sysbench 1.0: multi-threaded system evaluation benchmark Creating table 'sbtest1'...
Inserting 4000 records into 'sbtest1'
Creating secondary indexes on 'sbtest1'...
Creating table 'sbtest2'...
Inserting 4000 records into 'sbtest2'
Creating secondary indexes on 'sbtest2'...
Creating table 'sbtest3'...
Inserting 4000 records into 'sbtest3'
Creating secondary indexes on 'sbtest3'...
Creating table 'sbtest4'...
Inserting 4000 records into 'sbtest4'
Creating secondary indexes on 'sbtest4'...
Creating table 'sbtest5'...
Inserting 4000 records into 'sbtest5'
Creating secondary indexes on 'sbtest5'...
清空查询统计,然后运行一次sysbench,查看proxysql统计信息。
下面这个sql在proxysql是专门清空stats_mysql_query_digest表的。
admin@127.0.0.1 [(none)] 02:24:45>>>SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.01 sec)
使用sysbench来压测mysql。
[mysql@hpc01 ~]$ sysbench --test=oltp --oltp-table-size=4000 --oltp-read-only=off --init-rng=on --num-threads=5 --max-requests=0 --oltp-dist-type=uniform --max-time=36 --mysql-user=sbuser --mysql-password='sbpass' --db-driver=mysql --mysql-port=6033 --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-db=sbtest --oltp-tables-count=5 --report-interval=1 run
然后我们查看proxysql为我们统计了那些信息呢。
非常不错的统计信息,各种命令的聚合统计,方便我们监控数据库负载趋势,一眼就可以看出读多还是写多。
还有更具体的统计信息。
proxysql converts queries into fingerprints。然后对每类sql做聚合统计。
2.3读写分离配置
细心同学就发现了,现在所有的sql都发送到了group 0,也就是我们的master主库节点。好咯,我们来做一个读写分离。
要注意,proxysql没有设计多么复杂的读写分离算法,proxysql的实现方式很简单,就是做sql路由,我们自定义sql路由规则就可以实现读写分离。这里我们将所有除了select*
from update的select全部发送到slave,其他的的语句发送到master。
登录proxysql配置路由项。
admin@127.0.0.1 [(none)] 02:41:58>>>INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT.*FOR UPDATE$',0,1);
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 02:41:59>>>INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT',1,1);
Query OK, 1 row affected (0.00 sec) admin@127.0.0.1 [(none)] 02:41:59>>>LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec) admin@127.0.0.1 [(none)] 02:42:20>>>SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.04 sec)
聪明的同学就发现了,原来这么匹配是基于正则表达式的啊。right。
active表示是否启用这个sql路由项,
match_pattern就是我们正则匹配项,
destination_hostgroup表示我们要将该类sql转发到哪些mysql上面去,这里我们将select转发到group 1,也就是两个slave上。
apply为1表示该正则匹配后,将不再接受其他匹配,直接转发。
添加了sql路由,我们来看看是否实现了读写分离呢。
首先记得清空proxysql的query统计
admin@127.0.0.1 [(none)] 02:48:56>>>SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
直接用sysbench压测
[mysql@hpc01 ~]$ sysbench --test=oltp --oltp-table-size=4000 --oltp-read-only=off --init-rng=on --num-threads=5 --max-requests=0 --oltp-dist-type=uniform --max-time=36 --mysql-user=sbuser --mysql-password='sbpass' --db-driver=mysql --mysql-port=6033 --mysql-table-engine=innodb --mysql-host=127.0.0.1 --mysql-db=sbtest --oltp-tables-count=5 --report-interval=1 run
查看结果
可以看到,所有的非select*for update的查询语句都已经转发到slave了,也就是group 1.
登录到slave上我们确实可以到很多查询已经切过来了。
3.查询重写
3.1配置
查询重写这种东西,对于线上环境紧急故障处理还是很有用处的。如果定位到了问题所在,必须修改SQL,时间紧急,让应用重新发布上线是不太现实了,这时查询重写这个东西就非常有用了。
举个简单的例子
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c
这类SQL是有优化余地的,我们可以去掉ORDER BY c,多此一举,因为在做DISTINCT时我们已经做了排序。需要改成如下模式
SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ?
其实查询重写的实现在proxysql中也实现为正则匹配替换。是不是非常赞,不需要非常复杂的算法就实现了,非常赞,用户可控度也大,用着非常舒服。
我们编辑一条SQL路由规则。
INSERT INTO mysql_query_rules (active,match_pattern,replace_pattern,apply) VALUES (1,'DISTINCT(.*)ORDER BY c','DISTINCT\1',1);
这条规则什么意思呢,这条路由规则表示当proxysql匹配到DISTINCT<若干字符>ORDER BY c这个模式后,就将这个模式的ORDER BY c去掉。那么DISTINCT\1中的\1是什么意思呢,玩过sed的同学很快就反应过来,这不就是向前引用么,哈哈答对了。举个例子你就明白了。
假如我们有这样一个文件:
[root@hpc01 ~]$ cat aaa
,90909
,dasfsdfssd98908
我们想把每行的逗号去掉,我们可以利用sed的向前引用:
[root@hpc01 ~]$ sed "s/,\(.*\)/\1/g" aaa
90909
dasfsdfssd98908
逗号后面的所有字符用\(.*\)表示,在后面替换我们用\1表示这部分。sed最大支持到\9,还是很强大的。如果实在不明白什么意思,推荐学习学习《sed与awk》。反正要玩proxysql正则表达式要玩得溜溜的。
还要注意,我们要重写的selete语句,你可曾记得,我们已经将所有非seletc* from
update语句已经重定向到slave,也就是select语句已经有了一条路由规则了。而且那条路由已经将apply字段设为1,也就是不再接受其他路由规则。好,我们需要更改apply字段才可以使这条规则生效。
update mysql_query_rules set apply=0 where match_pattern='^SELECT';
使配置生效
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;
注意,以上配置都是在proxysql中操作的,别跑错了跑到数据库中搞啊。
3.2验证配置
首先清空以前的统计信息,不然混在一起,无法辨认。
admin@127.0.0.1 [(none)] 03:16:37>>>SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.01 sec)
直接使用sysbench压测
然后查看proxysql统计信息。
哈哈,是不是distinct后面的order by已经没有了。厉害了,word proxysql。
文章导航
Write a Reply or Comment
电子邮件地址不会被公开。 必填项已用*标注
评论
姓名 *
电子邮件 *
站点
For DBA 介绍
For DBA 是一个热爱数据库,Linux的团队,曾就职于某省级运营商,现就职于某知名互联网公司,热衷于研究和分享各种Oracle,MySQL,MongoDB,以及Linux的使用经验和心得。
标签
近期评论
- Harvey发表在《MySQL的char和varchar针对空格的处理》
- mark blue, mark发表在《MySQL的char和varchar针对空格的处理》
- Harvey发表在《MySQL的char和varchar针对空格的处理》
- milktwo发表在《MySQL的char和varchar针对空格的处理》
- milktwo发表在《MySQL的char和varchar针对空格的处理》
书签
文章归档
MySQL中间件之ProxySQL_读写分离/查询重写配置的更多相关文章
- MySql的主从复制以及读写分离详解
MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践 Mysql作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过.但在实际的生产环境中, ...
- MySQL+Amoeba实现数据库读写分离
参考:https://www.cnblogs.com/liuyisai/p/6009379.html 一,Amoeba是什么 Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发.座落与C ...
- mysql数据库主从同步读写分离(一)主从同步
1.mysql数据库主从同步读写分离 1.1.主要解决的生产问题 1.2.原理 a.为什么需要读写分离? 一台服务器满足不了访问需要.数据的访问基本都是2-8原则. b.怎么做? 不往从服务器去写了 ...
- 030:Cetus中间件和MHA读写分离
030:Cetus中间件和MHA读写分离 line:V1.1 mail: gczheng@139.com date: 2018-08-30 一.主机环境 虚拟机配置 CPU 内存 硬盘 OS版本 My ...
- 基于Mysql-Proxy实现Mysql的主从复制以及读写分离(上)
基于Mysql-Proxy实现Mysql的主从复制以及读写分离(上) 上周BOSS给分配任务让实现一下Mysql数据库的主从复制以及读写分离,然后花了一盏茶的功夫进行了调研,发现主从复制数据库进行一番 ...
- MySQL主从同步、读写分离配置步骤、问题解决笔记
MySQL主从同步.读写分离配置步骤.问题解决笔记 根据要求配置MySQL主从备份.读写分离,结合网上的文档,对搭建的步骤和出现的问题以及解决的过程做了如下笔记: 现在使用的两台服务器已经 ...
- redis 作为 mysql的缓存服务器(读写分离)
redis 作为 mysql的缓存服务器(读写分离) 一.redis简介 Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会 ...
- MySQL主从同步和读写分离的配置
主服务器:192.168.1.126 从服务器:192.168.1.163 amoeba代理服务器:192.168.1.237 系统全部是CentOS 6.7 1.配置主从同步 1.1.修改主服务器( ...
- 基于Mysql-Proxy实现Mysql的主从复制以及读写分离(下)
基于Mysql-Proxy实现Mysql的主从复制以及读写分离(下) 昨天谈到了Mysql实现主从复制,但由于时间原因并未讲有关读写分离的实现,之所以有读写分离,是为了使数据库拥有双机热备功能,至于双 ...
随机推荐
- 题解报告:poj 2559 Largest Rectangle in a Histogram(单调栈)
Description A histogram is a polygon composed of a sequence of rectangles aligned at a common base l ...
- 解题报告:hdu 1556 Color the ball(区间修改,单点查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1556 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N ...
- iOS9 关于明文HTTP报错的修复方法
报错:App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. ...
- HUST 1698 - 电影院 组合数学 + 分类思想
http://acm.hust.edu.cn/problem/show/1698 题目就是要把一个数n分成4段,其中中间两段一定要是奇数. 问有多少种情况. 分类, 奇数 + 奇数 + 奇数 + 奇数 ...
- flex弹性布局操练1
实现弹性布局之前常用浮动,相对定位和绝对定位等,但是现在好了,随着flex的兴起,方便了很多,而且也符合未来响应式布局的方向. 理论的东西可参考css3手册,这里专注实操. 一:单个元素 <di ...
- vue-router之 beforeRouteEnter
beforeRouteEnter在每次路由切换都执行 ,而项目优化后,切换路由mounted只在最开始执行一次 beforeRouteEnter的具体用法可参考官方文档 https://cn.vuej ...
- 关于Android软键盘把布局顶上去的问题(一)
最近接触到了一个登陆页面,布局最上面显示的是一个波纹的view,中间显示账号和密码的EditText,紧接着还有一个Button: 希望:点击EditText时,软键盘不能把波纹的view顶出去,也不 ...
- Ubuntu Linux14 64位下在Android studio下用gradle编译Andrid项目时发生libz.so.1共享库找不到的解决方法。
---恢复内容开始--- 我在Ubuntu14 64为下安装了AS,但在用Gradle编译项目时总是报找不到 libz.so.1的错误. error while loading shared libr ...
- leetcode_684. Redundant Connection
https://leetcode.com/problems/redundant-connection/ 一个无向图,n个顶点有n条边,输出一条可以删除的边,删除后使得图成为一棵树.可以使用并查集解决. ...
- CREATE DATABASE - 创建新数据库
SYNOPSIS CREATE DATABASE name [ [ WITH ] [ OWNER [=] dbowner ] [ LOCATION [=] 'dbpath' ] [ TEMPLATE ...