MySQL中間件之ProxySQL_讀寫分離/查詢重寫配置

MySQL中間件之ProxySQL_讀寫分離/查詢重寫配置

1.閒扯幾句
讀寫分離這是一個扯了好多年的話題,實現方式也也是層出不窮。筆者也曾經使用keepalive+lvs的方式給別人作過讀寫分離,效果還不錯,也不是特別麻煩,用起來蠻好,就是應用有點不喜歡,須要配置讀IP和寫IP,應用感受麻煩,不肯用。那麼引入中間件,這些都不是事,暴露給應用的仍是一個IP一個port,什麼讀寫分離,交給中間件好了,想怎麼路由SQL就怎麼路由SQL,你開心就好。php


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

繪圖1
看起來還不錯,可是mysql高可用這塊還需讀者本身去想辦法,MHA,MMM,group replication,pxc均可以的喲。
mysql一主兩從讀者自行搭建。html

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。
登陸proxysqlnode

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節點執行。mysql

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:linux

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中添加帳號,nginx

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,如今初始化數據庫。sql

[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爲咱們統計了那些信息呢。
QQ圖片20161225142941
很是不錯的統計信息,各類命令的聚合統計,方便咱們監控數據庫負載趨勢,一眼就能夠看出讀多仍是寫多。
還有更具體的統計信息。
QQ圖片20161225143211
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

查看結果
QQ圖片20161225145055
能夠看到,全部的非select*for update的查詢語句都已經轉發到slave了,也就是group 1.
登陸到slave上咱們確實能夠到不少查詢已經切過來了。
QQ圖片20161225145302


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統計信息。
QQ圖片20161225152038
哈哈,是否是distinct後面的order by已經沒有了。厲害了,word proxysql。

文章導航

Write a Reply or Comment

電子郵件地址不會被公開。 必填項已用*標註

 

相關文章
相關標籤/搜索