1. 程式人生 > 其它 >ProxySQL(10):讀寫分離方法論

ProxySQL(10):讀寫分離方法論

文章轉載自:https://www.cnblogs.com/f-ck-need-u/p/9318558.html

不同型別的讀寫分離

資料庫中介軟體最基本的功能就是實現讀寫分離,ProxySQL當然也支援。而且ProxySQL支援的路由規則非常靈活,不僅可以實現最簡單的讀寫分離,還可以將讀/寫都分散到多個不同的組,以及實現分庫sharding(分表sharding的規則比較難寫,但也能實現)。

本文只描述通過規則制定的語句級讀寫分離,不討論通過 ip/port, client, username, schemaname 實現的讀寫分離。

下面描述了ProxySQL能實現的常見讀寫分離型別。

最簡單的讀寫分離

這種模式的讀寫分離,嚴格區分後端的master和slave節點,且slave節點必須設定選項read_only=1。在ProxySQL上,分兩個組,一個寫組HG=10,一個讀組HG=20。同時在ProxySQL上開啟monitor模組的read_only監控功能,讓ProxySQL根據監控到的read_only值來自動調整節點放在HG=10(master會放進這個組)還是HG=20(slave會放進這個組)。

這種模式的讀寫分離是最簡單的,只需在mysql_users表中設定使用者的預設路由組為寫組HG=10,並在mysql_query_rules中加上兩條簡單的規則(一個select for update,一個select)即可。

例如,下面實現的就是這種讀寫分離模式。

mysql_replication_hostgroups: 
+------------------+------------------+----------+
| writer_hostgroup | reader_hostgroup | comment  |
+------------------+------------------+----------+
| 10               | 20               | cluster1 |
+------------------+------------------+----------+

mysql_servers: 
+--------------+----------+------+--------+--------+
| hostgroup_id | hostname | port | status | weight |
+--------------+----------+------+--------+--------+
| 10           | master   | 3306 | ONLINE | 1      |
| 20           | slave1   | 3306 | ONLINE | 1      |
| 20           | slave2   | 3306 | ONLINE | 1      |
+--------------+----------+------+--------+--------+

mysql_users: 
+----------+-------------------+
| username | default_hostgroup |
+----------+-------------------+
| root     | 10                |
+----------+-------------------+

mysql_query_rules: 
+---------+-----------------------+----------------------+
| rule_id | destination_hostgroup | match_digest         |
+---------+-----------------------+----------------------+
| 1       | 10                    | ^SELECT.*FOR UPDATE$ |
| 2       | 20                    | ^SELECT              |
+---------+-----------------------+----------------------+

這種讀寫分離模式,在環境較小時能滿足絕大多數需求。但是需求複雜、環境較大時,這種模式就太過死板,因為一切都是monitor模組控制的。

多個讀組或寫組的分離模式

前面那種讀寫分離模式,是通過monitor模組監控read_only來調整的,所以每一個後端叢集必須只能分為一個寫組,一個讀組。

但如果想要區分不同的select,並將不同的select路由到不同的節點上。例如有些查詢語句的開銷非常大,想讓它們獨佔一個節點/組,其它查詢共享一個節點/組,怎麼實現?

例如,下面這種模式。

看上去非常簡單。但是卻能適應各種需求。例如,後端做了分庫,對某庫的查詢要路由到特定的主機組(後文專門分析這種情況)。

至於各個組機組是同一個主從叢集(下圖左邊),還是互相獨立的主從叢集環境(下圖右邊),要看具體的需求,不過這種讀寫分離模式都能應付。

在實現這種模式時,前提是不能開啟monitor模組的read_only監控功能,也不要設定 mysql_replication_hostgroup 表。

例如,下面的配置實現的是上圖左邊的結構:寫請求路由給HG=10,對test1庫的select語句路由給HG=20,其它select路由給HG=30。

mysql_servers: 
+--------------+----------+------+--------+--------+
| hostgroup_id | hostname | port | status | weight |
+--------------+----------+------+--------+--------+
| 10           | host1    | 3306 | ONLINE | 1      |
| 20           | host2    | 3306 | ONLINE | 1      |
| 30           | host3    | 3306 | ONLINE | 1      |
+--------------+----------+------+--------+--------+

mysql_users: 
+----------+-------------------+
| username | default_hostgroup |
+----------+-------------------+
| root     | 10                |
+----------+-------------------+

mysql_query_rules: 
+---------+-----------------------+----------------------+
| rule_id | destination_hostgroup | match_digest         |
+---------+-----------------------+----------------------+
| 1       | 10                    | ^SELECT.*FOR UPDATE$ |
| 2       | 20                    | ^SELECT.*test1\..*   |
| 3       | 30                    | ^SELECT              |
+---------+-----------------------+----------------------+

sharding後的讀寫分離

ProxySQL對sharding的支援比較弱,要寫sharding的路由規則真心覺得有點繁瑣。但無論如何,ProxySQL通過定製路由規則是能實現簡單的sharding的。這也算是讀寫分離的一種情況。

如下圖,將課程所在庫分為三個庫:"MySQL"、"python"和"Linux"。當查詢條件中的篩選條件是MySQL時,就路由給MySQL庫所在的主機組HG=20,篩選條件是Python時,就路由給HG=10,同理HG=30。

找出需要特殊對待的SQL語句

有些SQL語句執行次數較多、效能開銷較大、執行時間較長等等,這幾類語句都需要特殊對待。例如,將它們路由到獨立的節點/主機組,或者為它們開啟快取功能。

本文通過sysbench來模擬,以便為官方手冊裡的這篇文章提供測試環境。當然,如果您會sysbench或其它效能測試工具,可無視。

1.首先建立測試資料庫sbtest。這裡我直接連線到後端的MySQL節點建立庫和表。

mysqladmin -h192.168.100.22 -uroot -pP@ssword1! -P3306 create sbtest;

2.準備測試表,假設以2張表為例,每個表中10W行資料。填充完後,兩張表表名為sbtest1和sbtest2。

SYSBENCH=/usr/share/sysbench/
sysbench --mysql-host=192.168.100.22 \
         --mysql-port=3306 \
         --mysql-user=root \
         --mysql-password=P@ssword1! \
         $SYSBENCH/oltp_common.lua \
         --tables=1 \
         --table_size=100000 \
         prepare

3.sysbench連線到ProxySQL,做只讀測試。注意下面的選項--db-ps-mode必須設定為disable,表示禁止ProxySQL使用prepare statement,目前ProxySQL還不支援對prepare語句的快取。不過ProxySQL作者已經將此功能提上日程了。

sysbench --threads=4 \
         --time=20 \
         --report-interval=5 \
         --mysql-host=127.0.0.1 \
         --mysql-port=6033 \
         --mysql-user=root \
         --mysql-password=P@ssword1! \
         --db-ps-mode=disable \
         $SYSBENCH/oltp_read_only.lua \
         --skip_trx=on \
         --tables=1 \
         --table_size=100000 \
         run

由於這時候還沒有設定sysbench的測試語句的路由,所以它們全都會路由到同一個主機組,例如預設的組。

4.檢視stats_mysql_query_digest表,按照各種測試指標條件進行排序,例如按照總執行時間欄位sum_time降序以便找出最耗時的語句,按照count_star降序排序找出執行次數最多的語句,還可以按照平均執行時間降序等等。請參照上面列出的官方手冊文章。

例如,此處按照sum_time降序排序:

Admin> SELECT count_star,sum_time,digest,digest_text 
       FROM stats_mysql_query_digest 
       ORDER BY sum_time DESC 
       LIMIT 4;
+------------+----------+--------------------+---------------------------------------------+
| count_star | sum_time | digest             | digest_text                                 |
+------------+----------+--------------------+---------------------------------------------+
| 72490      | 17732590 | 0x13781C1DBF001A0C | SELECT c FROM sbtest1 WHERE id=?            |
| 7249       | 9629225  | 0x704822A0F7D3CD60 | SELECT DISTINCT c FROM sbtest1 XXXXXXXXXXXX |
| 7249       | 6650716  | 0xADF3DDF2877EEAAF | SELECT c FROM sbtest1 WHERE id XXXXXXXXXXXX |
| 7249       | 3235986  | 0x7DD56217AF7A5197 | SELECT c FROM sbtest1 WHERE id yyyyyyyyyyyy |
+------------+----------+--------------------+---------------------------------------------+

5.對那些開銷大的語句,制定獨立的路由規則,並決定是否開啟查詢快取以及快取過期時長。
6.寫好規則後進行測試。