ProxySQL官檔翻譯__14_ProxySQL_Configuration

14_ProxySQL_Configuration

備註:文章編寫時間201904-201905期間,後續官方在github的更新沒有被寫入

~
~
如何最簡配置ProxySQL[Mini HOW TO on ProxySQL Configuration]

這個簡單的HOWTO描述瞭如何一步步的配置ProxySQL的一些組件。但注意,這不是一個完整的指南。

假設您已經瞭解ProxySQL體系結構,並且本HOWTO假定使用標準SQL管理界面來重新配置ProxySQL,默認情況下使用簡單(可更改)憑據連接到端口6032:

$ mysql -u admin -padmin -h 127.0.0.1 -P6032

首先,查驗以下表中沒有配置任何內容:mysql_servers、mysql_replication_hostgroups、mysql_query_rules。

mysql> \R Admin>
PROMPT set to 'Admin> '
Admin>
Admin> SELECT * FROM mysql_servers;
Empty set (0.00 sec)

Admin> SELECT * from mysql_replication_hostgroups;
Empty set (0.00 sec)

Admin> SELECT * from mysql_query_rules;
Empty set (0.00 sec)

一、添加後端數據庫服務器[Add backends]

在這個演示中,我使用mysql_sandbox(MySQL沙箱工具https://launchpad.net/mysql-sandbox)在本地啓動了3個MySQL服務器。讓我們把它們添加到ProxySQL中。

Admin> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'127.0.0.1',21891);
Query OK, 1 row affected (0.01 sec)

Admin> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'127.0.0.1',21892);
Query OK, 1 row affected (0.01 sec)

Admin> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (1,'127.0.0.1',21893);
Query OK, 1 row affected (0.00 sec)

Admin> SELECT * FROM mysql_servers;
+--------------+-----------+-------+--------+--------+-------------+-----------------+---------------------+
| hostgroup_id | hostname  | port  | status | weight | compression | max_connections | max_replication_lag |
+--------------+-----------+-------+--------+--------+-------------+-----------------+---------------------+
| 1            | 127.0.0.1 | 21891 | ONLINE | 1      | 0           | 1000            | 0                   |
| 1            | 127.0.0.1 | 21892 | ONLINE | 1      | 0           | 1000            | 0                   |
| 1            | 127.0.0.1 | 21893 | ONLINE | 1      | 0           | 1000            | 0                   |
+--------------+-----------+-------+--------+--------+-------------+-----------------+---------------------+
3 rows in set (0.00 sec)

注意:默認情況下,mysql_sandbox將在slaves上設置read_only = 0。需要手動在slaves上設置set global read_only = 1。

二、配置監控[Configure monitoring]

ProxySQL會經常的監視它爲它配置的後端服務器。爲此,配置一些變量很重要。

1、添加監視後端所需用戶的憑據(需要在MySQL Server中已創建該用戶):

Admin> SELECT * FROM global_variables WHERE variable_name='mysql-monitor_username';
+------------------------+----------------+
| variable_name          | variable_value |
+------------------------+----------------+
| mysql-monitor_username | monitor        |   <==默認值
+------------------------+----------------+
1 row in set (0.00 sec)

Admin> SELECT * FROM global_variables WHERE variable_name='mysql-monitor_password';
+------------------------+----------------+
| variable_name          | variable_value |
+------------------------+----------------+
| mysql-monitor_password | monitor        |   <==默認值
+------------------------+----------------+
1 row in set (0.00 sec)

這裏使用默認值介紹使用方式:

Admin> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.00 sec)

Admin> UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_password';
Query OK, 1 row affected (0.00 sec)

然後我們配置各種監控間隔:

Admin> SELECT * FROM global_variables WHERE variable_name IN ('mysql-monitor_connect_interval','mysql-monitor_ping_interval','mysql-monitor_read_only_interval');
+----------------------------------+----------------+
| variable_name                    | variable_value |
+----------------------------------+----------------+
| mysql-monitor_connect_interval   | 60000          |
| mysql-monitor_ping_interval      | 10000          |
| mysql-monitor_read_only_interval | 1500           |
+----------------------------------+----------------+
3 rows in set (0.00 sec)

Admin> UPDATE global_variables SET variable_value='2000' WHERE variable_name IN ('mysql-monitor_connect_interval','mysql-monitor_ping_interval','mysql-monitor_read_only_interval');
Query OK, 3 rows affected (0.00 sec)

Admin> SELECT * FROM global_variables WHERE variable_name LIKE 'mysql-monitor_%';
+----------------------------------------+---------------------------------------------------+
| variable_name                          | variable_value                                    |
+----------------------------------------+---------------------------------------------------+
| mysql-monitor_history                  | 600000                                            |
| mysql-monitor_connect_interval         | 2000                                              |
| mysql-monitor_connect_timeout          | 200                                               |
| mysql-monitor_ping_interval            | 2000                                              |
| mysql-monitor_ping_timeout             | 100                                               |
| mysql-monitor_read_only_interval       | 2000                                              |
| mysql-monitor_read_only_timeout        | 100                                               |
| mysql-monitor_replication_lag_interval | 10000                                             |
| mysql-monitor_replication_lag_timeout  | 1000                                              |
| mysql-monitor_username                 | monitor                                           |
| mysql-monitor_password                 | monitor                                           |
| mysql-monitor_query_variables          | SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES |
| mysql-monitor_query_status             | SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS    |
| mysql-monitor_query_interval           | 60000                                             |
| mysql-monitor_query_timeout            | 100                                               |
| mysql-monitor_timer_cached             | true                                              |
| mysql-monitor_writer_is_also_reader    | true                                              |
+----------------------------------------+---------------------------------------------------+
17 rows in set (0.00 sec)

在ProxySQL中有很多變量,有些變量尚未使用或與此無關。當前只考慮上邊列出的那些。
表global_variables中與MySQL Monitor相關的更改僅在運行 LOAD MYSQL VARIABLES TO RUNTIME 命令後纔會生效,
並且在運行 SAVE MYSQL VARIABLES TO DISK 後它們纔將永久存儲到磁盤。

Admin> LOAD MYSQL VARIABLES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SAVE MYSQL VARIABLES TO DISK;
Query OK, 110 rows affected (0.02 sec)

三、後端MySQL服務健康檢測[Backend's health check] -- '

現在,讓我們看看ProxySQL是否能夠與這些主機通信。ProxySQL有幾個存儲監視信息的表。

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)

Admin> SHOW TABLES FROM monitor;
+------------------------------------+
| tables                             |
+------------------------------------+
| mysql_server_connect_log           |
| mysql_server_galera_log            |
| mysql_server_group_replication_log |
| mysql_server_ping_log              |
| mysql_server_read_only_log         |
| mysql_server_replication_lag_log   |
+------------------------------------+
6 rows in set (0.00 sec)

並非當前監視器中的所有表都會被使用。現在我們可以使用以下查詢檢查相關表:

Admin> SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 10;
+-----------+-------+------------------+----------------------+---------------+
| hostname  | port  | time_start_us       | connect_success_time | connect_error |
+-----------+-------+------------------+----------------------+---------------+
| 127.0.0.1 | 21891 | 1456968814253432 | 562                  | NULL          |
| 127.0.0.1 | 21892 | 1456968814253432 | 309                  | NULL          |
| 127.0.0.1 | 21893 | 1456968814253432 | 154                  | NULL          |
| 127.0.0.1 | 21891 | 1456968812252146 | 689                  | NULL          |
| 127.0.0.1 | 21892 | 1456968812252146 | 424                  | NULL          |
| 127.0.0.1 | 21893 | 1456968812252146 | 174                  | NULL          |
| 127.0.0.1 | 21891 | 1456968810251585 | 569                  | NULL          |
| 127.0.0.1 | 21892 | 1456968810251585 | 316                  | NULL          |
| 127.0.0.1 | 21893 | 1456968810251585 | 155                  | NULL          |
| 127.0.0.1 | 21891 | 1456968808250762 | 570                  | NULL          |
+-----------+-------+------------------+----------------------+---------------+
10 rows in set (0.00 sec)

Admin> SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start_us DESC LIMIT 10;
+-----------+-------+------------------+-------------------+------------+
| hostname  | port  | time_start_us       | ping_success_time | ping_error |
+-----------+-------+------------------+-------------------+------------+
| 127.0.0.1 | 21891 | 1456968828686787 | 124               | NULL       |
| 127.0.0.1 | 21892 | 1456968828686787 | 62                | NULL       |
| 127.0.0.1 | 21893 | 1456968828686787 | 57                | NULL       |
| 127.0.0.1 | 21891 | 1456968826686385 | 99                | NULL       |
| 127.0.0.1 | 21892 | 1456968826686385 | 46                | NULL       |
| 127.0.0.1 | 21893 | 1456968826686385 | 42                | NULL       |
| 127.0.0.1 | 21891 | 1456968824685162 | 135               | NULL       |
| 127.0.0.1 | 21892 | 1456968824685162 | 61                | NULL       |
| 127.0.0.1 | 21893 | 1456968824685162 | 57                | NULL       |
| 127.0.0.1 | 21891 | 1456968822684689 | 215               | NULL       |
+-----------+-------+------------------+-------------------+------------+
10 rows in set (0.01 sec)

根據上面的結果,我們可以得出結論,所有配置的服務器都是健康的。
這裏需要特別注意是:即使在將表加載到RUNTIME之前,也會根據表mysql_servers的內容執行對connect和ping的監視。
這樣做是有意的:通過這種方式,可以在生產中添加節點之前執行基本運行狀況檢查。

確認後端服務正常後,就可以加載到RUNTIME層進行啓用:

Admin> SELECT * FROM runtime_mysql_servers;
Empty set (0.00 sec)

Admin> LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.01 sec)

Admin> SELECT * FROM runtime_mysql_servers;
+--------------+-----------+---—---+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname  | port  | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 127.0.0.1 | 21891 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 127.0.0.1 | 21892 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 127.0.0.1 | 21893 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)

四、配置MySQL複製架構主機組[MySQL replication hostgroups]

檢查一下監視器模式中的另一個表,monitor.mysql_server_read_only_log:

Admin> SELECT * FROM monitor.mysql_server_read_only_log ORDER BY time_start_us DESC LIMIT 10;
Empty set (0.00 sec)

此表目前爲空。原因是ProxySQL僅檢查在 mysql_replication_hostgroups 中配置的主機組中設定了read_only值的服務器。

查看 mysql_replication_hostgroups ,發現它也是空的:

Admin> SELECT * FROM mysql_replication_hostgroups;
Empty set (0.00 sec)

但是這個表的功能是什麼?使用此表,可以將列出的主機組配置爲成對的讀寫、只讀主機組。ProxySQL將監視指定主機組中所有服務器的read_only值,並根據read_only的值將服務器分配給讀寫或只讀主機組。

例如:
查看該表的表結構:

Admin> SHOW CREATE TABLE mysql_replication_hostgroups \G
*************************** 1. row ***************************
       table: mysql_replication_hostgroups
Create Table: 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')) NOT NULL DEFAULT 'read_only',
    comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup))
1 row in set (0.00 sec)

插入讀寫、只讀組配置信息:

Admin> INSERT INTO mysql_replication_hostgroups(writer_hostgroup,reader_hostgroup,check_type,comment) VALUES (1,2,'read_only','cluster1');
Query OK, 1 row affected (0.00 sec)

讀寫組編號爲1,只讀組編號爲2;

Admin> select * from mysql_replication_hostgroups;
+------------------+------------------+------------+----------+
| writer_hostgroup | reader_hostgroup | check_type | comment  |
+------------------+------------------+------------+----------+
| 1                | 2                | read_only  | cluster1 |
+------------------+------------------+------------+----------+
1 row in set (0.00 sec)

設置完成後,在主機組1或2中配置的所有服務器都將自動移動到正確的主機組(起初我們配置的服務器都在組1中):
1)如果它們的read_only = 0,將被自動移動到主機組1 ;
2)如果它們的read_only = 1,將被自動移動到主機組2 ;

但此時此算法仍未運行,因爲新的配置並未在加載到RUNTIME層:

Admin> select * from mysql_servers;
+--------------+-----------+---—---+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname  | port  | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 127.0.0.1 | 21891 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 127.0.0.1 | 21892 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 1            | 127.0.0.1 | 21893 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)

使用與MYSQL SERVERS相同的LOAD命令加載mysql_replication_hostgroups到RUNTIME層:
事實上,LOAD MYSQL SERVERS TO RUNTIME 會同時處理mysql_servers和mysql_replication_hostgroups表。

Admin> LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

查看MySQL服務分組:

Admin> select * from mysql_servers;
+--------------+-----------+---—---+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname  | port  | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1            | 127.0.0.1 | 21891 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 127.0.0.1 | 21892 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 127.0.0.1 | 21893 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+-----------+----—--+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.00 sec)

等幾秒鐘,再次檢查狀態:

Admin> SELECT * FROM monitor.mysql_server_read_only_log ORDER BY time_start_us DESC LIMIT 10;
+-----------+-------+------------------+--------------+-----------+-------+
| hostname  | port  | time_start_us       | success_time | read_only | error |
+-----------+-------+------------------+--------------+-----------+-------+
| 127.0.0.1 | 21891 | 1456969634783579 | 762          | 0         | NULL  |
| 127.0.0.1 | 21892 | 1456969634783579 | 378          | 1         | NULL  |
| 127.0.0.1 | 21893 | 1456969634783579 | 317          | 1         | NULL  |
| 127.0.0.1 | 21891 | 1456969632783364 | 675          | 0         | NULL  |
| 127.0.0.1 | 21892 | 1456969632783364 | 539          | 1         | NULL  |
| 127.0.0.1 | 21893 | 1456969632783364 | 550          | 1         | NULL  |
| 127.0.0.1 | 21891 | 1456969630783159 | 493          | 0         | NULL  |
| 127.0.0.1 | 21892 | 1456969630783159 | 626          | 1         | NULL  |
| 127.0.0.1 | 21893 | 1456969630783159 | 572          | 1         | NULL  |
| 127.0.0.1 | 21891 | 1456969628782328 | 433          | 0         | NULL  |
+-----------+-------+------------------+--------------+-----------+-------+
10 rows in set (0.01 sec)

ProxySQL正在監視服務器的read_only值。並且還創建了hostgroup2,它從hostgroup1移動了read_only = 1(reader)的服務器。

一切看起來都不錯是時候將配置保存到磁盤:

Admin> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.03 sec)

Admin> SAVE MYSQL VARIABLES TO DISK;
Query OK, 110 rows affected (0.00 sec)

五、設置MySQL Users(連接後端使用)

在mysql_servers中配置服務器之後,還需要配置mysql的用戶。這是使用 mysql_users 表實現的:

Admin> SELECT * FROM mysql_users;
Empty set (0.00 sec)

Admin> SHOW CREATE TABLE mysql_users \G
*************************** 1. row ***************************
       table: mysql_users
Create Table: CREATE TABLE mysql_users (
    username VARCHAR NOT NULL,
    password VARCHAR,
    active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1,
    use_ssl INT CHECK (use_ssl IN (0,1)) NOT NULL DEFAULT 0,
    default_hostgroup INT NOT NULL DEFAULT 0,
    default_schema VARCHAR,
    schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0,
    transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 1,
    fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0,
    backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1,
    frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1,
    max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000,
    comment VARCHAR NOT NULL DEFAULT '',
    PRIMARY KEY (username, backend),
    UNIQUE (username, frontend))
1 row in set (0.00 sec)

該表初始時爲空的。

1)添加後端MySQL上的業務賬號到 mysql_users (確保該賬號在MySQL上已存在):

-- MYSQL上建立用戶

mysql> CREATE DATABASE sbtest ;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX, DROP ON sbtest.* TO 'msandbox'@'188.188.0.%' IDENTIFIED BY '123456'; 
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

Admin> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('root','123456',1);
Query OK, 1 row affected (0.00 sec)

Admin> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('msandbox','123456',1);
Query OK, 1 row affected (0.00 sec)

Admin> SELECT * FROM mysql_users;
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| username | password | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | comment |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| root     | 123456   | 1      | 0       | 1                 | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |         |
| msandbox | 123456   | 1      | 0       | 1                 | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |         |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
2 rows in set (0.00 sec)

對於該表,將大多數字段保留爲默認值。這裏配置的最重要的字段是:username、password、default_hostgroup
用戶名和密碼的含義應該非常清楚。default_hostgroup是主機組,如果特定查詢沒有匹配到查詢規則,則將該特定用戶生成的流量都發往該主機組(稍後將詳細介紹)。

2)再次,將配置加載到RUNTIME層以使其生效,並將其保存到磁盤以使其在重新啓動時保持不變。

Admin> SELECT * FROM runtime_mysql_users;
Empty set (0.00 sec)

Admin> SELECT * FROM runtime_mysql_users;
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| username | password                                  | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | comment |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| root     | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 0       | 1        | 10000           |         |
| msandbox | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 0       | 1        | 10000           |         |
| root     | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 0        | 10000           |         |
| msandbox | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 0        | 10000           |         |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
4 rows in set (0.00 sec)

被添加的每個用戶出現了成對的記錄,這是因爲每個用戶在前端和後端都有一條用戶記錄(ProxySQL使用了後端MySQL的用戶做連接認證);

從RUNTIME層獲取用戶加密碼密碼,更新MEMORY層:

Admin> SAVE MYSQL USERS FROM RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SELECT * FROM runtime_mysql_users;
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| username | password                                  | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | comment |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| root     | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 0       | 1        | 10000           |         |
| msandbox | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 0       | 1        | 10000           |         |
| root     | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 0        | 10000           |         |
| msandbox | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 0        | 10000           |         |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
4 rows in set (0.00 sec)

持久化用戶信息到DISK層:

Admin> SELECT * FROM disk.mysql_users;
Empty set (0.00 sec)

Admin> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.01 sec)

Admin> SELECT * FROM disk.mysql_users;
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| username | password                                  | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections | comment |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
| root     | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 1        | 10000           |         |
| msandbox | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 | 1      | 0       | 1                 |                | 0             | 1                      | 0            | 1       | 1        | 10000           |         |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+---------+
2 rows in set (0.00 sec)

3)我們現在可以嘗試從不同的終端連接(連接端口默認是6033):

[root@localhost ~]# mysql -u msandbox -p123456 -h 188.188.0.71 -P6033 -e "SELECT 1"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---+
| 1 |
+---+
| 1 |
+---+

注意:連接端口默認是6033,不是6032(ProxySQL管理端口)也不是3306(MySQL端口)。

[root@localhost ~]# mysql -u msandbox -p123456 -h 188.188.0.71 -P6033 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  21891 |
+--------+

這裏查詢出了後端MySQL服務的端口。

它似乎有效,並且毫不奇怪,查詢被髮送到偵聽端口21891上的服務器(Master),因爲用戶msandbox的默認組爲hostgroup1,並且當前也沒有針對該用戶的查詢規則可用。

六、功能測試[Functional tests]

現在可以嘗試一些"benchmark"測試,來驗證ProxySQL是否正常運行。

如果已經創建了sysbench表,則可以使用以下命令運行負載測試:
這裏使用 sysbench-1.0.14 進行測試。

-- 測試數據初始
[root@localhost ~]# sysbench oltp_common --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5  prepare

-- 執行讀寫測試
sysbench oltp_read_write --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5 \
--time=200 --histogram --report-interval=10 --db-ps-mode=disable run

備註: 如果設置了--db-ps-mode=disable,則效果爲每個線程始終在一個Session中執行所有SQL;如果不設置,則爲每次執行都新建連接。

在測試過程中你會發現,所有的請求都集中在了Master上,而Slave上卻沒有任何請求到達。

七、ProxySQL信息收集[ProxySQL Statistics]

ProxySQL在stats庫中收集了大量實時統計信息:

Admin> SHOW SCHEMAS;
+-----+---------------+-------------------------------------+
| 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)

Admin> 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_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        |
+--------------------------------------+
18 rows in set (0.00 sec)

stats架構中有很多表。我們將對它們進行分析。

1、表 stats.stats_mysql_connection_pool

Admin> SELECT * FROM stats.stats_mysql_connection_pool;
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
| hostgroup | srv_host  | srv_port | status       | ConnUsed | ConnFree | ConnOK | ConnERR | MaxConnUsed | Queries | Queries_GTID_sync | Bytes_data_sent | Bytes_data_recv | Latency_us |
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
| 1         | 127.0.0.1 | 21891    | ONLINE       | 0        | 4        | 11     | 66      | 5           | 3262254 | 0                 | 156040355       | 6371749875      | 99         |
| 1         | 127.0.0.1 | 21892    | OFFLINE_HARD | 0        | 0        | 0      | 0       | 0           | 0       | 0                 | 0               | 0               | 97         |
| 2         | 127.0.0.1 | 21893    | ONLINE       | 0        | 0        | 0      | 0       | 0           | 0       | 0                 | 0               | 0               | 96         |
| 2         | 127.0.0.1 | 21892    | ONLINE       | 0        | 0        | 0      | 0       | 0           | 0       | 0                 | 0               | 0               | 97         |
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
4 rows in set (0.00 sec)

說明:當前,當服務器被刪除(完全刪除或從主機組中移出)時,它在內部被標記爲"OFFLINE_HARD",而不是真正刪除。這就是爲什麼它將端口21892上的服務器顯示爲主機組1的"OFFLINE_HARD"。
此表返回有關發送到每個服務器的流量的相關信息。正如預期的那樣,所有流量都被髮送到主服務器端口21891上的服務器。

2、表stats_mysql_commands_counters

Admin> SELECT * FROM stats_mysql_commands_counters WHERE Total_cnt;
+--------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+--------+--------+---------+----------+
| Command      | Total_Time_us | Total_cnt | cnt_100us | cnt_500us | cnt_1ms | cnt_5ms | cnt_10ms | cnt_50ms | cnt_100ms | cnt_500ms | cnt_1s | cnt_5s | cnt_10s | cnt_INFs |
+--------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+--------+--------+---------+----------+
| BEGIN        | 60686611      | 163092    | 2550      | 126541    | 24450   | 9549    | 2        | 0        | 0         | 0         | 0      | 0      | 0       | 0        |
| COMMIT       | 651883996     | 163019    | 13        | 3         | 0       | 134329  | 26377    | 2294     | 3         | 0         | 0      | 0      | 0       | 0        |
| CREATE_INDEX | 799325        | 14        | 0         | 4         | 0       | 0       | 0        | 2        | 5         | 3         | 0      | 0      | 0       | 0        |
| CREATE_TABLE | 668337        | 30        | 0         | 9         | 4       | 2       | 1        | 10       | 4         | 0         | 0      | 0      | 0       | 0        |
| DELETE       | 66235607      | 163109    | 66        | 134225    | 21610   | 7137    | 70       | 1        | 0         | 0         | 0      | 0      | 0       | 0        |
| DROP_TABLE   | 130117        | 32        | 0         | 5         | 0       | 18      | 3        | 6        | 0         | 0         | 0      | 0      | 0       | 0        |
| INSERT       | 71401062      | 163144    | 65        | 135608    | 21000   | 6413    | 2        | 2        | 25        | 29        | 0      | 0      | 0       | 0        |
| SELECT       | 973021665     | 2283433   | 2272      | 1695366   | 421243  | 164544  | 7        | 1        | 0         | 0         | 0      | 0      | 0       | 0        |
| UPDATE       | 142844582     | 326280    | 134       | 255645    | 54795   | 15573   | 125      | 8        | 0         | 0         | 0      | 0      | 0       | 0        |
| SHOW         | 8005          | 9         | 0         | 5         | 1       | 3       | 0        | 0        | 0         | 0         | 0      | 0      | 0       | 0        |
+--------------+---------------+-----------+-----------+-----------+---------+---------+----------+----------+-----------+-----------+--------+--------+---------+----------+
10 rows in set (0.00 sec)

表stats_mysql_commands_counters返回有關執行的語句類型和執行時間分佈的詳細信息!

3、表stats_mysql_query_digest

表 stats_mysql_commands_counters 提供了非常有用的信息。我們可以獲得有關已執行查詢的更多詳細信息嗎?表 stats_mysql_query_digest 有助於:

Admin> SELECT * FROM stats_mysql_query_digest ORDER BY sum_time DESC limit 10;
+-----------+------------+----------+----------------+--------------------+--------------------------------------------------------------------+------------+------------+------------+-----------+----------+----------+
| hostgroup | schemaname | username | client_address | digest             | digest_text                                                        | count_star | first_seen | last_seen  | sum_time  | min_time | max_time |
+-----------+------------+----------+----------------+--------------------+--------------------------------------------------------------------+------------+------------+------------+-----------+----------+----------+
| 1         | sbtest     | msandbox |                | 0x695FBF255DBEB0DD | COMMIT                                                             | 163019     | 1556684776 | 1556685389 | 651883996 | 96       | 57674    |
| 1         | sbtest     | msandbox |                | 0xBF001A0C13781C1D | SELECT c FROM sbtest1 WHERE id=?                                   | 328166     | 1556684776 | 1556685389 | 112340379 | 83       | 4543     |
| 1         | sbtest     | msandbox |                | 0x0250CB4007721D69 | SELECT c FROM sbtest3 WHERE id=?                                   | 327446     | 1556684776 | 1556685389 | 112260374 | 82       | 4517     |
| 1         | sbtest     | msandbox |                | 0x03744DC190BC72C7 | SELECT c FROM sbtest5 WHERE id=?                                   | 327416     | 1556684776 | 1556685389 | 111997649 | 83       | 11095    |
| 1         | sbtest     | msandbox |                | 0x9AF59B998A3688ED | SELECT c FROM sbtest2 WHERE id=?                                   | 324866     | 1556684776 | 1556685389 | 111375893 | 86       | 9565     |
| 1         | sbtest     | msandbox |                | 0x9D058B6F3BC2F754 | SELECT c FROM sbtest4 WHERE id=?                                   | 322922     | 1556684776 | 1556685389 | 110558550 | 80       | 9678     |
| 1         | sbtest     | msandbox |                | 0xFAD1519E4760CBDE | BEGIN                                                              | 163092     | 1556684776 | 1556685389 | 60686611  | 61       | 5466     |
| 1         | sbtest     | msandbox |                | 0x44BCB144058686EB | SELECT DISTINCT c FROM sbtest3 WHERE id BETWEEN ? AND ? ORDER BY c | 32783      | 1556684776 | 1556685389 | 35102860  | 112      | 2626     |
| 1         | sbtest     | msandbox |                | 0x283AA9863F85EFC8 | SELECT DISTINCT c FROM sbtest4 WHERE id BETWEEN ? AND ? ORDER BY c | 32563      | 1556684776 | 1556685389 | 35056979  | 86       | 6810     |
| 1         | sbtest     | msandbox |                | 0x847CD40BA8EA5175 | SELECT DISTINCT c FROM sbtest5 WHERE id BETWEEN ? AND ? ORDER BY c | 32695      | 1556684776 | 1556685389 | 34881271  | 87       | 3293     |
+-----------+------------+----------+----------------+--------------------+--------------------------------------------------------------------+------------+------------+------------+-----------+----------+----------+
10 rows in set (0.01 sec)

在這裏太多的信息使得格式化現實很困難。讓我們只獲得重要的幾個指標:

Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC limit 10;
+----+-----------+------------+--------------------------------------------------------------------+
| hg | sum_time  | count_star | digest_text                                                        |
+----+-----------+------------+--------------------------------------------------------------------+
| 1  | 651883996 | 163019     | COMMIT                                                             |
| 1  | 112340379 | 328166     | SELECT c FROM sbtest1 WHERE id=?                                   |
| 1  | 112260374 | 327446     | SELECT c FROM sbtest3 WHERE id=?                                   |
| 1  | 111997649 | 327416     | SELECT c FROM sbtest5 WHERE id=?                                   |
| 1  | 111375893 | 324866     | SELECT c FROM sbtest2 WHERE id=?                                   |
| 1  | 110558550 | 322922     | SELECT c FROM sbtest4 WHERE id=?                                   |
| 1  | 60686611  | 163092     | BEGIN                                                              |
| 1  | 35102860  | 32783      | SELECT DISTINCT c FROM sbtest3 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 35056979  | 32563      | SELECT DISTINCT c FROM sbtest4 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 34881271  | 32695      | SELECT DISTINCT c FROM sbtest5 WHERE id BETWEEN ? AND ? ORDER BY c |
+----+-----------+------------+--------------------------------------------------------------------+
10 rows in set (0.01 sec)

所有流量都將發送到hostgroup1。現在那如何將特定的查詢發送到Slave上呢?繼續下面的查詢規則部分......

八、MySQL查詢規則[MySQL Query Rules]

1、添加查詢規則

表 mysql_query_rules 有很多字段,它是控制通過ProxySQL的流量的一個非常強大的工具。
其表定義如下:

Admin> SHOW CREATE TABLE mysql_query_rules \G
*************************** 1. row ***************************
       table: mysql_query_rules
Create Table: CREATE TABLE mysql_query_rules (
    rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0,
    username VARCHAR,
    schemaname VARCHAR,
    flagIN INT CHECK (flagIN >= 0) NOT NULL DEFAULT 0,
    client_addr VARCHAR,
    proxy_addr VARCHAR,
    proxy_port INT CHECK (proxy_port >= 0 AND proxy_port <= 65535), digest VARCHAR,
    match_digest VARCHAR,
    match_pattern VARCHAR,
    negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0,
    re_modifiers VARCHAR DEFAULT 'CASELESS',
    flagOUT INT CHECK (flagOUT >= 0), replace_pattern VARCHAR CHECK(CASE WHEN replace_pattern IS NULL THEN 1 WHEN replace_pattern IS NOT NULL AND match_pattern IS NOT NULL THEN 1 ELSE 0 END),
    destination_hostgroup INT DEFAULT NULL,
    cache_ttl INT CHECK(cache_ttl > 0),
    cache_empty_result INT CHECK (cache_empty_result IN (0,1)) DEFAULT NULL,
    cache_timeout INT CHECK(cache_timeout >= 0),
    reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,
    timeout INT UNSIGNED CHECK (timeout >= 0),
    retries INT CHECK (retries>=0 AND retries <=1000),
    delay INT UNSIGNED CHECK (delay >=0),
    next_query_flagIN INT UNSIGNED,
    mirror_flagOUT INT UNSIGNED,
    mirror_hostgroup INT UNSIGNED,
    error_msg VARCHAR,
    OK_msg VARCHAR,
    sticky_conn INT CHECK (sticky_conn IN (0,1)),
    multiplex INT CHECK (multiplex IN (0,1,2)),
    gtid_from_hostgroup INT UNSIGNED,
    log INT CHECK (log IN (0,1)),
    apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0,
    comment VARCHAR)
1 row in set (0.00 sec)

現在可以配置ProxySQL將前2個查詢發送給從Slave服務器,將其他所有查詢發送給主服務器。

查看當前設置的查詢規則:

Admin> SELECT * FROM mysql_query_rules ;
Empty set (0.00 sec)

插入查詢規則:

-- 將對sbtest1表的以下2種查詢發送到Slave。
Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (10,1,'msandbox','^SELECT c FROM sbtest1 WHERE id=\?$',2,1);
Query OK, 1 row affected (0.00 sec)

Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (20,1,'msandbox','DISTINCT c FROM sbtest1',2,1);
Query OK, 1 row affected (0.00 sec)

查看插入結果:

Admin> SELECT * FROM mysql_query_rules ;
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| rule_id | active | username | schemaname | flagIN | client_addr | proxy_addr | proxy_port | digest | match_digest                        | match_pattern | negate_match_pattern | re_modifiers | flagOUT | replace_pattern | destination_hostgroup | cache_ttl | cache_empty_result | cache_timeout | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | gtid_from_hostgroup | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| 10      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
| 20      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | DISTINCT c FROM sbtest1             | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
2 rows in set (0.00 sec)

Admin> SELECT rule_id,active,username,match_digest,destination_hostgroup,apply FROM mysql_query_rules ;
+---------+--------+----------+-------------------------------------+-----------------------+-------+
| rule_id | active | username | match_digest                        | destination_hostgroup | apply |
+---------+--------+----------+-------------------------------------+-----------------------+-------+
| 10      | 1      | msandbox | ^SELECT c FROM sbtest1 WHERE id=\?$ | 2                     | 1     |
| 20      | 1      | msandbox | DISTINCT c FROM sbtest1             | 2                     | 1     |
+---------+--------+----------+-------------------------------------+-----------------------+-------+
2 rows in set (0.00 sec)

幾點說明:
1)查詢規則按rule_id順序進行處理;
2)僅處理具有active = 1的規則,即開啓狀態的。
因爲查詢規則是一個非常強大的工具,如果配置錯誤會導致排錯比較困難(我們都喜歡用正則表達式,不是嗎?),默認情況下,active爲0(active = 0)。 在啓用它們之前,應該仔細檢查規則的正則表達式!
3)第一個規則示例使用插入符號(^)和美元符號($):
這些是標記模式開頭和結尾的特殊正則表達式字符。在這種情況下,這意味着match_digest或match_pattern應該與查詢完全匹配。
4)與第一個規則示例相比,第二個規則示例不使用插入符號或美元:匹配可以在查詢中的任何位置。
5)要特別注意正則表達式,以避免某些規則不應該與它匹配!
6)您可能會注意到問號(?)已轉義。它在正則表達式中具有特殊含義;如上所述,需要對正則表達式語法特別重視!
7)apply = 1表示如果匹配則不會檢查其他規則。

通過上面說明,表 mysql_query_rules 的查詢可以簡化爲如下這樣:

Admin> SELECT match_digest,destination_hostgroup FROM mysql_query_rules WHERE active=1 AND username='msandbox' ORDER BY rule_id;
+-------------------------------------+-----------------------+
| match_digest                        | destination_hostgroup |
+-------------------------------------+-----------------------+
| ^SELECT c FROM sbtest1 WHERE id=\?$ | 2                     |
| DISTINCT c FROM sbtest1             | 2                     |
+-------------------------------------+-----------------------+
2 rows in set (0.00 sec)

對於這兩個特定規則,查詢將被髮送到Slave。如果查詢沒有匹配到規則,則發送到default_hostgroup(對於用戶msandbox,該值爲1)。

2、清空舊的查詢統計記錄

接下來,讓我們重置表stats_mysql_query_digest的內容。爲了實現這一點,我們可以簡單地對stats_mysql_query_digest_reset運行任何查詢即可,例如:

Admin> SELECT * FROM stats_mysql_query_digest_reset LIMIT 1;

查詢 stats_mysql_query_digest_reset 將會以原子方式獲取 stats_mysql_query_digest 表的內容,並截斷它!

3、加載規則到RUNTIME層

現在我們可以在加載查詢規則到RUNTIME層,使其生效:

Admin> SELECT * FROM runtime_mysql_query_rules;
Empty set (0.00 sec)

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SELECT * FROM runtime_mysql_query_rules;
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| rule_id | active | username | schemaname | flagIN | client_addr | proxy_addr | proxy_port | digest | match_digest                        | match_pattern | negate_match_pattern | re_modifiers | flagOUT | replace_pattern | destination_hostgroup | cache_ttl | cache_empty_result | cache_timeout | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | gtid_from_hostgroup | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| 10      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
| 20      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | DISTINCT c FROM sbtest1             | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
2 rows in set (0.00 sec)

4、將查詢規則持久化到DISK層

Admin> SELECT * FROM disk.mysql_query_rules;
Empty set (0.00 sec)

Admin> SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.01 sec)

Admin> SELECT * FROM disk.mysql_query_rules;
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| rule_id | active | username | schemaname | flagIN | client_addr | proxy_addr | proxy_port | digest | match_digest                        | match_pattern | negate_match_pattern | re_modifiers | flagOUT | replace_pattern | destination_hostgroup | cache_ttl | cache_empty_result | cache_timeout | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | gtid_from_hostgroup | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| 10      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
| 20      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | DISTINCT c FROM sbtest1             | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | NULL      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
2 rows in set (0.00 sec)

5、重新執行測試

最後我們重新執行sysbench加載:

-- 執行讀寫測試
sysbench oltp_read_write --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5 \
--time=200 --histogram --report-interval=10 --db-ps-mode=disable run

6、再次查看查詢統計信息

1)表 stats.stats_mysql_connection_pool

Admin> SELECT * FROM stats.stats_mysql_connection_pool;
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
| hostgroup | srv_host  | srv_port | status       | ConnUsed | ConnFree | ConnOK | ConnERR | MaxConnUsed | Queries | Queries_GTID_sync | Bytes_data_sent | Bytes_data_recv | Latency_us |
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
| 1         | 127.0.0.1 | 21891    | ONLINE       | 0        | 4        | 12     | 66      | 5           | 5548772 | 0                 | 250629298       | 11033778165     | 93         |
| 1         | 127.0.0.1 | 21892    | OFFLINE_HARD | 0        | 0        | 0      | 0       | 0           | 0       | 0                 | 0               | 0               | 94         |
| 2         | 127.0.0.1 | 21893    | ONLINE       | 0        | 3        | 3      | 0       | 3           | 140634  | 0                 | 3477406         | 176787576       | 91         |
| 2         | 127.0.0.1 | 21892    | ONLINE       | 0        | 3        | 3      | 0       | 3           | 140419  | 0                 | 3472382         | 176972544       | 94         |
+-----------+-----------+----------+--------------+----------+----------+--------+---------+-------------+---------+-------------------+-----------------+-----------------+------------+
4 rows in set (0.00 sec)

這次組2中的2個MySQL也分配到了查詢。

2)表stats_mysql_query_digest

Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC limit 15;
+----+-----------+------------+--------------------------------------------------------------------+
| hg | sum_time  | count_star | digest_text                                                        |
+----+-----------+------------+--------------------------------------------------------------------+
| 1  | 528005107 | 128310     | COMMIT                                                             |
| 1  | 85388244  | 258648     | SELECT c FROM sbtest3 WHERE id=?                                   |
| 1  | 84775526  | 257258     | SELECT c FROM sbtest5 WHERE id=?                                   |
| 1  | 84527137  | 257098     | SELECT c FROM sbtest4 WHERE id=?                                   |
| 1  | 84271753  | 255208     | SELECT c FROM sbtest2 WHERE id=?                                   |
| 2  | 46785931  | 255528     | SELECT c FROM sbtest1 WHERE id=?                                   |
| 1  | 43321724  | 128379     | BEGIN                                                              |
| 1  | 27591062  | 25737      | SELECT DISTINCT c FROM sbtest2 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 27147997  | 25698      | SELECT DISTINCT c FROM sbtest3 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 27139402  | 25743      | SELECT DISTINCT c FROM sbtest5 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 27046866  | 25702      | SELECT DISTINCT c FROM sbtest4 WHERE id BETWEEN ? AND ? ORDER BY c |
| 2  | 26084914  | 25529      | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 15539338  | 25714      | SELECT c FROM sbtest2 WHERE id BETWEEN ? AND ? ORDER BY c          |
| 1  | 15535214  | 25786      | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c          |
| 1  | 15499890  | 25664      | SELECT c FROM sbtest3 WHERE id BETWEEN ? AND ? ORDER BY c          |
+----+-----------+------------+--------------------------------------------------------------------+
15 rows in set (0.00 sec)

正如所料,2個類型的查詢被髮送到hostgroup2(Slave上)。表stats_mysql_query_digest允許聚合結果,例如:

Admin> SELECT hostgroup hg, SUM(sum_time), SUM(count_star) FROM stats_mysql_query_digest GROUP BY hostgroup;
+----+---------------+-----------------+
| hg | SUM(sum_time) | SUM(count_star) |
+----+---------------+-----------------+
| 1  | 1421564103    | 2286517         |
| 2  | 72870845      | 281057          |
+----+---------------+-----------------+
2 rows in set (0.00 sec)

九、查詢緩存[Query Caching]

ProxySQL的一個流行用途是充當查詢緩存。默認情況下,查詢不會被緩存,但可以在mysql_query_rules中設置cache_ttl(以毫秒爲單位)。
假設我們還要將發送給Slave的所有查詢緩存5秒。

1、修改查詢規則

Admin> UPDATE mysql_query_rules SET cache_ttl=5000 WHERE active=1 AND destination_hostgroup=2;
Query OK, 2 rows affected (0.00 sec)

2、將修改加載到RUNTIME層

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SELECT * FROM runtime_mysql_query_rules;
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| rule_id | active | username | schemaname | flagIN | client_addr | proxy_addr | proxy_port | digest | match_digest                        | match_pattern | negate_match_pattern | re_modifiers | flagOUT | replace_pattern | destination_hostgroup | cache_ttl | cache_empty_result | cache_timeout | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | gtid_from_hostgroup | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
| 10      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | 5000      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
| 20      | 1      | msandbox | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | DISTINCT c FROM sbtest1             | NULL          | 0                    | CASELESS     | NULL    | NULL            | 2                     | 5000      | NULL               | NULL          | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL                | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+-------------------------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+--------------------+---------------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+---------------------+-----+-------+---------+
2 rows in set (0.00 sec)

3、清空舊的查詢統計記錄

Admin> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;
Empty set (0.01 sec)

4、再次執行測試

-- 執行讀寫測試
sysbench oltp_read_write --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5 \
--time=200 --histogram --report-interval=10 --db-ps-mode=disable run

5、查看stats_mysql_query_digest

Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest where digest_text like 'SELECT%sbtest1%' ORDER BY sum_time DESC ;
+----+----------+------------+--------------------------------------------------------------------+
| hg | sum_time | count_star | digest_text                                                        |
+----+----------+------------+--------------------------------------------------------------------+
| 2  | 23806132 | 128797     | SELECT c FROM sbtest1 WHERE id=?                                   |
| 2  | 13463802 | 12767      | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 7612531  | 12616      | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c          |
| 1  | 5591611  | 12755      | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?                     |
| 1  | 5260845  | 12806      | SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?                |
| 2  | 409      | 1          | SELECT DISTINCT c FROM sbtest1 WHERE id=?                          |
| 1  | 216      | 1          | SELECT DISTINCAT c FROM sbtest1 WHERE id=?                         |
| -1 | 0        | 7          | SELECT DISTINCT c FROM sbtest1 WHERE id=?                          |
| -1 | 0        | 24         | SELECT c FROM sbtest1 WHERE id=?                                   |
+----+----------+------------+--------------------------------------------------------------------+
9 rows in set (0.00 sec)

可以發現:
1)它們仍然被髮送到hostgroup2;
2)如果它們出現在查詢緩存中,則不會將它們發送到任何主機組並標記爲特殊的主機組-1;

通過以上實驗,我們可以通過 mysql_query_rules 中的 cache_ttl 來控制內存佔用量和結果集的生命週期:選擇 cache_ttl 是明智地,他直到可以獲得對查詢緩存的更多控制。

特別注意:
目前無法定義查詢緩存使用的最大內存量,也無法強制選擇性地或完全刷新查詢緩存。

十、查詢的改寫[Query Rewrite]

ProxySQL支持多種方式來匹配查詢,如flagIN, username, schemaname。

匹配查詢的最常用方法是編寫與查詢本身的文本相匹配的正則表達式。爲了匹配查詢的文本,ProxySQL提供了2種機制,使用了2個不同的字段:

  • match_digest :針對查詢語句的命令概要(被用?替換掉變量值的SQL語句)的正則表達式;針對的查詢語句文本可以在 stats_mysql_query_digest.query_digest中查看。
  • match_pattern :針對原始SQL文本的正則表達式.

爲什麼會有這些不同的機制?
查詢的摘要可能比查詢本身小得多(例如,具有幾MB數據的INSERT語句),因此對較小的字符串運行正則表達式肯定會更快。因此,如果不需要嘗試匹配查詢中的特定文字,
建議使用match_digest(它更快)。儘管如此,但如果要重寫查詢,則必須與原始查詢匹配(使用match_pattern),因爲它是需要重寫的是原始查詢。

-- 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

1、改寫配置舉例

將同時包含DISTINCT和ORDER BY c的語句改寫成DISTINCT 1的語句:

1)添加查詢規則

Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_pattern,replace_pattern,apply) VALUES (30,1,'msandbox','DISTINCT(.*)ORDER BY c','DISTINCT\1',1);
Query OK, 1 row affected (0.00 sec)

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            | 10000     | 1     |
| 20      | DISTINCT c FROM sbtest1             | NULL                   | NULL            | 10000     | 1     |
| 30      | NULL                                | DISTINCT(.*)ORDER BY c | DISTINCT\1      | NULL      | 1     |
+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
3 rows in set (0.00 sec)

2)加載到RUNTME層

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

3)清空舊的查詢統計記錄

Admin> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;

4)執行測試

-- 執行讀寫測試
sysbench oltp_read_write --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5 \
--time=200 --histogram --report-interval=10 --db-ps-mode=disable run

5)查看stats_mysql_query_digest

Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC limit 10;
+----+-----------+------------+--------------------------------------------------------------------+
| hg | sum_time  | count_star | digest_text                                                        |
+----+-----------+------------+--------------------------------------------------------------------+
| 1  | 262096703 | 65249      | COMMIT                                                             |
| 1  | 42813558  | 133794     | SELECT c FROM sbtest2 WHERE id=?                                   |
| 1  | 41657095  | 130914     | SELECT c FROM sbtest4 WHERE id=?                                   |
| 1  | 41641341  | 130064     | SELECT c FROM sbtest3 WHERE id=?                                   |
| 1  | 41610083  | 129484     | SELECT c FROM sbtest5 WHERE id=?                                   |
| 2  | 23794597  | 128544     | SELECT c FROM sbtest1 WHERE id=?                                   |
| 1  | 21205569  | 65282      | BEGIN                                                              |
| 2  | 13508337  | 13160      | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c |
| 1  | 12705099  | 13233      | SELECT DISTINCT c FROM sbtest2 WHERE id BETWEEN ? AND ?            |
| 1  | 12153358  | 13101      | SELECT DISTINCT c FROM sbtest4 WHERE id BETWEEN ? AND ?            |
+----+-----------+------------+--------------------------------------------------------------------+
10 rows in set (0.00 sec)

看起來有些不對勁,因爲似乎沒有重寫過。這是故意的,所以我們現在可以進行故障排除。

6)規則診斷

對於故障排除有一個非常有用的表就是 stats.stats_mysql_query_rules:

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 |
+------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
| 4    | 10      | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL                   | NULL            | 10000     | 1     |
| 4    | 20      | DISTINCT c FROM sbtest1             | NULL                   | NULL            | 10000     | 1     |
| 16   | 30      | NULL                                | DISTINCT(.*)ORDER BY c | DISTINCT\1      | NULL      | 1     |
+------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
3 rows in set (0.01 sec)

似乎有些不對:帶有rule_id = 30的規則有0次命中!

問題是帶有rule_id = 20的規則也匹配在rule_id = 30中匹配的查詢,而未匹配到規則20的查詢,由於20中設置的apply = 1,這將阻止它們達到規則30。
(因爲apply = 1時,未匹配的查詢將被髮送到默認組處理)

7)修該規則

Admin> UPDATE mysql_query_rules SET apply=0 WHERE rule_id=20;
Query OK, 1 row affected (0.00 sec)

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            | 10000     | 1     |
| 20      | DISTINCT c FROM sbtest1             | NULL                   | NULL            | 10000     | 0     |
| 30      | NULL                                | DISTINCT(.*)ORDER BY c | DISTINCT\1      | NULL      | 1     |
+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
3 rows in set (0.00 sec)

8)將修改後的配置加載到RUNTME層

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SELECT rule_id,apply FROM runtime_mysql_query_rules;
+---------+-------+
| rule_id | apply |
+---------+-------+
| 10      | 1     |
| 20      | 0     |
| 30      | 1     |
+---------+-------+
3 rows in set (0.00 sec)

注意:運行LOAD MYSQL QUERY RULES TO RUNTIME時,不僅會重置內部查詢處理結構,還會重置stats.stats_mysql_query_rules中的計數器。

Admin> SELECT * FROM stats.stats_mysql_query_rules;
+---------+------+
| rule_id | hits |
+---------+------+
| 10      | 0    |
| 20      | 0    |
| 30      | 0    |
+---------+------+
3 rows in set (0.00 sec)

9)清空舊的查詢統計記錄

Admin> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;

10)再次執行測試

-- 執行讀寫測試
sysbench oltp_read_write --mysql_storage_engine=innodb --db-driver=mysql --mysql-host=188.188.0.71 --mysql-port=6033 \
--mysql-user='msandbox' --mysql-password='123456' --mysql-db=sbtest --threads=4 --table_size=10000 --tables=5 \
--time=200 --histogram --report-interval=10 --db-ps-mode=disable run

11)再次查看規則命中情況

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 |
+------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
| 4    | 10      | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL                   | NULL            | 10000     | 1     |
| 4    | 20      | DISTINCT c FROM sbtest1             | NULL                   | NULL            | 10000     | 0     |
| 20   | 30      | NULL                                | DISTINCT(.*)ORDER BY c | DISTINCT\1      | NULL      | 1     |
+------+---------+-------------------------------------+------------------------+-----------------+-----------+-------+
3 rows in set (0.00 sec)

這次規則30被命中了20次,有重寫了,看起來不錯:-)
那查詢執行情況怎麼樣?

12)查看 stats_mysql_query_digest

Admin> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest WHERE digest_text like '%sbtest1%' ORDER BY sum_time DESC;
+----+----------+------------+-------------------------------------------------------------+
| hg | sum_time | count_star | digest_text                                                 |
+----+----------+------------+-------------------------------------------------------------+
| 1  | 6127168  | 4856       | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+? ORDER BY c |
| 2  | 4264263  | 7359       | SELECT c FROM sbtest1 WHERE id=?                            |
| 1  | 4081063  | 4856       | UPDATE sbtest1 SET k=k+? WHERE id=?                         |
| 1  | 3497644  | 4856       | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?+?            |
| 1  | 3270527  | 4856       | DELETE FROM sbtest1 WHERE id=?                              |
| 1  | 3193123  | 4856       | SELECT SUM(K) FROM sbtest1 WHERE id BETWEEN ? AND ?+?       |
| 1  | 3124698  | 4856       | UPDATE sbtest1 SET c=? WHERE id=?                           |
| 1  | 2866474  | 4856       | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)     |
| 2  | 1889996  | 1633       | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ?+?   |
| -1 | 0        | 3223       | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ?+?   |
| -1 | 0        | 41201      | SELECT c FROM sbtest1 WHERE id=?                            |
+----+----------+------------+-------------------------------------------------------------+
11 rows in set (0.00 sec)

注意:
rule_id = 20和rule_id = 30的規則可以合併爲一個規則。這裏把它們被分開是爲了描述應用字段的重要性,並且不僅多個規則可以匹配相同的查詢,而且多個規則可以將設置轉換並應用於同一查詢。

-- 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

2、查詢重寫的幾個例子。

我們想要重寫如下查詢:
將查詢
SELECT c FROM sbtest1 WHERE id=?
轉換爲入:
SELECT c FROM sbtest2 WHERE id=?

但對於ID的值,只知道1000到3999之間的...;這是沒有任何意義的,它只是展示一些潛力,包括一些複雜的分片能力!!
看來得使用正則表達式匹配? :-)

1)添加對應得規則

Admin> INSERT INTO mysql_query_rules (rule_id,active,username,match_pattern,replace_pattern,apply) VALUES (5,1,'msandbox','^SELECT (c) FROM sbtest(1) WHERE id=(1|2|3)(...)$','SELECT c FROM sbtest2 WHERE id=\3\4',1);
Query OK, 1 row affected (0.00 sec)

說明:選擇"c"和"1"(在sbtest1中)只是爲了顯示語法。

2)查看規則添加結果

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 |
+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
| 5       | NULL                                | ^SELECT (c) FROM sbtest(1) WHERE id=(1|2|3)(...)$ | SELECT c FROM sbtest2 WHERE id=\3\4 | NULL      | 1     |
| 10      | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL                                              | NULL                                | 10000     | 1     |
| 20      | DISTINCT c FROM sbtest1             | NULL                                              | NULL                                | 10000     | 0     |
| 30      | NULL                                | DISTINCT(.*)ORDER BY c                            | DISTINCT\1                          | NULL      | 1     |
+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
4 rows in set (0.00 sec)

3)將修改後的配置加載到RUNTME層

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.00 sec)

Admin> SELECT rule_id, match_digest, match_pattern, replace_pattern, cache_ttl, apply FROM runtime_mysql_query_rules ORDER BY rule_id;
+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
| rule_id | match_digest                        | match_pattern                                     | replace_pattern                     | cache_ttl | apply |
+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
| 5       | NULL                                | ^SELECT (c) FROM sbtest(1) WHERE id=(1|2|3)(...)$ | SELECT c FROM sbtest2 WHERE id=\3\4 | NULL      | 1     |
| 10      | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL                                              | NULL                                | 10000     | 1     |
| 20      | DISTINCT c FROM sbtest1             | NULL                                              | NULL                                | 10000     | 0     |
| 30      | NULL                                | DISTINCT(.*)ORDER BY c                            | DISTINCT\1                          | NULL      | 1     |
+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
4 rows in set (0.00 sec)

4)清空舊的查詢統計記錄

Admin> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;

5)再次執行測試

執行由123組成得id:

mysql> SELECT c FROM sbtest1 WHERE id=1123;

它有用嗎?顯然是的:)

6)再次查看規則命中情況

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;
+------+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
| hits | rule_id | match_digest                        | match_pattern                                     | replace_pattern                     | cache_ttl | apply |
+------+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
| 3    | 5       | NULL                                | ^SELECT (c) FROM sbtest(1) WHERE id=(1|2|3)(...)$ | SELECT c FROM sbtest2 WHERE id=\3\4 | NULL      | 1     |
| 7    | 10      | ^SELECT c FROM sbtest1 WHERE id=\?$ | NULL                                              | NULL                                | 10000     | 1     |
| 4    | 20      | DISTINCT c FROM sbtest1             | NULL                                              | NULL                                | 10000     | 0     |
| 20   | 30      | NULL                                | DISTINCT(.*)ORDER BY c                            | DISTINCT\1                          | NULL      | 1     |
+------+---------+-------------------------------------+---------------------------------------------------+-------------------------------------+-----------+-------+
4 rows in set (0.00 sec)

每執行一次測試得查詢語句,規則5得命中就增加1。

十一、將配置持久化到DISK層

將實驗中涉及到的配置,持久化到DISK層。

Admin> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.02 sec)

Admin> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.01 sec)

Admin> SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.02 sec)

~
~
完畢!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章