MySQL Router實現MySQL的讀寫分離


1.簡介

MySQL Router是MySQL官方提供的一個輕量級MySQL中間件,用於取代以前老版本的SQL proxy。

既然MySQL Router是一個數據庫的中間件,那么MySQL Router必須能夠分析來自前面客戶端的SQL請求是寫請求還是讀請求,以便決定這個SQL請求是發送給master還是slave,以及發送給哪個master、哪個slave。這樣,MySQL Router就實現了MySQL的讀寫分離,對MySQL請求進行了負載均衡。

因此,MySQL Router的前提是后端實現了MySQL的主從復制。

MySQL Router很輕量級,只能通過不同的端口來實現簡單的讀/寫分離,且讀請求的調度算法只能使用默認的rr(round-robin),更多一點、更復雜一點的能力都不具備。所以,在實現MySQL Router時,需要自行配置好后端MySQL的高可用。高可用建議通過Percona XtraDB Cluster或MariaDB Galera或MySQL官方的group replication實現,如果實在沒有選擇,還可以通過MHA實現。

所以,一個簡單的MySQL Router部署圖如下。

本文將使用MySQL Router分別實現后端無MySQL主從高可用情形的讀寫分離,至於為什么不實現后端有MySQL高可用的讀寫分離情形。在我看來,MySQL Router只是一個玩具,不僅功能少,而且需要在應用程序代碼中指定讀/寫的不同端口(見后文關於配置文件的解釋),在實際環境中應該沒人會這樣用。

2.配置MySQL Router

以下是實驗環境。

角色名 主機IP MySQL版本 數據狀態
MySQL Router 192.168.0.10 MySQL 8.0.12
master 192.168.0.242 MySQL 8.0.12 全新實例
slave1 192.168.0.240 MySQL 8.0.12 全新實例
slave2 192.168.0.238 MySQL 8.0.12 全新實例

因為后端MySQL主從復制沒有實現高可用,所以只有一個master節點負責寫操作。

所有后端MySQL節點都是剛安裝好的全新MySQL實例,所以直接開啟主從復制即可。如果是已有數據的主從復制,需要先保證它們已同步好,方法見:將slave恢復到master指定的坐標

2.1 安裝MySQL Router

wget https://cdn.mysql.com//Downloads/MySQL-Router/mysql-router-8.0.13-linux-glibc2.12-x86_64.tar.xz

tar xf mysql-router-8.0.13-linux-glibc2.12-x86_64.tar.xz
mv mysql-router-8.0.13-linux-glibc2.12-x86_64 /usr/local/mysqlrouter

這就完了,就這么簡單。

解壓二進制包后,解壓目錄下有以下幾個文件。

[root@s1 mr]# ls
bin  data  include  lib  run  share

bin目錄下只有一個二進制程序mysqlrouter,這也是MySQL Router的主程序。

share目錄下有示例配置文件和示例SysV風格的啟動腳本,但是很不幸該腳本基於debian平台,在redhat系列上需要修改和安裝一些東西才能使用。所以后文我自己寫了一個centos下的SysV腳本。

[root@s1 mr]# ls share/doc/mysqlrouter/
License.txt  README.txt  sample_mysqlrouter.conf  sample_mysqlrouter.init

最后,將主程序添加到PATH環境變量中。

echo "PATH=$PATH:/usr/local/mysqlrouter/bin" >/etc/profile.d/mysqlrouter.sh
chmod +x /etc/profile.d/mysqlrouter.sh
source /etc/profile.d/mysqlrouter.sh

2.2 啟動並測試MySQL Router

以下是上述實驗環境的配置文件,這里只有一個master節點192.168.0.242:3306,如果有多個寫節點(master),則使用逗號分隔各節點。關於配置文件,后文會解釋。

[DEFAULT]
logging_folder =/usr/local/mysqlrouter/run/
plugin_folder =/usr/local/mysqlrouter/lib/mysqlrouter/
runtime_folder =/usr/local/mysqlrouter/run/
config_folder =/usr/local/mysqlrouter/etc/

[logger]
level =debug

[routing:masters]
bind_address = 192.168.0.10:7002
destinations = 192.168.0.242:3306
mode = read-write
connect_timeout = 2

[routing:slaves]
bind_address = 192.168.0.10:7001
destinations = 192.168.0.240:3306,192.168.0.238:3306
mode = read-only
connect_timeout = 1

然后在MySQL Router所在的機器上創建上面使用的目錄。

shell> mkdir /usr/local/mysqlrouter/run/ /usr/local/mysqlrouter/lib/mysqlrouter/ /usr/local/mysqlrouter/etc/

這樣就可以啟動MySQL Router來提供服務了(啟動之前,請確保后端MySQL已被配置好主從復制)。

[root@mysql-proxy etc]# mysqlrouter --config /usr/local/mysqlrouter/etc/mysqlrouter.cnf &
[1] 1506

查看監聽狀態。這里監聽的兩個端口7001和7002是前端連接MySQL Router用的,它們用來接收前端發送的SQL請求,並按照讀、寫規則,將SQL請求路由到后端MySQL主從節點。

[root@mysql-proxy etc]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.11:39668        0.0.0.0:*               LISTEN      -                   
tcp        0      0 192.168.0.10:7001       0.0.0.0:*               LISTEN      1506/mysqlrouter    
tcp        0      0 192.168.0.10:7002       0.0.0.0:*               LISTEN      1506/mysqlrouter    
[root@mysql-proxy etc]# 

查看日志:

[root@mysql-proxy etc]# cat /usr/local/mysqlrouter/run/mysqlrouter.log
2018-11-09 14:19:14 main DEBUG [7f60a856d780] Main logger initialized, logging to '/usr/local/mysqlrouter/run/mysqlrouter.log'
2018-11-09 14:19:14 main INFO [7f60a856d780] Loading all plugins.
2018-11-09 14:19:14 main INFO [7f60a856d780]   plugin 'routing:masters' loading
2018-11-09 14:19:14 main DEBUG [7f60a856d780]   plugin 'routing' loaded ok
2018-11-09 14:19:14 main INFO [7f60a856d780]   plugin 'routing:slaves' loading
2018-11-09 14:19:14 main DEBUG [7f60a856d780]   plugin 'routing' loaded ok
2018-11-09 14:19:14 main INFO [7f60a856d780] Initializing all plugins.
2018-11-09 14:19:14 main INFO [7f60a856d780]   plugin 'routing' initializing
2018-11-09 14:19:14 main DEBUG [7f60a856d780]   plugin 'routing' init exit ok
2018-11-09 14:19:14 main INFO [7f60a856d780] Starting all plugins.
2018-11-09 14:19:14 main INFO [7f60a57a2700]   plugin 'routing:masters' starting
2018-11-09 14:19:14 routing INFO [7f60a57a2700] [routing:masters] started: listening on 192.168.0.10:7002
2018-11-09 14:19:14 main INFO [7f60a4fa1700]   plugin 'routing:slaves' starting
2018-11-09 14:19:14 routing INFO [7f60a4fa1700] [routing:slaves] started: listening on 192.168.0.10:7001
2018-11-09 14:19:14 main INFO [7f60a856d780] Running.

最后進行測試即可。測試前,先在后端Master上授權MySQL Router節點允許連接,它將會復制到兩個slave節點上。

mysql> grant all on *.* to root@'192.168.100.%' identified by 'P@ssword1!';

連上MySQL Router的7002端口,這個端口是負責寫的端口。由於沒有配置主從高可用,所以,簡單測試下是否能寫即可。

[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"select @@server_id;" -P7002
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"show databases;" -P7002
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| db01               |
| db02               |
| db03               |
| first_db           |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
| test1              |
+--------------------+

再測試下各slave節點,是否能實現rr調度算法的讀請求的負載均衡。

[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"select @@server_id;" -P7001
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+
[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"select @@server_id;" -P7001
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          31 |
+-------------+
[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"select @@server_id;" -P7001
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          10 |
+-------------+
[root@mysql-proxy etc]# mysql -h192.168.0.10 -uroot -pabc123 -e"select @@server_id;" -P7001
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|          31 |
+-------------+

顯然,測試的結果一切正常。

這樣看來MySQL Router好簡單,確實好簡單。只需提供一個合理的配置文件,一切都完成了。那么,下面解釋下MySQL Router的配置文件。

3.MySQL Router的配置文件解釋

MySQL Router的配置文件也很簡單,需要配置的項不多。

mysql router默認會尋找安裝目錄下的"mysqlrouter.conf"和家目錄下的".mysqlrouter.conf"。也可以在二進制程序mysqlrouter命令下使用"-c"或者"--config"手動指定配置文件。

MySQL router的配置文件是片段式的,常用的就3個片段:[DEFAULT]、[logger]、[routing:NAME]。片段名稱區分大小寫,且只支持單行"#"或";"注釋,不支持行中、行尾注釋。

以上面示例的配置文件為例。

[DEFAULT] config_folder = /etc/mysqlrouter logging_folder = /usr/local/mysqlrouter/log runtime_folder = /var/run/mysqlrouter  [logger] level = INFO  [routing:slaves] bind_address = 192.168.100.21:7001 destinations = 192.168.100.23:3306,192.168.100.24:3306 mode = read-only connect_timeout = 1  [routing:masters] bind_address = 192.168.100.21:7002 destinations = 192.168.100.22:3306 mode = read-write connect_timeout = 2

1.DEFAULT片段的配置。

[DEFAULT]片段通常配置配置文件的目錄、日志的目錄、MySQL router運行時的目錄(如pid文件)。

例如:

[DEFAULT]
config_folder=/etc/mysqlrouter   # 指定額外的配置文件目錄,該目錄下的conf文件都會被加載 logging_folder=/usr/local/mysqlrouter/log # 指定日志目錄,日志文件名為mysqlrouter.log runtime_folder=/var/run/mysqlrouter # 指定運行時目錄,默認為/run/mysqlrouter

2.logger片段的配置。

[logger]片段只有一個選項,設置日志的記錄級別。

[logger] level=debug # 有debug、info(默認)、warning、error、fatal,不區分大小寫

3.routing片段的配置。

[routing:NAME]是MySQL router主要部分,設置不同的路由實例,其中NAME可以隨意命名。如[routing:slaves][routing:masters]

在routing配置片段,可以設置的選項包括:

  • (1).bind_addressbind_port
    bind_address和bind_port是mysql router監聽前端SQL請求的地址和端口。其中端口是MySQL Router要求強制提供的,但可以不用bind_port綁定,因為它可用通過bind_address的IP:PORT格式指定。
    一個routing規則中只能設置一個地址監聽指令,但可以通過"0.0.0.0"來監聽主機上所有的地址。如果沒有提供監聽地址,則默認監聽127.0.0.1。
    另外,監聽地址不能出現在destinations指令指定的列表中。
    示例如下:
[routing:slaves] bind_port = 7001 [routing:slaves] bind_address = 192.168.100.21 bind_port = 7001 [routing:slaves] bind_address = 192.168.100.21:7001

一般來說,通過不同端口實現讀/寫分離,並非好方法,最大的原因是需要在應用程序代碼中指定這些連接端口。但是,MySQL Router只能通過這種方式實現讀寫分離,所以MySQL Router拿來當玩具玩玩就好

  • (2).destinations
    定義routing規則的轉發目標,格式為HOST:PORT,HOST可以是IP也可以是主機名,多個轉發目標使用逗號分隔。如定義的目標列表是多個slave。
[routing:slaves] bind_address = 192.168.100.21:7001 destinations = 192.168.100.23:3306,192.168.100.24:3306 [routing:masters] bind_address = 192.168.100.21:7002 destinations = 192.168.100.22:3306,192.168.100.100:3306
  • (3).mode
    MySQL router提供兩種mode:read-only和read-write。這兩種方式會產生不同的轉發調度方式。
    • 設置為read-write,常用於設置destinations為master時,實現master的高可用。
      • 調度方式:當MySQL router第一次收到客戶端請求時,會將請求轉發給destinations列表中的第一個目標,第二次收到客戶端請求還是會轉發給第一個目標,只有當第一個目標聯系不上(如關閉了MySQL服務、宕機等)才會聯系第二個目標,如果所有目標都聯系不上,MySQL Router會中斷。這種調度方式被稱為"first-available"。
      • 當聯系上了某一個目標時,MySQL Router會將其緩存下來,下次收到請求還會繼續轉發給該目標。既然是緩存的目標,就意味着在MySQL Router重啟之后就會失效。
      • 所以通過MySQL Router實現讀寫分離的寫時,可以設置多個master,讓性能好的master放在destinations列表的第一個位置,其他的master放在后面的位置作為備用master。
    • 設置為read-only,常用於設置destinations為slave時,實現MySQL讀請求負載均衡。
      • 調度方式:當MySQL route收到客戶端請求時,會從destinations列表中的第一個目標開始向后輪詢(round-robin),第一個請求轉發給第一個目標,第二個請求轉發給第二個目標,轉發給最后一個目標之后的下一個請求又轉發給第一個目標。如果第一個目標不可用,會依次向后檢查,直到目標可用,如果所有目標都不可用,則MySQL Router中斷。
      • 那些不可用的目標會暫時被隔離,並且mysql router會不斷的檢查它們的狀況,當重新可用時會重新加入到目標列表。
  • (4).connect_timeout
    MySQL Router聯系destinations的超時時間,默認為1秒,值的范圍為1-65536。應該盡量設置值小點,免得等待時間過長。
    對於read-write模式,可以將超時時間設置的稍長一點點,防止誤認為主master不可用而去聯系備master。
    對於read-only模式,可以將超時時間設置的稍短一點點,因為這種模式下是destinations列表輪詢的,即使誤判了影響也不會太大。
  • (5).其他選項
    還能設置一些其他的指令,如使用的協議、最大請求數等,但是都可以不用設置使用默認值,它們都是MySQL Router結合MySQL優化過的一些選項,本身已經較完美了。

配置文件大概就這些內容,配置好后,記得先創建default片段中涉及到的目錄。之后就可以啟動mysql router提供讀/寫分離服務了。

4.為MySQL Router提供SysV腳本

MySQL Router只提供了一個主程序(bin目錄下的mysqlrouter),且該程序只能啟動,沒有停止選項,所以只能使用kill命令來殺掉進程。

MySQL Router也提供了示例啟動腳本,該腳本在位置為$basedir/share/doc/mysqlrouter/sample_mysqlrouter.init,但是該腳本是基於Debian平台的,在CentOS上需要設置和安裝一些東西,所以不用它,自己寫個粗糙點的腳本即可。

shell> vim /etc/init.d/mysqlrouter
#!/bin/bash # chkconfig: - 78 30 # Description: Start / Stop MySQL Router DAEMON=/usr/local/mysqlrouter proc=$DAEMON/bin/mysqlrouter DAEMON_OPTIONS="-c ${DAEMON}/etc/mysqlrouter.conf" . /etc/init.d/functions start() { if [ -e /var/lock/subsys/mysqlrouter ]; then action "MySQL Router is working" /bin/false else $proc $DAEMON_OPTIONS & &>/dev/null retval=$? echo if [ $retval -eq 0 ]; then touch /var/lock/subsys/mysqlrouter action "Starting MySQL Router" /bin/true else echo "Starting MySQL Router Failure" fi fi } stop() { if [ -e /var/lock/subsys/mysqlrouter ]; then killall $proc retval=$? echo if [ $retval -eq 0 ]; then rm -f /var/lock/subsys/mysqlrouter action "Stoping MySQL Router" /bin/true fi else action "MySQL Router is not working" /bin/false fi } status() { if [ -e /var/lock/subsys/mysqlrouter ]; then echo "MySQL Router is running" else echo "MySQL Router is not running" fi } case "$1" in start) start sleep 1 ;; stop) stop sleep 1 ;; restart) stop start sleep 1 ;; status) status ;; *) echo "Usage: $0 {start|stop|status|restart}" retval=1 ;; esac exit $retval 

然后賦予執行權限。

shell> chmod +x /etc/init.d/mysqlrouter

轉載請注明出處:https://www.cnblogs.com/f-ck-need-u/p/9276639.html#undefined


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM