1. 程式人生 > 實用技巧 >使用ProxySQL實現MySQL Group Replication的故障轉移、讀寫分離(二)

使用ProxySQL實現MySQL Group Replication的故障轉移、讀寫分離(二)

在上一篇文章《使用ProxySQL實現MySQL Group Replication的故障轉移、讀寫分離(一) 》 中,已經完成了MGR+ProxySQL叢集的搭建,也測試了ProxySQL實現業務層面的故障轉移,接下來繼續測試讀寫分離。


王國維大師筆下的人生三境界:

第一重境界:昨夜西風凋碧樹。獨上高樓,望盡天涯路;
第二重境界:衣帶漸寬終不悔,為伊消得人憔悴;
第三重境界:眾裡尋他千百度,驀然回首,那人卻在燈火闌珊處。

作為一個一根筋的學渣程式設計師,我還沒能想透徹。但是資料庫讀寫分離的三境界卻有了一定的瞭解,我們不妨來看一看MySQL資料庫讀寫分離的三境界。

第一重境界:人工實現讀寫分離。通過IP、埠讀寫分離,業務層面人工識別讀寫語句,然後將其分配到不同的主機,實現讀寫分離;
第二重境界:正則實現讀寫分離。通過路由中介軟體識別SQL語句,通過正則表示式匹配SQL語句,然後根據匹配結果分發到不同的主機;
第三重境界:識別TOP SQL,將高負載SQL分發到不同的主機;


(一)第一境界:人工實現讀寫分離

通過IP、埠讀寫分離,業務層面人工識別讀寫語句,然後使用不同的連線資料庫配置資訊,將其分配到不同的主機,實現讀寫分離。在ProxySQL裡面,我們是通過埠來實現讀寫分離的。具體操作如下:

STEP1:配置ProxySQL在兩個埠上偵聽,並且重新啟動ProxySQL

mysql -uadmin -padmin -h127.0.0.1 -P6032
mysql> SET mysql-interfaces='0.0.0.0:6401;0.0.0.0:6402';
-- save it on disk and restart proxysql
mysql> SAVE MYSQL VARIABLES TO
DISK; mysql> PROXYSQL RESTART;

STEP2:配置路由規則,通過埠將請求分發到不同的組

mysql> INSERT INTO mysql_query_rules (rule_id,active,proxy_port,destination_hostgroup,apply) VALUES (1,1,6401,10,1), (3,1,6402,20,1);
mysql> LOAD MYSQL QUERY RULES TO RUNTIME;
mysql> SAVE MYSQL QUERY RULES TO DISK;

這樣,通過6401埠訪問資料庫的請求就會被轉發到組1(寫組)中,通過6402埠訪問資料庫的請求會被轉發到組3(讀組)中,從而實現讀寫分離,具體使用6401埠還是6402埠訪問資料庫,取決於開發人員人工識別SQL的讀寫特性。


(二)第二境界:使用正則表示式實現讀寫分離

通過路由中介軟體識別SQL語句,通過正則表示式匹配SQL語句,然後根據匹配結果分發到不同的主機。操作過程如下

STEP1:為避免干擾測試,刪除之前定義的規則

DELETE FROM mysql_query_rules;

STEP2:定義新的讀寫分離規則

INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(1,1,'^SELECT.*FOR UPDATE$',1,1);
INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(2,1,'^SELECT',3,1);

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

現在,ProxySQL的路由規則為:

  • SELECT FOR UPDATE操作將被路由到組1(寫組);
  • 其它的SELECT語句將被路由到組3(讀組);
  • 其它的路由到預設組,即組1。



這裡對使用正則表示式方式進行測試,整個過程如下:

(1)測試之前讀寫組資訊修改

-- 根據組的規則:最多1個寫節點,其餘的寫節點放入備用寫組。目前我們可以看到節點192.168.10.13是寫節點,其餘2個節點是備用寫節點,沒有讀節點
mysql> select * from mysql_group_replication_hostgroups;
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| writer_hostgroup | backup_writer_hostgroup | reader_hostgroup | offline_hostgroup | active | max_writers | writer_is_also_reader | max_transactions_behind | comment |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| 1                | 2                       | 3                | 4                 | 1      | 1           | 0                     | 100                     | NULL    |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
1 row in set (0.00 sec)

mysql> mysql> 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            | 192.168.10.13 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 192.168.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.01 sec)


-- 為了實現讀寫分離,需要有讀節點,我們可以修改writer_is_also_reader引數,讓backup_writer_hostgroup中的節點既做備用寫節點,又做讀節點
mysql> update  mysql_group_replication_hostgroups set writer_is_also_reader = 2 ;
Query OK, 1 row affected (0.00 sec)

mysql> select * from mysql_group_replication_hostgroups;
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| writer_hostgroup | backup_writer_hostgroup | reader_hostgroup | offline_hostgroup | active | max_writers | writer_is_also_reader | max_transactions_behind | comment |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| 1                | 2                       | 3                | 4                 | 1      | 1           | 2                     | 100                     | NULL    |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
1 row in set (0.00 sec)

mysql> 
mysql> select * from runtime_mysql_group_replication_hostgroups;
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| writer_hostgroup | backup_writer_hostgroup | reader_hostgroup | offline_hostgroup | active | max_writers | writer_is_also_reader | max_transactions_behind | comment |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| 1                | 2                       | 3                | 4                 | 1      | 1           | 0                     | 100                     | NULL    |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
1 row in set (0.00 sec)


--需要生效、永久儲存mysql server配置
mysql> load mysql servers to runtime;
Query OK, 0 rows affected (0.01 sec)

mysql> save mysql servers to disk;
Query OK, 0 rows affected (0.03 sec)


mysql> select * from runtime_mysql_group_replication_hostgroups;
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| writer_hostgroup | backup_writer_hostgroup | reader_hostgroup | offline_hostgroup | active | max_writers | writer_is_also_reader | max_transactions_behind | comment |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
| 1                | 2                       | 3                | 4                 | 1      | 1           | 2                     | 100                     | NULL    |
+------------------+-------------------------+------------------+-------------------+--------+-------------+-----------------------+-------------------------+---------+
1 row in set (0.01 sec)


-- 最終mysql server的組資訊如下
mysql> 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            | 192.168.10.13 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 3            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 3            | 192.168.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 192.168.10.11 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 192.168.10.12 | 3306 | 0         | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
5 rows in set (0.00 sec)


(2)匯入規則

-- 為避免測試干擾,先刪除之前的規則
DELETE FROM mysql_query_rules;

-- 匯入規則
INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(1,1,'^SELECT.*FOR UPDATE$',1,1);
INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(2,1,'^SELECT',3,1);

-- 生效、儲存規則
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;


(3)測試規則是否生效

測試SQL語句:

mysql -uusera -p123456 -h192.168.10.10 -P6033 

-- 寫測試
insert into testdb.test01 values(3,'c');

-- 讀測試
SELECT * from testdb.test01;

-- 正則大小寫測試
select * from testdb.test01;

-- select for update測試
SELECT * from testdb.test01 FOR UPDATE;
select * from testdb.test01 FOR UPDATE;

exit;

ProxySQL將SQL語句分發到哪一臺主機上執行,可以檢視統計檢視:stats_mysql_query_digest和stats_mysql_query_digest_reset。兩個表的內容和結構相同,但是查詢stats_mysql_query_digest_reset表會自動將內部統計資訊重置為零,即執行了stats_mysql_query_digest_reset的查詢後,2個表的資料都會被完全清除。這裡我們直接使用stats_mysql_query_digest_reset來查詢上面的測試:

mysql> select hostgroup,schemaname,username,digest_text,count_star from   stats_mysql_query_digest_reset;
+-----------+--------------------+----------+----------------------------------------+------------+
| hostgroup | schemaname         | username | digest_text                            | count_star |
+-----------+--------------------+----------+----------------------------------------+------------+
| 1         | information_schema | usera    | SELECT * from testdb.test01 FOR UPDATE | 1          |
| 3         | information_schema | usera    | select * from testdb.test01            | 1          |
| 3         | information_schema | usera    | SELECT * from testdb.test01            | 1          |
| 1         | information_schema | usera    | select * from testdb.test01 FOR UPDATE | 1          |
| 1         | information_schema | usera    | insert into testdb.test01 values(?,?)  | 1          |
| 1         | information_schema | usera    | select @@version_comment limit ?       | 1          |
+-----------+--------------------+----------+----------------------------------------+------------+
6 rows in set (0.00 sec)

可以看到,正則表示式規則不區分大小寫,並且根據匹配規則,已經將SQL發到了對應的主機上執行。

個人覺得基於正則表示式路由SQL語句到不同主機執行已經十分智慧了,然而ProxySQL官方並不建議這麼幹,因為我們無法準確知道各型別的SQL語句的開銷,從而可能會導致流量分佈不均。

接下來我們來看看ProxySQL推薦的方法,基於正則表示式和摘要進行讀寫拆分。


(三)第三境界:使用正則表示式和digest實現讀寫分離

以下是ProxySQL推薦的有效設定讀寫分離的配置過程:
(1)配置ProxySQL以將所有流量僅傳送到一個MySQL主節點,寫和讀都發送到一個節點;
(2)檢查stats_mysql_query_digest哪些是最昂貴的SELECT語句;
(3)確定哪些昂貴的語句應移至讀節點;
(4)配置mysql_query_rules(建立規則)以僅將昂貴的SELECT語句傳送給讀者

總之,想法非常簡單:僅傳送那些你想傳送的SQL給讀節點,而不是傳送所有SELECT語句。

我們來整理一下整個過程:

STEP1:去除規則,讓所有SQL語句都在預設組上執行

mysql> delete from mysql_query_rules;
Query OK, 2 rows affected (0.00 sec)

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

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


STEP2:查詢最昂貴的SQL

假設目前所有讀寫操作都在同一臺機器上執行,且執行了很久,讀寫比例都具有代表性,我們可以使用stats_mysql_query_digest查詢最昂貴的SQL,可以多維度進行查詢。

(1)查詢查詢總耗時最多的5個SQL

mysql> SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY sum_time DESC LIMIT 5;
+--------------------+--------------------------+------------+----------+
| digest             | SUBSTR(digest_text,0,25) | count_star | sum_time |
+--------------------+--------------------------+------------+----------+
| 0xBF001A0C13781C1D | SELECT c FROM sbtest1 WH | 9594       | 9837782  |
| 0xC4771449056AB3AC | SELECT c FROM sbtest14 W | 9984       | 9756595  |
| 0xD84E4E04982951C1 | SELECT c FROM sbtest9 WH | 9504       | 9596185  |
| 0x9B090963F41AD781 | SELECT c FROM sbtest10 W | 9664       | 9530433  |
| 0x9AF59B998A3688ED | SELECT c FROM sbtest2 WH | 9744       | 9513180  |
+--------------------+--------------------------+------------+----------+
5 rows in set (0.00 sec)


(2)檢視執行次數最多的5個SQL語句

mysql> SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY count_star DESC LIMIT 5;
+--------------------+--------------------------+------------+----------+
| digest             | SUBSTR(digest_text,0,25) | count_star | sum_time |
+--------------------+--------------------------+------------+----------+
| 0xC4771449056AB3AC | SELECT c FROM sbtest14 W | 9984       | 9756595  |
| 0x9AF59B998A3688ED | SELECT c FROM sbtest2 WH | 9744       | 9513180  |
| 0x9B090963F41AD781 | SELECT c FROM sbtest10 W | 9664       | 9530433  |
| 0x03744DC190BC72C7 | SELECT c FROM sbtest5 WH | 9604       | 9343514  |
| 0x1E7B7AC5611F30C2 | SELECT c FROM sbtest6 WH | 9594       | 9245838  |
+--------------------+--------------------------+------------+----------+


(3)檢視平均執行時間最長的5個SQL語句

mysql> SELECT digest,SUBSTR(digest_text,0,25),count_star,sum_time, sum_time/count_star as avg_time FROM stats_mysql_query_digest WHERE digest_text LIKE 'SELECT%' ORDER BY avg_time DESC LIMIT 5;
+--------------------+--------------------------+------------+----------+----------+
| digest             | SUBSTR(digest_text,0,25) | count_star | sum_time | avg_time |
+--------------------+--------------------------+------------+----------+----------+
| 0x0DCAF47B4A363A7A | SELECT * from testdb.tes | 1          | 11400    | 11400    |
| 0x2050E81DB9C7038E | select * from testdb.tes | 1          | 10817    | 10817    |
| 0xF340A73F6EDA5B20 | SELECT c FROM sbtest11 W | 964        | 1726994  | 1791     |
| 0xC867A28C90150A81 | SELECT DISTINCT c FROM s | 929        | 1282699  | 1380     |
| 0x283AA9863F85EFC8 | SELECT DISTINCT c FROM s | 963        | 1318362  | 1369     |
+--------------------+--------------------------+------------+----------+----------+


(4)檢視平均執行時間最長的5個SQL語句,且滿足平均執行時間大於1s,並顯示該SQL執行時間佔所有SQL執行時間的百分比

SELECT  digest,SUBSTR(digest_text,0,25),count_star,sum_time,sum_time/count_star as avg_time,round(sum_time/1000000*100/(SELECT sum(sum_time/1000000) FROM stats_mysql_query_digest ),3) as pct 
FROM    stats_mysql_query_digest 
WHERE   digest_text LIKE 'SELECT%' 
AND     sum_time/count_star > 1000000
ORDER BY avg_time DESC LIMIT 5;

說明:在測試該語句時,是使用sysbench壓測出來的資料,發現存在一個sum_time非常大的SQL,導致在求sum(sum_time)時返回NULL值,故先做了預處理,把sum_time/1000000變為進行計算。


STEP3:結合digest和正則表示式實現路由

我們先觀察一下,未使用路由規則時候的流量分佈,可以看到,所有流量都到了hostgroup1

mysql>  select hostgroup,schemaname,username,digest_text,count_star from   stats_mysql_query_digest_reset;
+-----------+--------------------+----------+---------------------------------------------------------------------+------------+
| hostgroup | schemaname         | username | digest_text                                                         | count_star |
+-----------+--------------------+----------+---------------------------------------------------------------------+------------+
| 1         | information_schema | usera    | SET PROFILING = ?                                                   | 1          |
| 1         | information_schema | usera    | SHOW DATABASES                                                      | 3          |
| 1         | information_schema | usera    | SHOW VARIABLES LIKE ?;                                              | 2          |
| 1         | information_schema | usera    | SET NAMES utf8mb4                                                   | 3          |
| 1         | tssysbench         | usera    | INSERT INTO sbtest15 (id, k, c, pad) VALUES (?, ?, ?, ?)            | 1285       |
| 1         | tssysbench         | usera    | INSERT INTO sbtest14 (id, k, c, pad) VALUES (?, ?, ?, ?)            | 1309       |
| 1         | tssysbench         | usera    | INSERT INTO sbtest13 (id, k, c, pad) VALUES (?, ?, ?, ?)            | 1303       |
| 1         | tssysbench         | usera    | INSERT INTO sbtest12 (id, k, c, pad) VALUES (?, ?, ?, ?)            | 1240       |
| 1         | tssysbench         | usera    | UPDATE sbtest3 SET k=k+? WHERE id=?                                 | 1280       |
| 1         | tssysbench         | usera    | UPDATE sbtest2 SET k=k+? WHERE id=?                                 | 1280       |
| 1         | tssysbench         | usera    | UPDATE sbtest1 SET k=k+? WHERE id=?                                 | 1219       |
| 1         | tssysbench         | usera    | SELECT DISTINCT c FROM sbtest15 WHERE id BETWEEN ? AND ? ORDER BY c | 1207       |
| 1         | tssysbench         | usera    | SELECT DISTINCT c FROM sbtest14 WHERE id BETWEEN ? AND ? ORDER BY c | 1262       |
| 1         | tssysbench         | usera    | SELECT DISTINCT c FROM sbtest11 WHERE id BETWEEN ? AND ? ORDER BY c | 1227       |


插入路由規則:

-- 根據digest插入規則,匹配特定的SQL語句
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(1,1,'0x0DCAF47B4A363A7A',3,1);
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(2,1,'0x63F9BD89D906209B',3,1);
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(3,1,'0x10D8D9CC551E199B',3,1);
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(4,1,'0xC867A28C90150A81',3,1);
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(5,1,'0x283AA9863F85EFC8',3,1);
INSERT INTO mysql_query_rules (rule_id,active,digest,destination_hostgroup,apply) VALUES(6,1,'0x16BD798E66615299',3,1);

-- 根據正則表示式插入規則,匹配所有SELECT 開頭的語句
INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES(7,1,'^SELECT COUNT\(\*\)',3,1);


-- 使規則生效、儲存
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;


STEP4:使用sysbench查詢,再次檢視流量分佈,可以看到,符合路由條件的SQL語句已經轉移到了hostgroup3執行。

mysql> select hostgroup,schemaname,username,digest_text,count_star from   stats_mysql_query_digest_reset;
+-----------+------------+----------+---------------------------------------------------------------------+------------+
| hostgroup | schemaname | username | digest_text                                                         | count_star |
+-----------+------------+----------+---------------------------------------------------------------------+------------+
| 1         | tssysbench | usera    | UPDATE sbtest3 SET k=k+? WHERE id=?                                 | 863        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest14 WHERE id BETWEEN ? AND ? ORDER BY c | 841        |
| 3         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest13 WHERE id BETWEEN ? AND ? ORDER BY c | 765        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest12 WHERE id BETWEEN ? AND ? ORDER BY c | 837        |
| 3         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest11 WHERE id BETWEEN ? AND ? ORDER BY c | 813        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest10 WHERE id BETWEEN ? AND ? ORDER BY c | 861        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest9 WHERE id BETWEEN ? AND ? ORDER BY c  | 835        |
| 3         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest8 WHERE id BETWEEN ? AND ? ORDER BY c  | 823        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest6 WHERE id BETWEEN ? AND ? ORDER BY c  | 834        |
| 1         | tssysbench | usera    | UPDATE sbtest5 SET c=? WHERE id=?                                   | 870        |
| 3         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest4 WHERE id BETWEEN ? AND ? ORDER BY c  | 802        |
| 1         | tssysbench | usera    | UPDATE sbtest1 SET c=? WHERE id=?                                   | 835        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest3 WHERE id BETWEEN ? AND ? ORDER BY c  | 838        |
| 1         | tssysbench | usera    | SELECT DISTINCT c FROM sbtest2 WHERE id BETWEEN ? AND ? ORDER BY c  | 885

至此,以實現根據負載進行流量分發。





================================================================================================================

附1:讀寫分離路由規則表解析

讀寫分離路由解析資訊存放在mysql_query_rules表中,表的語法如下:

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,
    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,
    reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,
    timeout INT UNSIGNED,
    retries INT CHECK (retries>=0 AND retries <=1000),
    delay INT UNSIGNED,
    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)

重要列的含義如下:

  • rule_id :規則的id,是主鍵,具有唯一非空特性,規則匹配時,按照rule_id從小到大匹配;
  • active :規則是否啟用,1代表啟用;
  • username: : 匹配來自特定使用者的流量;
  • client_addr :匹配來自特定客戶端的流量;
  • proxy_addr : 匹配特定本地IP上的傳入流量;
  • proxy_port : 匹配特定本地埠上的傳入流量,具體見上面使用埠進行讀寫分離的方案;
  • digest : 將查詢與特定摘要匹配,每個相同的SQL文字都會生成一個唯一的diagst碼(類似Oracle的sql_id),按照碼進行匹配;
  • match_digest :將查詢摘要與正則表示式匹配;
  • match_pattern:將查詢文字與正則表示式匹配;
  • destination_hostgroup:將匹配的查詢路由到該主機組,除非存在已啟動的事務並且已登入的使用者將transaction_persistent標誌設定為1(請參見表mysql_users),否則將發生這種情況。
  • cache_ttl :查詢結果快取保留的時間(單位:s);
  • timeout :執行匹配或重寫的查詢的最大超時(以毫秒為單位)。如果查詢的執行時間超過特定閾值,則會自動終止該查詢。如果未指定超時,則mysql-default_query_timeout應用全域性變數
  • retries : 在執行查詢檢測到失敗的情況下,重新執行查詢的次數
  • apply : 如果這隻為1,則不再匹配後面的查詢規則。


附2:本次實驗用到的sysbench指令碼

-- 準備階段
sysbench /usr/share/sysbench/oltp_read_write.lua  --mysql-host=192.168.10.10  --mysql-port=6033 --mysql-user=usera  --mysql-password='123456' --mysql-db=tssysbench --db-driver=mysql  --tables=15  --table-size=50000  --report-interval=10 --threads=4  --time=120 prepare

-- 測試階段
sysbench /usr/share/sysbench/oltp_read_write.lua  --mysql-host=192.168.10.10  --mysql-port=6033 --mysql-user=usera  --mysql-password='123456' --mysql-db=tssysbench --db-driver=mysql  --tables=15  --table-size=500000  --report-interval=10 --threads=4 --time=120 run

-- 清除階段
sysbench /usr/share/sysbench/oltp_read_write.lua  --mysql-host=192.168.10.10  --mysql-port=6033 --mysql-user=usera  --mysql-password='123456' --mysql-db=tssysbench --db-driver=mysql  --tables=15  --table-size=500000  --report-interval=10 --threads=4 --time=120 cleanup


【完】