返回ProxySQL系列文章:http://www.cnblogs.com/f-ck-need-u/p/7586194.htmlhtml
<p> </p>前端
<a name="blog1111"></a>mysql
這裏經過一個簡單的示例實現ProxySQL的讀寫分離功能,算是ProxySQL的快速入門。即便是快速入門,須要配置的內容也不少,包括:後端MySQL配置、監控配置、發送SQL語句的用戶、SQL語句的路由規則。因此,想要實現一個ProxySQL+MySQL,即便只實現最基本的功能,步驟也是挺多的,不過配置的邏輯都很簡單。sql
實驗環境:shell
角色 | 主機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實例 |
爲了演示完整的過程,這裏把後端MySQL主從複製的基本配置步驟也列出來了。如瞭解配置過程,可跳過主從配置的部分。數據庫
注意點:slave節點須要設置read_only=1
。若是後端是PXC/MGR/MariaDB Galera,則無需手動設置,由於會自動設置。後端
<a name="blog1.1111"></a>緩存
提供3個MySQL節點的配置文件。app
# 如下是Master的配置文件 [mysqld] datadir=/data socket=/data/mysql.sock server-id=110 log-bin=/data/master-bin sync-binlog=1 log-error=/data/error.log pid-file=/data/mysqld.pid # 如下是slave1的配置文件 [mysqld] datadir=/data socket=/data/mysql.sock server-id=120 relay_log=/data/relay-log log-error=/data/error.log pid-file=/data/mysqld.pid read_only=1 # 如下是slave2的配置文件 [mysqld] datadir=/data socket=/data/mysql.sock server-id=130 relay_log=/data/relay-log log-error=/data/error.log pid-file=/data/mysqld.pid read_only=1
爲3個MySQL節點提供數據目錄/datafrontend
mkdir /data chown -R mysql.mysql /data
初始化三個MySQL節點。
mysqld --initialize-insecure --user=mysql --datadir=/data
啓動3個MySQL節點的mysqld服務。
systemctl start mysqld
連上master,修改root密碼,建立用於複製的用戶repl。
# 如下在master上執行 mysql> alter user root@localhost identified by 'P@ssword1!'; mysql> create user repl@'192.168.100.%' identified by 'P@ssword1!'; mysql> grant replication slave on *.* to repl@'192.168.100.%';
連上兩個slave,開啓複製線程。
# 如下在兩個slave節點上都執行 change master to master_host='192.168.100.22', master_user='repl', master_password='P@ssword1!', master_port=3306, master_log_file='master-bin.000001', master_log_pos=4; start slave;
如此配置以後,3個MySQL節點就保持了同步。
<a name="blog1.2222"></a>
首先啓動ProxySQL。
service proxysql start
啓動後會監聽兩個端口,默認爲6032和6033。6032端口是ProxySQL的管理端口,6033是ProxySQL對外提供服務的端口。
[root@s1 ~]# netstat -tnlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:6032 0.0.0.0:* LISTEN 1231/proxysql tcp 0 0 0.0.0.0:6033 0.0.0.0:* LISTEN 1231/proxysql tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1152/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2151/master tcp6 0 0 :::22 :::* LISTEN 1152/sshd tcp6 0 0 ::1:25 :::* LISTEN 2151/master
而後使用mysql客戶端鏈接到ProxySQL的管理接口(admin interface),該接口的默認管理員用戶和密碼都是admin。
[root@s1 ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1 --prompt 'admin> '
我這裏從新設置了提示符。
admin> show databases; +-----+---------------+-------------------------------------+ | seq | name | file | +-----+---------------+-------------------------------------+ | 0 | main | | | 2 | disk | /var/lib/proxysql/proxysql.db | | 3 | stats | | | 4 | monitor | | | 5 | stats_history | /var/lib/proxysql/proxysql_stats.db | +-----+---------------+-------------------------------------+ 5 rows in set (0.00 sec)
ProxySQL提供了幾個庫,每一個庫都有各自的意義。本文只是快速入門文章,不會詳細介紹每一個庫中的每一個表以及每一個字段,不過在接下來的文章中,我會詳細介紹到每一個字段,由於每一個字段都重要。
在本文,主要修改main和monitor數據庫中的表。
admin> show tables from main; +--------------------------------------------+ | tables | +--------------------------------------------+ | global_variables | | mysql_collations | | mysql_group_replication_hostgroups | | mysql_query_rules | | mysql_query_rules_fast_routing | | mysql_replication_hostgroups | | mysql_servers | | mysql_users | | proxysql_servers | | runtime_checksums_values | | runtime_global_variables | | runtime_mysql_group_replication_hostgroups | | runtime_mysql_query_rules | | runtime_mysql_query_rules_fast_routing | | runtime_mysql_replication_hostgroups | | runtime_mysql_servers | | runtime_mysql_users | | runtime_proxysql_servers | | runtime_scheduler | | scheduler | +--------------------------------------------+ admin> show tables from monitor; +------------------------------------+ | tables | +------------------------------------+ | mysql_server_connect_log | | mysql_server_group_replication_log | | mysql_server_ping_log | | mysql_server_read_only_log | | mysql_server_replication_lag_log | +------------------------------------+
runtime_
開頭的是運行時的配置,這些是不能修改的。要修改ProxySQL的配置,須要修改了非runtime_
表,修改後必須執行LOAD ... TO RUNTIME
才能加載到RUNTIME生效,執行save ... to disk
才能將配置持久化保存到磁盤。具體操做見後文。
insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.100.22',3306); insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.100.23',3306); insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.100.24',3306);
注:上面語句中沒有先切換到main庫也執行成功了,由於ProxySQL內部使用的SQLite3數據庫引擎,和MySQL的解析方式是不同的。即便執行了
USE main
語句也是無任何效果的,但不會報錯。
查看這3個節點是否插入成功,以及它們的狀態。請認真讀一讀每一個字段的名稱,混個眼熟。
admin> select * from mysql_servers\G *************************** 1. row *************************** hostgroup_id: 10 hostname: 192.168.100.22 port: 3306 status: ONLINE weight: 1 compression: 0 max_connections: 1000 max_replication_lag: 0 use_ssl: 0 max_latency_ms: 0 comment: *************************** 2. row *************************** hostgroup_id: 10 hostname: 192.168.100.23 port: 3306 status: ONLINE weight: 1 compression: 0 max_connections: 1000 max_replication_lag: 0 use_ssl: 0 max_latency_ms: 0 comment: *************************** 3. row *************************** hostgroup_id: 10 hostname: 192.168.100.24 port: 3306 status: ONLINE weight: 1 compression: 0 max_connections: 1000 max_replication_lag: 0 use_ssl: 0 max_latency_ms: 0 comment: 3 rows in set (0.00 sec)
修改後,加載到RUNTIME,並保存到disk。
load mysql servers to runtime; save mysql servers to disk;
<a name="blog1.3333"></a>
添加節點以後,還須要監控後端節點。對於後端是主從複製的環境來講,這是必須的,由於ProxySQL須要經過每一個節點的read_only
值來自動調整它們是屬於讀組仍是寫組。
首先在後端master節點上建立一個用於監控的用戶名(只需在master上建立便可,由於會複製到slave上),這個用戶名只需具備USAGE
權限便可。若是還須要監控複製結構中slave是否嚴重延遲於master(先混個眼熟:這個俗語叫作"拖後腿",術語叫作"replication lag"),則還需具有replication client
權限。這裏直接賦予這個權限。
# 在master上執行: mysql> create user monitor@'192.168.100.%' identified by 'P@ssword1!'; mysql> grant replication client on *.* to monitor@'192.168.100.%';
而後回到ProxySQL上配置監控。
set mysql-monitor_username='monitor'; set mysql-monitor_password='P@ssword1!';
以上設置其實是在修改global_variables表,它和下面兩個語句是等價的:
UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username'; UPDATE global_variables SET variable_value='P@ssword1!' WHERE variable_name='mysql-monitor_password';
修改後,加載到RUNTIME,並保存到disk。
load mysql variables to runtime; save mysql variables to disk;
驗證監控結果:ProxySQL監控模塊的指標都保存在monitor庫的log表中。
如下是鏈接是否正常的監控(對connect指標的監控):(在前面可能會有不少connect_error,這是由於沒有配置監控信息時的錯誤,配置後若是connect_error的結果爲NULL則表示正常)
admin> select * from mysql_server_connect_log; +----------------+------+------------------+-------------------------+---------------+ | hostname | port | time_start_us | connect_success_time_us | connect_error | +----------------+------+------------------+-------------------------+---------------+ | 192.168.100.22 | 3306 | 1530968712977867 | 4174 | NULL | | 192.168.100.23 | 3306 | 1530968712988986 | 4908 | NULL | | 192.168.100.24 | 3306 | 1530968713000074 | 3044 | NULL | | 192.168.100.22 | 3306 | 1530968772978982 | 3407 | NULL | | 192.168.100.23 | 3306 | 1530968772989627 | 3404 | NULL | | 192.168.100.24 | 3306 | 1530968773000778 | 3444 | NULL | +----------------+------+------------------+-------------------------+---------------+
如下是對心跳信息的監控(對ping指標的監控):
admin> select * from mysql_server_ping_log; +----------------+------+------------------+----------------------+-------------+ | hostname | port | time_start_us | ping_success_time_us | ping_error | +----------------+------+------------------+----------------------+-------------+ | 192.168.100.22 | 3306 | 1530968712666540 | 452 | NULL | | 192.168.100.23 | 3306 | 1530968712668779 | 458 | NULL | | 192.168.100.24 | 3306 | 1530968712671541 | 324 | NULL | | 192.168.100.22 | 3306 | 1530968722667071 | 1190 | NULL | | 192.168.100.23 | 3306 | 1530968722669574 | 1162 | NULL | | 192.168.100.24 | 3306 | 1530968722673162 | 1380 | NULL | | 192.168.100.22 | 3306 | 1530968732668840 | 1065 | NULL | | 192.168.100.23 | 3306 | 1530968732670709 | 1054 | NULL | | 192.168.100.24 | 3306 | 1530968732672703 | 1040 | NULL | +----------------+------+------------------+----------------------+-------------+
可是,read_only和replication_lag的監控日誌都爲空。
admin> select * from mysql_server_read_only_log; Empty set (0.00 sec) admin> select * from mysql_server_replication_lag_log; Empty set (0.00 sec)
這是由於尚未對ProxySQL中的節點分組:writer_hostgroup、reader_hostgroup。設置分組信息,須要修改的是main庫中的mysql_replication_hostgroups表,該表只有3個字段:第一個字段名爲writer_hostgroup,第二個字段爲reader_hostgroup,第三個字段爲註釋字段,可隨意寫。
例如,指定寫組的id爲10,讀組的id爲20。
insert into mysql_replication_hostgroups values(10,20);
在該配置加載到RUNTIME生效以前,先查看下各mysql server所在的組。
admin> select hostgroup_id,hostname,port,status,weight from mysql_servers; +--------------+----------------+------+--------+--------+ | hostgroup_id | hostname | port | status | weight | +--------------+----------------+------+--------+--------+ | 10 | 192.168.100.22 | 3306 | ONLINE | 1 | | 10 | 192.168.100.23 | 3306 | ONLINE | 1 | | 10 | 192.168.100.24 | 3306 | ONLINE | 1 | +--------------+----------------+------+--------+--------+
3個節點都在hostgroup_id=10的組中。
如今,將剛纔mysql_replication_hostgroups
表的修改加載到RUNTIME生效。
load mysql servers to runtime; save mysql servers to disk;
一加載,Monitor模塊就會開始監控後端的read_only值,當監控到read_only值後,就會按照read_only的值將某些節點自動移動到讀/寫組。
例如,此處全部節點都在id=10
的寫組,slave1和slave2都是slave,它們的read_only=1,這兩個節點將會移動到id=20
的組。若是一開始這3節點都在id=20
的讀組,那麼移動的將是Master節點,會移動到id=10
的寫組。
看結果:
admin> select hostgroup_id,hostname,port,status,weight from mysql_servers; +--------------+----------------+------+--------+--------+ | hostgroup_id | hostname | port | status | weight | +--------------+----------------+------+--------+--------+ | 10 | 192.168.100.22 | 3306 | ONLINE | 1 | | 20 | 192.168.100.23 | 3306 | ONLINE | 1 | | 20 | 192.168.100.24 | 3306 | ONLINE | 1 | +--------------+----------------+------+--------+--------+
admin> select * from mysql_server_read_only_log; +----------------+------+------------------+-----------------+-----------+--------+ | hostname | port | time_start_us | success_time_us | read_only | error | +----------------+------+------------------+-----------------+-----------+--------+ | 192.168.100.22 | 3306 | 1530970372197917 | 8487 | 0 | NULL | | 192.168.100.23 | 3306 | 1530970372198992 | 7907 | 1 | NULL | | 192.168.100.24 | 3306 | 1530970372199835 | 8064 | 1 | NULL | | 192.168.100.22 | 3306 | 1530970373698824 | 10078 | 0 | NULL | | 192.168.100.23 | 3306 | 1530970373699825 | 9845 | 1 | NULL | | 192.168.100.24 | 3306 | 1530970373700786 | 10745 | 1 | NULL | +----------------+------+------------------+-----------------+-----------+--------+
<a name="blog1.4444"></a>
上面的全部配置都是關於後端MySQL節點的,如今能夠配置關於SQL語句的,包括:發送SQL語句的用戶、SQL語句的路由規則、SQL查詢的緩存、SQL語句的重寫等等。
本小節是SQL請求所使用的用戶配置,例如root用戶。這要求咱們須要先在後端MySQL節點添加好相關用戶。這裏以root和sqlsender兩個用戶名爲例。
首先,在master節點上執行:(只需master執行便可,會複製給兩個slave)
grant all on *.* to root@'192.168.100.%' identified by 'P@ssword1!'; grant all on *.* to sqlsender@'192.168.100.%' identified by 'P@ssword1!';
而後回到ProxySQL,配置mysql_users表,將剛纔的兩個用戶添加到該表中。
insert into mysql_users(username,password,default_hostgroup) values('root','P@ssword1!',10); insert into mysql_users(username,password,default_hostgroup) values('sqlsender','P@ssword1!',10); load mysql users to runtime; save mysql users to disk;
mysql_users表有很多字段,最主要的三個字段爲username
、password
和default_hostgroup
:
select password(PASSWORD)
,而後將加密結果複製到該字段。hostgroup_id=10
組中的某個節點。admin> select * from mysql_users\G *************************** 1. row *************************** username: root password: P@ssword1! active: 1 # 注意本行 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 *************************** 2. row *************************** username: sqlsender password: P@ssword1! active: 1 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
雖然本文不詳細介紹mysql_users表,但上面標註了"注意本行"的兩個字段必需要引發注意。
只有active=1
的用戶纔是有效的用戶。
至於transaction_persistent
字段,當它的值爲1時,表示事務持久化:當某鏈接使用該用戶開啓了一個事務後,那麼在事務提交/回滾以前,全部的語句都路由到同一個組中,避免語句分散到不一樣組(更進一步的,它會自動禁用multiplexing,讓同一個事務的語句從同一個鏈接路由出去,保證路由到同一個組的同一個節點)。在之前的版本中,默認值爲0,不知道從哪一個版本開始,它的默認值爲1。咱們指望的值爲1,因此在繼續下面的步驟以前,先查看下這個值,若是爲0,則執行下面的語句修改成1。
update mysql_users set transaction_persistent=1 where username='root'; update mysql_users set transaction_persistent=1 where username='sqlsender'; load mysql users to runtime; save mysql users to disk;
而後,另開一個終端,分別使用root用戶和sqlsender用戶測試下它們是否能路由到默認的hostgroup_id=10
(它是一個寫組)讀、寫數據。
[root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e "select @@server_id" +-------------+ | @@server_id | +-------------+ | 110 | +-------------+ [root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e "create database proxy_test" [root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e "show databases;" +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | proxy_test | | sys | +--------------------+ [root@s1 ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e '\ use proxy_test;\ create table t(id int);' [root@s1 ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'show tables from proxy_test;' +-------------------------+ | Tables_in_proxy_test | +-------------------------+ | t | +-------------------------+
<a name="blog1.5555"></a>
ProxySQL的路由規則很是靈活,能夠基於用戶、基於schema以及基於每一個語句實現路由規則的定製。
本文做爲入門文章,實現一個最簡單的語句級路由規則,從而實現讀寫分離。必須注意,這只是實驗,實際的路由規則毫不應該僅根據所謂的讀、寫操做進行分離,而是從各項指標中找出壓力大、執行頻繁的語句單獨寫規則、作緩存等等。
和查詢規則有關的表有兩個:mysql_query_rules
和mysql_query_rules_fast_routing
,後者是前者的擴展表,1.4.7以後才支持該快速路由表。本文只介紹第一個表。
插入兩個規則,目的是將select語句分離到hostgroup_id=20
的讀組,但因爲select語句中有一個特殊語句SELECT...FOR UPDATE
它會申請寫鎖,因此應該路由到hostgroup_id=10
的寫組。
insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',10,1), (2,1,'^SELECT',20,1); load mysql query rules to runtime; save mysql query rules to disk;
select ... for update
規則的rule_id必需要小於普通的select規則的rule_id,由於ProxySQL是根據rule_id的順序進行規則匹配的。
再來測試下,讀操做是否路由給了hostgroup_id=20
的讀組。
[root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e 'select @@server_id' mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@server_id | +-------------+ | 120 | +-------------+ [root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e 'select @@server_id' mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@server_id | +-------------+ | 130 | +-------------+
讀操做已經路由給讀組,再看看寫操做。這裏以事務持久化進行測試。
[root@s1 ~]# mysql -uroot -pP@ssword1! -P6033 -h127.0.0.1 -e '\ start transaction;\ select @@server_id;\ commit;\ select @@server_id;' +-------------+ | @@server_id | +-------------+ | 110 | +-------------+ +-------------+ | @@server_id | +-------------+ | 120 | +-------------+
顯然,一切都按照預期進行。
最後,若是想查看路由的信息,可查詢stats庫中的stats_mysql_query_digest
表。如下是該表的一個輸出格式示例(和本文無關)。
admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC; +----+----------+------------+-------------------------------------------------------------+ | hg | sum_time | count_star | digest_text | +----+----------+------------+-------------------------------------------------------------+ | 2 | 14520738 | 50041 | SELECT c FROM sbtest1 WHERE id=? | | 1 | 3142041 | 5001 | COMMIT | | 1 | 2270931 | 5001 | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+? ORDER BY c | | 1 | 2021320 | 5003 | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+? | | 1 | 1768748 | 5001 | UPDATE sbtest1 SET k=k+? WHERE id=? | | 1 | 1697175 | 5003 | SELECT SUM(K) FROM sbtest1 WHERE id BETWEEN ? AND ?+? | | 1 | 1346791 | 5001 | UPDATE sbtest1 SET c=? WHERE id=? | | 1 | 1263259 | 5001 | DELETE FROM sbtest1 WHERE id=? | | 1 | 1191760 | 5001 | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?) | | 1 | 875343 | 5005 | BEGIN | +----+----------+------------+-------------------------------------------------------------+
至此,MySQL的讀寫分離嚐鮮結束。該系列後面的文章將詳細介紹ProxySQL的各個方面。