ProxySQL 配置詳解及讀寫分離(+GTID)等功能說明 (完整篇)

 

ProxySQL是靈活強大的MySQL代理層, 是一個能實實在在用在生產環境的MySQL中間件,能夠實現讀寫分離,支持 Query 路由功能,支持動態指定某個 SQL 進行 cache,支持動態加載配置、故障切換和一些 SQL的過濾功能。還有一些同類產品好比 DBproxy、MyCAT、OneProxy 等。但通過反覆對比和測試以後,仍是以爲ProxySQL是一款性能不諳,靠譜穩定的MySQL 中間件產品 !html

ProxySQL的亮點所在前端

-  幾乎全部的配置都可在線更改(其配置數據基於SQLite存儲),無需重啓proxysql
-  基於正則和client_addr的強大和靈活的路由規則
-  詳細的狀態統計,統計結果和pt-query-digest對慢日誌的分析結果相似,至關於有了統一的查看sql性能和sql語句統計的入口(Designed by a DBA for DBAs)
-  自動重連和從新執行機制(auto-reconnect and automatic re-execution of queries using it’s Connections Pool ): 若一個請求在連接或執行過程當中意外中斷,proxysql會根據其內部機制從新執行該操做
-  query cache功能:比mysql自帶QC更靈活,可在mysql_query_rules表中依據digest,match_pattern,client_addr等維度控制哪類語句能夠緩存
-  支持鏈接池(connection pool)而且支持multiplexing,區別於atlas之流的鏈接池實現。node

ProxySQL的特色mysql

ProxySQL是一個高性能的MySQL中間件,擁有強大的規則引擎。具備如下特性:
-  鏈接池,並且是 multiplexing;
-  主機和用戶的最大鏈接數限制;
-  自動下線後端DB;
    -  延遲超過閥值
    -  ping 延遲超過閥值
    -  網絡不通或宕機
-  強大的規則路由引擎;
   -  實現讀寫分離
   -  查詢重寫
   -  sql流量鏡像
-  支持prepared statement;
-  支持Query Cache;
-  支持負載均衡,與gelera結合自動failover;
-  將全部配置保存寫入到SQLit表中。
-  支持動態加載配置,即通常能夠在線修改配置,但有少部分參數仍是須要重啓來生效。
-  支持query cache。
-  支持對query的路由,能夠針對某個語句進行分配去哪一個實例執行。
-  不支持分表,能夠分庫,可是利用規則配置實現分表。linux

如上可知,ProxySQL集合了不少優秀特性於一身,那麼它的缺點呢就是項目不夠成熟,好在官方網站一直在及時更新,而且受到 Percona 官方的支持。git

ProxySQL多層管理配置設計 (有三層配置)github

runtime:運行中使用的配置文件
memory:提供用戶動態修改配置文件
disk:將修改的配置保存到磁盤SQLit表中(即:proxysql.db)
config:通常不使用它(即:proxysql.cnf)web

ProxySQL運行機制草圖以下:
ProxySQL有一個完備的配置系統,配置ProxySQL是基於sql命令的方式完成的。ProxySQL支持配置修改以後的在線保存、應用,不須要重啓便可生效。整個配置系統分三層設計。
整個配置系統分爲三層,以下圖所示:sql

ProxySQL配置系統分爲三層的目的:
1) 自動更新;
2) 儘量的不重啓proxysql就能夠修改配置;
3) 方便回滾錯誤配置;shell

簡單說就是配置proxysql分爲三個級別,RUNTIME是即時生效的,MEMORY是保存在內存中但並不當即生效的,DISK|CONFIG FILE是持久化或寫在配置文件中的。

這三個級別的配置文件互不干擾,在某個層級修改了配置文件,想要加載或保存到另外一個層級,須要額外的LOAD或SAVE操做:"LOAD xx_config FROM xx_level | LOAD xx_config TO xx_level | SAVE xx_config TO xx_level | SAVE xx_config FROM xx_level",達到加載配置或者持久化配置的目的。這三層中每層的功能與含義以下:
-  RUNTIME層
表明的是ProxySQL當前生效的配置,包括 global_variables, mysql_servers, mysql_users, mysql_query_rules。沒法直接修改這裏的配置,必需要從下一層load進來。該層級的配置時在proxysql管理庫(sqlite)的main庫中以runtime_開頭的表,這些表的數據庫沒法直接修改,只能從其餘層級加載;該層表明的是ProxySQL當前生效的正在使用的配置,包括global_variables, mysql_servers, mysql_users, mysql_query_rules表。沒法直接修改這裏的配置,必需要從下一層load進來。也就是說RUNTIME這個頂級層,是proxysql運行過程當中實際使用的那一份配置,這一份配置會直接影響到生產環境的,因此要將配置加載進RUNTIME層時須要三思而行。

-  MEMORY層
是平時在mysql命令行修改的 main 裏頭配置,能夠認爲是SQLite數據庫在內存的鏡像。該層級的配置在main庫中以mysql_開頭的表以及global_variables表,這些表的數據能夠直接修改;用戶能夠經過MySQL客戶端鏈接到此接口(admin接口),而後能夠在mysql命令行查詢不一樣的表和數據庫,並修改各類配置,能夠認爲是SQLite數據庫在內存的鏡像。也就是說MEMORY這個中間層,上面接着生產環境層RUNTIME,下面接着持久化層DISK和CONFIG FILE。MEMORY層是咱們修改proxysql的惟一正常入口。通常來講在修改一個配置時,首先修改Memory層,確認無誤後再接入RUNTIME層,最後持久化到DISK和CONFIG FILE層。也就是說memeory層裏面的配置隨便改,不影響生產,也不影響磁盤中保存的數據。經過admin接口能夠修改mysql_servers、mysql_users、mysql_query_rules、global_variables等表的數據。

-  DISK|CONFIG FILR層
持久存儲的那份配置,通常在$(DATADIR)/proxysql.db,在重啓的時候會從硬盤裏加載。 /etc/proxysql.cnf文件只在第一次初始化的時候用到,完了後,若是要修改監聽端口,仍是須要在管理命令行裏修改,再 save 到硬盤。該層級的配置在磁盤上的sqlite庫或配置文件裏。DISK/CONFIG FILE層表示持久存儲的那份配置,持久層對應的磁盤文件是$(DATADIR)/proxysql.db,在重啓ProxySQL的時候,會從proxysql.db文件中加載信息。而 /etc/proxysql.cnf文件只在第一次初始化的時候使用,以後若是要修改配置,就須要在管理端口的SQL命令行裏進行修改,而後再save到硬盤。 也就是說DISK和CONFIG FILE這一層是持久化層,咱們作的任何配置更改,若是不持久化下來,重啓後,配置都將丟失。

                                      須要注意                                       
1) ProxySQL每個配置項在三層中都存在,可是這三層是互相獨立的,也就是說proxysql能夠同時擁有三份配置,每層都是獨立的,可能三份配置都不同,也可能三份都同樣。
2) RUNTIME層表明 ProxySQL 當前生效的正在使用的配置,沒法直接修改這裏的配置,必需要從下一層 "load" 進來。
3) MEMORY這一層上面鏈接 RUNTIME 層,下面鏈接持久化層。在這層能夠正常操做 ProxySQL 配置,隨便修改,不會影響生產環境。修改一個配置通常都是先在 MEMORY 層完成,而後確認正常以後再加載到 RUNTIME 和持久化到磁盤上。
4) DISK 和 CONFIG FILE層持久化配置信息,重啓後內存中的配置信息會丟失,因此須要將配置信息保留在磁盤中。重啓時,能夠從磁盤快速加載回來。

ProxySQL配置文件的修改流程通常是:
- 啓動時:先修改必要的CONFIG FILE配置,好比管理端口,而後啓動;
- 其餘配置:修改MEMORY中的表,而後加載到RUNTIME並持久化。

ProxySQL具備一個複雜但易於使用的配置系統,能夠知足如下需求:
-  容許輕鬆動態更新配置(這是爲了讓ProxySQL用戶能夠在須要零宕機時間配置的大型基礎架構中使用它)。與MySQL兼容的管理界面可用於此目的。
-  容許儘量多的配置項目動態修改,而不須要從新啓動ProxySQL進程
-  能夠絕不費力地回滾無效配置
-  這是經過多級配置系統實現的,其中設置從運行時移到內存,並根據須要持久保存到磁盤。

通常,修改的配置都是在memory層能夠load到runtime,使配置在不用重啓proxysql的狀況下也能夠生效,也能夠save到disk,將對配置的修改持久化!

須要修改配置時,直接操做的是 MEMORAY,如下命令可用於加載或保存 users (mysql_users):  (序號對應上圖「運行機制」草圖)

[1]: LOAD MYSQL USERS TO RUNTIME / LOAD MYSQL USERS FROM MEMORY   #經常使用。將修改後的配置(在memory層)用到實際生產
[2]: SAVE MYSQL USERS TO MEMORY / SAVE MYSQL USERS FROM RUNTIME        #將生產配置拉一份到memory中
[3]: LOAD MYSQL USERS TO MEMORY / LOAD MYSQL USERS FROM DISK           #將磁盤中持久化的配置拉一份到memory中來
[4]: SAVE MYSQL USERS TO DISK /  SAVE MYSQL USERS FROM MEMORY     #經常使用。將memoery中的配置保存到磁盤中去
[5]: LOAD MYSQL USERS FROM CONFIG                                      #將配置文件中的配置加載到memeory中

我的仍是比較習慣用 TO,記住往上層是 LOAD,往下層是 SAVE。如下命令加載或保存servers (mysql_servers):

[1]: LOAD MYSQL SERVERS TO RUNTIME  #經常使用,讓修改的配置生效
[2]: SAVE MYSQL SERVERS TO MEMORY
[3]: LOAD MYSQL SERVERS TO MEMORY
[4]: SAVE MYSQL SERVERS TO DISK     #經常使用,將修改的配置持久化
[5]: LOAD MYSQL SERVERS FROM CONFIG

後面的使用方法也基本相同,一併列出。如下命令加載或保存query rules (mysql_query_rules):

[1]: load mysql query rules to run    #經常使用
[2]: save mysql query rules to mem
[3]: load mysql query rules to mem
[4]: save mysql query rules to disk   #經常使用
[5]: load mysql query rules from config

如下命令加載或保存 mysql variables (global_variables):

[1]: load mysql variables to runtime
[2]: save mysql variables to memory
[3]: load mysql variables to memory
[4]: save mysql variables to disk
[5]: load mysql variables from config

如下命令加載或保存admin variables (select * from global_variables where variable_name like 'admin-%'):

[1]: load admin variables to runtime
[2]: save admin variables to memory
[3]: load admin variables to memory
[4]: save admin variables to disk
[5]: load admin variables from config

ProxySQL啓動過程總結:
當proxysql啓動時,首先讀取配置文件CONFIG FILE(/etc/proxysql.cnf),而後從該配置文件中獲取datadir,datadir中配置的是sqlite的數據目錄。若是該目錄存在,且sqlite數據文件存在,那麼正常啓動,將sqlite中的配置項讀進內存,而且加載進RUNTIME,用於初始化proxysql的運行。若是datadir目錄下沒有sqlite的數據文件,proxysql就會使用config file中的配置來初始化proxysql,而且將這些配置保存至數據庫。sqlite數據文件能夠不存在,/etc/proxysql.cnf文件也能夠爲空,但/etc/proxysql.cnf配置文件必須存在,不然,proxysql沒法啓動。

1、 ProxySQL 安裝 (兩種方式)

1) 採用yum方式安裝
[root@mysql-proxy ~]# vim /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/\$releasever
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key

執行安裝
[root@mysql-proxy ~]# yum clean all
[root@mysql-proxy ~]# yum makecache
[root@mysql-proxy ~]# yum -y install proxysql
 
[root@mysql-proxy ~]# proxysql --version
ProxySQL version 1.4.13-15-g69d4207, codename Truls
 
啓動ProxySQL
[root@mysql-proxy ~]# chkconfig proxysql on
[root@mysql-proxy ~]# systemctl start proxysql       
[root@mysql-proxy ~]# systemctl status proxysql

啓動後會監聽兩個端口,
默認爲6032和6033。6032端口是ProxySQL的管理端口,6033是ProxySQL對外提供服務的端口 (即鏈接到轉發後端的真正數據庫的轉發端口)。
[root@mysql-proxy ~]# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name   
tcp        0      0 0.0.0.0:6032            0.0.0.0:*               LISTEN      23940/proxysql     
tcp        0      0 0.0.0.0:6033            0.0.0.0:*               LISTEN      23940/proxysql

2)採用rpm包方式安裝
proxysql的rpm包下載地址: https://pan.baidu.com/s/1S1_b5DKVCpZSOUNmtCXrrg
提取密碼: 5t1c
 
[root@mysql-proxy ~]# wget https://github.com/sysown/proxysql/releases/download/v1.4.8/proxysql-1.4.8-1-centos7.x86_64.rpm
[root@mysql-proxy ~]# rpm -ivh proxysql-1.4.8-1-centos7.x86_64.rpm --force

[root@mysql-proxy ~]# /etc/init.d/proxysql start
Starting ProxySQL: DONE!

[root@mysql-proxy ~]# ss -lntup|grep proxy
tcp    LISTEN     0      128       *:6032                  *:*                   users:(("proxysql",pid=2943,fd=24))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=22))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=21))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=20))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=19))

如上能夠看出轉發端口6033是啓動了四個線程

==============================================================
以上兩種方式採用任何一種均可以順利安裝proxysql插件。

另外,記得在proxysql服務器上安裝mysql客戶端,用於在本機鏈接到ProxySQL的管理接口
[root@mysql-proxy ~]# vim /etc/yum.repos.d/mariadb.repo
[mariadb] 
name = MariaDB
baseurl = http://yum.mariadb.org/10.3.5/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
  
安裝mysql-clinet客戶端
[root@mysql-proxy ~]# yum install -y MariaDB-client
 
--------------------------------------------------------------------------------------------------------------------------------------------------------
若是遇到報錯:
Error: MariaDB-compat conflicts with 1:mariadb-libs-5.5.60-1.el7_5.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
  
解決辦法:
[root@mysql-proxy ~]# rpm -qa|grep mariadb*
mariadb-libs-5.5.56-2.el7.x86_64
[root@mysql-proxy ~]# rpm -e mariadb-libs-5.5.56-2.el7.x86_64 --nodeps
[root@mysql-proxy ~]# yum install -y MariaDB-client

ProxySQL配置
ProxySQL有配置文件/etc/proxysql.cnf和配置數據庫文件/var/lib/proxysql/proxysql.db。這裏須要特別注意:若是存在若是存在"proxysql.db"文件(在/var/lib/proxysql目錄下),則ProxySQL服務只有在第一次啓動時纔會去讀取proxysql.cnf文件並解析;後面啓動會就不會讀取proxysql.cnf文件了!若是想要讓proxysql.cnf文件裏的配置在重啓proxysql服務後生效(即想要讓proxysql重啓時讀取並解析proxysql.cnf配置文件),則須要先刪除/var/lib/proxysql/proxysql.db數據庫文件,而後再重啓proxysql服務。這樣就至關於初始化啓動proxysql服務了,會再次生產一個純淨的proxysql.db數據庫文件(若是以前配置了proxysql相關路由規則等,則就會被抹掉)。 官方推薦用admin interface方式!(即在proxysql本機使用mysql客戶端鏈接管理端口)

[root@mysql-proxy ~]# egrep -v "^#|^$" /etc/proxysql.cnf
datadir="/var/lib/proxysql"                                   #數據目錄
admin_variables=
{
        admin_credentials="admin:admin"                       #鏈接管理端的用戶名與密碼
        mysql_ifaces="0.0.0.0:6032"                           #管理端口,用來鏈接proxysql的管理數據庫
}
mysql_variables=
{
        threads=4                                             #指定轉發端口開啓的線程數量
        max_connections=2048
        default_query_delay=0
        default_query_timeout=36000000
        have_compress=true
        poll_timeout=2000
        interfaces="0.0.0.0:6033"                             #指定轉發端口,用於鏈接後端mysql數據庫的,至關於代理做用
        default_schema="information_schema"
        stacksize=1048576
        server_version="5.5.30"                               #指定後端mysql的版本
        connect_timeout_server=3000
        monitor_username="monitor"
        monitor_password="monitor"
        monitor_history=600000
        monitor_connect_interval=60000
        monitor_ping_interval=10000
        monitor_read_only_interval=1500
        monitor_read_only_timeout=500
        ping_interval_server_msec=120000
        ping_timeout_server=500
        commands_stats=true
        sessions_sort=true
        connect_retries_on_failure=10
}
mysql_servers =
(
)
mysql_users:
(
)
mysql_query_rules:
(
)
scheduler=
(
)
mysql_replication_hostgroups=
(
)


proxysql的數據目錄
[root@mysql-proxy ~]# ll /var/lib/proxysql/
total 1014052
-rw------- 1 root root     122880 Jan 25 14:33 proxysql.db
-rw------- 1 root root 1023288179 Jan 28 12:30 proxysql.log
-rw-r--r-- 1 root root          6 Jan 25 14:20 proxysql.pid
-rw------- 1 root root    1736704 Jan 28 12:29 proxysql_stats.db

查看main庫(默認登錄後即在此庫)的global_variables表信息
MySQL [(none)]> 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.000 sec)

MySQL [(none)]> use main;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [main]> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
20 rows in set (0.000 sec)

MySQL [main]> select * from global_variables;
+-----------------------------------------------------+---------------------------+
| variable_name                                       | variable_value            |
+-----------------------------------------------------+---------------------------+
| mysql-shun_on_failures                              | 5                         |
| mysql-shun_recovery_time_sec                        | 10                        |
| mysql-query_retries_on_failure                      | 1                         |
| mysql-connect_retries_delay                         | 1                         |
| mysql-connection_delay_multiplex_ms                 | 0                         |
| mysql-connection_max_age_ms                         | 0                         |
| mysql-connect_timeout_server_max                    | 10000                     |
| mysql-eventslog_filename                            |                           |
| mysql-eventslog_filesize                            | 104857600                 |
| mysql-default_charset                               | utf8                      |
| mysql-free_connections_pct                          | 10                        |
| mysql-session_idle_ms                               | 1000                      |
| mysql-client_found_rows                             | true                      |
| mysql-monitor_enabled                               | true                      |
| mysql-monitor_connect_timeout                       | 600                       |
| mysql-monitor_ping_max_failures                     | 3                         |
| mysql-monitor_ping_timeout                          | 1000                      |
| mysql-monitor_read_only_max_timeout_count           | 3                         |
| mysql-monitor_replication_lag_interval              | 10000                     |
| mysql-monitor_replication_lag_timeout               | 1000                      |
| mysql-monitor_groupreplication_healthcheck_interval | 5000                      |
| mysql-monitor_groupreplication_healthcheck_timeout  | 800                       |
| mysql-monitor_replication_lag_use_percona_heartbeat |                           |
| mysql-monitor_query_interval                        | 60000                     |
| mysql-monitor_query_timeout                         | 100                       |
| mysql-monitor_slave_lag_when_null                   | 60                        |
| mysql-monitor_wait_timeout                          | true                      |
| mysql-monitor_writer_is_also_reader                 | true                      |
| mysql-max_allowed_packet                            | 4194304                   |
| mysql-throttle_connections_per_sec_to_hostgroup     | 1000000                   |
| mysql-max_transaction_time                          | 14400000                  |
| mysql-multiplexing                                  | true                      |
| mysql-forward_autocommit                            | false                     |
| mysql-enforce_autocommit_on_reads                   | false                     |
| mysql-autocommit_false_not_reusable                 | false                     |
| mysql-autocommit_false_is_transaction               | false                     |
| mysql-verbose_query_error                           | false                     |
| mysql-hostgroup_manager_verbose                     | 1                         |
| mysql-threshold_query_length                        | 524288                    |
| mysql-threshold_resultset_size                      | 4194304                   |
| mysql-query_digests_max_digest_length               | 2048                      |
| mysql-query_digests_max_query_length                | 65000                     |
| mysql-wait_timeout                                  | 28800000                  |
| mysql-throttle_max_bytes_per_second_to_client       | 2147483647                |
| mysql-throttle_ratio_server_to_client               | 0                         |
| mysql-max_stmts_per_connection                      | 20                        |
| mysql-max_stmts_cache                               | 10000                     |
| mysql-mirror_max_concurrency                        | 16                        |
| mysql-mirror_max_queue_length                       | 32000                     |
| mysql-default_max_latency_ms                        | 1000                      |
| mysql-query_processor_iterations                    | 0                         |
| mysql-query_processor_regex                         | 1                         |
| mysql-long_query_time                               | 1000                      |
| mysql-query_cache_size_MB                           | 256                       |
| mysql-poll_timeout_on_failure                       | 100                       |
| mysql-server_capabilities                           | 45578                     |
| mysql-session_idle_show_processlist                 | true                      |
| mysql-query_digests                                 | true                      |
| mysql-query_digests_lowercase                       | false                     |
| mysql-servers_stats                                 | true                      |
| mysql-default_reconnect                             | true                      |
| mysql-ssl_p2s_ca                                    |                           |
| mysql-ssl_p2s_cert                                  |                           |
| mysql-ssl_p2s_key                                   |                           |
| mysql-ssl_p2s_cipher                                |                           |
| mysql-init_connect                                  |                           |
| mysql-default_sql_mode                              |                           |
| mysql-default_time_zone                             | SYSTEM                    |
| mysql-connpoll_reset_queue_length                   | 50                        |
| mysql-stats_time_backend_query                      | false                     |
| mysql-stats_time_query_processor                    | false                     |
| mysql-threads                                       | 4                         |
| mysql-max_connections                               | 2048                      |
| mysql-default_query_delay                           | 0                         |
| mysql-default_query_timeout                         | 36000000                  |
| mysql-have_compress                                 | true                      |
| mysql-poll_timeout                                  | 2000                      |
| mysql-interfaces                                    | 0.0.0.0:6033              |
| mysql-default_schema                                | information_schema        |
| mysql-stacksize                                     | 1048576                   |
| mysql-server_version                                | 5.5.30                    |
| mysql-connect_timeout_server                        | 3000                      |
| mysql-monitor_username                              | proxysql                  |
| mysql-monitor_password                              | proxysql                  |
| mysql-monitor_history                               | 600000                    |
| mysql-monitor_connect_interval                      | 60000                     |
| mysql-monitor_ping_interval                         | 10000                     |
| mysql-monitor_read_only_interval                    | 1500                      |
| mysql-monitor_read_only_timeout                     | 500                       |
| mysql-ping_interval_server_msec                     | 120000                    |
| mysql-ping_timeout_server                           | 500                       |
| mysql-commands_stats                                | true                      |
| mysql-sessions_sort                                 | true                      |
| mysql-connect_retries_on_failure                    | 10                        |
| admin-stats_credentials                             | stats:stats               |
| admin-stats_mysql_connections                       | 60                        |
| admin-stats_mysql_connection_pool                   | 60                        |
| admin-stats_mysql_query_cache                       | 60                        |
| admin-stats_system_cpu                              | 60                        |
| admin-stats_system_memory                           | 60                        |
| admin-telnet_admin_ifaces                           | (null)                    |
| admin-telnet_stats_ifaces                           | (null)                    |
| admin-refresh_interval                              | 2000                      |
| admin-read_only                                     | false                     |
| admin-hash_passwords                                | true                      |
| admin-cluster_username                              |                           |
| admin-cluster_password                              |                           |
| admin-cluster_check_interval_ms                     | 1000                      |
| admin-cluster_check_status_frequency                | 10                        |
| admin-cluster_mysql_query_rules_diffs_before_sync   | 3                         |
| admin-cluster_mysql_servers_diffs_before_sync       | 3                         |
| admin-cluster_mysql_users_diffs_before_sync         | 3                         |
| admin-cluster_proxysql_servers_diffs_before_sync    | 3                         |
| admin-cluster_mysql_query_rules_save_to_disk        | true                      |
| admin-cluster_mysql_servers_save_to_disk            | true                      |
| admin-cluster_mysql_users_save_to_disk              | true                      |
| admin-cluster_proxysql_servers_save_to_disk         | true                      |
| admin-checksum_mysql_query_rules                    | true                      |
| admin-checksum_mysql_servers                        | true                      |
| admin-checksum_mysql_users                          | true                      |
| admin-web_enabled                                   | false                     |
| admin-web_port                                      | 6080                      |
| admin-admin_credentials                             | admin:admin|
| admin-mysql_ifaces                                  | 0.0.0.0:6032              |
| admin-version                                       | 1.4.8-32-g669c149         |
+-----------------------------------------------------+---------------------------+
125 rows in set (0.003 sec)

登錄成功後,可經過對main庫(默認登錄後即在此庫)的global_variables表中的"admin-admin_credentials" 和 "admin-mysql_ifaces"
兩個變量進行更改來修改登陸認證! 好比說修改密碼或定義一個非admin的用戶用於遠程登陸(下面會說到)。

proxysql的6032端口是管理入口,帳號密碼是admin(能夠動態修改),容許客戶端鏈接;6033端口就是客戶端入口,帳號密碼經過管理接口去設置。在proxysql本機使用mysql客戶端鏈接到ProxySQL的管理接口(admin interface), 該接口的默認管理員用戶和密碼都是admin。

mysql_ifaces
也就是說proxysql有一個admin接口專門來作配置,至關於一個mysql shell能夠經過sql來讓配置實時生效。
mysql_ifaces配置了容許鏈接proxysql的ip和port

[root@mysql-proxy ~]# vim /etc/proxysql.cnf
........
# 將admin_variables中的mysql_ifaces修改爲容許遠程訪問
#      mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock"
       mysql_ifaces="0.0.0.0:6032"

若是ip配置爲0.0.0.0表示不限制ip,可是出於安全考慮,admin用戶不管怎麼設置都只能在本機登陸!!!

admin_credentials
這個key保存全部能夠操做proxysql的用戶名和密碼,格式爲:user:pass;user1:pass1,這裏能夠修改密碼或定義一個非admin的用戶用於遠程登陸。 前提是保證想要管理proxysql的機器安裝有mysql client客戶端!

先在proxysql本機登陸 (由於初始帳號密碼是admin:admin,只能在本機登陸), 這裏的proxysql本機地址是172.16.60.214

修改遠程鏈接proxysql管理端口的帳號和密碼radmin:radmin.
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032        
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 34
Server version: 5.5.30 (ProxySQL Admin Module)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> update global_variables set variable_value = 'admin:admin;radmin:radmin' where variable_name = 'admin-admin_credentials';
Query OK, 1 row affected (0.002 sec)

MySQL [(none)]> LOAD ADMIN VARIABLES TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE ADMIN VARIABLES TO DISK;
Query OK, 31 rows affected (0.077 sec)


這樣就可使用下面的命令在其餘機器上使用radmin用戶登陸(其餘機器上須要有mysql client)
[root@MGR-node3 ~]# mysql -uradmin -pradmin -h172.16.60.214 -P6032         
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 35
Server version: 5.5.30 (ProxySQL Admin Module)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+-----+---------------+-------------------------------------+
| seq | name          | file                                |
+-----+---------------+-------------------------------------+
| 0   | main          |                                     |
| 2   | disk          | /var/lib/proxysql/proxysql.db       |
| 3   | stats         |                                     |
| 4   | monitor       |                                     |
| 5   | stats_history | /var/lib/proxysql/proxysql_stats.db |
+-----+---------------+-------------------------------------+
5 rows in set (0.00 sec)

ProxySQL的庫、表說明 (默認管理端口是6032,客戶端服務端口是6033。默認的用戶名密碼都是 admin)

經過管理端口6032去鏈接的 (注意, 下面鏈接命令中後面的--prompt 'admin'字段能夠不加,也是能夠登陸進去的)
 
[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1
或者
[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1 --prompt 'admin> '
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 33
Server version: 5.5.30 (ProxySQL Admin Module)
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
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.000 sec)
 
ProxySQL提供了幾個庫,每一個庫都有各自的意義;
-  main 內存配置數據庫,表裏存放後端db實例、用戶驗證、路由規則等信息。表名以 runtime_開頭的表示proxysql當前運行的配置內容,
不能經過dml語句修改,只能修改對應的不以 runtime_ 開頭的(在內存)裏的表,而後 LOAD 使其生效, SAVE 使其存到硬盤以供下次重啓加載。
-  disk 是持久化到硬盤的配置,sqlite數據文件。
-  stats 是proxysql運行抓取的統計信息,包括到後端各命令的執行次數、流量、processlist、查詢種類彙總/執行時間等等。
-  monitor 庫存儲 monitor 模塊收集的信息,主要是對後端db的健康/延遲檢查。
 
1) main 庫 (disk庫的表字段和main同樣)
admin> show tables from main;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
20 rows in set (0.001 sec)

經常使用的幾個表介紹
===============================================
global_variables       
設置變量,包括監聽的端口、管理帳號等。

mysql_collations       
相關字符集和校驗規則。

mysql_query_rules      
定義查詢路由規則。

mysql_replication_hostgroups   
監視指定主機組中全部服務器的read_only值,而且根據read_only的值將服務器分配給寫入器或讀取器主機組。ProxySQL monitor模塊會監控hostgroups
後端全部servers 的read_only 變量,若是發現從庫的read_only變爲0、主庫變爲1,則認爲角色互換了,自動改寫mysql_servers表裏面 hostgroup關係,
達到自動 Failover 效果。

mysql_servers
設置後端MySQL的表

mysql_users
配置後端數據庫的程序帳號和監控帳號。

scheduler
調度器是一個相似於cron的實現,集成在ProxySQL中,具備毫秒的粒度。經過腳本檢測來設置ProxySQL。

2)stats庫
MySQL [(none)]> 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_global                   |
| 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        |
+--------------------------------------+
15 rows in set (0.001 sec)

經常使用的幾個表介紹
===============================================
stats_mysql_commands_counters
統計各類SQL類型的執行次數和時間,經過參數mysql-commands_stats控制開關,默認是ture。

stats_mysql_connection_pool
鏈接後端MySQL的鏈接信息。

stats_mysql_processlist
相似MySQL的show processlist的命令,查看各線程的狀態。

stats_mysql_query_digest
表示SQL的執行次數、時間消耗等。經過變量mysql-query_digests控制開關,默認是開。 

stats_mysql_query_rules
路由命中次數統計。

3)monitor庫
MySQL [(none)]> show tables from monitor;             
+------------------------------------+
| tables                             |
+------------------------------------+
| mysql_server_connect_log           |
| mysql_server_group_replication_log |
| mysql_server_ping_log              |
| mysql_server_read_only_log         |
| mysql_server_replication_lag_log   |
+------------------------------------+
5 rows in set (0.000 sec)

經常使用的幾個表介紹
===============================================
mysql_server_connect_log
鏈接到全部MySQL服務器以檢查它們是否可用,該表用來存放檢測鏈接的日誌。

mysql_server_ping_log
使用mysql_ping API ping後端MySQL服務器,檢查它們是否可用,該表用來存放ping的日誌。

mysql_server_replication_lag_log
後端MySQL服務主從延遲的檢測。

runtime_開頭的是運行時的配置,這些是不能修改的。要修改ProxySQL的配置,須要修改了非runtime_表,
修改後必須執行"LOAD ... TO RUNTIME"才能加載到RUNTIME生效,執行save ... to disk才能將配置持久化保存到磁盤。

global_variables 有80多個變量能夠設置,其中就包括監聽的端口、管理帳號、禁用monitor等

(admin@127.0.0.1:6032) [(none)]> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
20 rows in set (0.001 sec)
 
(admin@127.0.0.1:6032) [(none)]> 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_global                   |
| 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        |
+--------------------------------------+
15 rows in set (0.000 sec)
 
(admin@127.0.0.1:6032) [(none)]> show create table mysql_servers\G;
*************************** 1. row ***************************
       table: mysql_servers
Create Table: CREATE TABLE mysql_servers (
    hostgroup_id INT CHECK (hostgroup_id>=0) NOT NULL DEFAULT 0,
    hostname VARCHAR NOT NULL,
    port INT NOT NULL DEFAULT 3306,
    status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE',
    weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1,
    compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0,
    max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000,
    max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0,
    use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0,
    max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0,
    comment VARCHAR NOT NULL DEFAULT '',
    PRIMARY KEY (hostgroup_id, hostname, port) )
1 row in set (0.000 sec)
 
ERROR: No query specified
 
(admin@127.0.0.1:6032) [(none)]> select * from mysql_servers;
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 10           | 172.16.60.211 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 20           | 172.16.60.212 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 20           | 172.16.60.213 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.000 sec)

 hostgroup_id: ProxySQL經過 hostgroup (下稱HG) 的形式組織後端db實例。一個 HG 表明同屬於一個角色
 該表的主鍵是 (hostgroup_id, hostname, port),能夠看到一個 hostname:port 能夠在多個hostgroup裏面,如上面的 10.0.100.100:3307,這樣能夠避免 HG 1000 的從庫全都不可用時,依然能夠把讀請求發到主庫上。
-  一個 HG 能夠有多個實例,即多個從庫,能夠經過 weight 分配權重
-  hostgroup_id 0 是一個特殊的HG,路由查詢的時候,沒有匹配到規則則默認選擇 HG 0
 status:
-  ONLINE: 當先後端實例狀態正常
    SHUNNED: 臨時被剔除,可能由於後端 too many connections error,或者超過了可容忍延遲閥值 max_replication_lag
    OFFLINE_SOFT: 「軟離線」狀態,再也不接受新的鏈接,但已創建的鏈接會等待活躍事務完成。
   -  OFFLINE_HARD: 「硬離線」狀態,再也不接受新的鏈接,已創建的鏈接或被強制中斷。當後端實例宕機或網絡不可達,會出現。
-  max_connections: 容許鏈接到該後端mysql實例的最大鏈接數。不要大於MySQL設置的 max_connections,若是後端實例 hostname:port 在多個 hostgroup 裏,以較大者爲準,而不是各自獨立容許的最大鏈接數。
 max_replication_lag: 容許的最大延遲,主庫不受這個影響,默認0。若是 > 0, monitor 模塊監控主從延遲大於閥值時,會臨時把它變爲 SHUNNED 。
 max_latency_ms: mysql_ping 響應時間,大於這個閥值會把它從鏈接池剔除(即便是ONLINE)
-  comment: 備註,不建議留空。能夠經過它的內容如json格式的數據,配合本身寫的check腳本,完成一些自動化的工做。

表 mysql_users

MySQL [(none)]> 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,
    PRIMARY KEY (username, backend),
    UNIQUE (username, frontend))
1 row in set (0.000 sec)
 
ERROR: No query specified
 
MySQL [(none)]> select * from mysql_users;
+-----------+------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| username  | password   | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections |
+-----------+------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| proxysql  | proxysql   | 1      | 0       | 2                 | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |
| root      | passwd     | 1      | 0       | 10                | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |
| sqlsender | P@ssword1! | 1      | 0       | 10                | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |
+-----------+------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
3 rows in set (0.000 sec)
 
MySQL [(none)]> select username,password,transaction_persistent,active,backend,frontend,max_connections from runtime_mysql_users;
+-----------+-------------------------------------------+------------------------+--------+---------+----------+-----------------+
| username  | password                                  | transaction_persistent | active | backend | frontend | max_connections |
+-----------+-------------------------------------------+------------------------+--------+---------+----------+-----------------+
| proxysql  | *BF27B4C7AAD278126E228AA8427806E870F64F39 | 1                      | 1      | 0       | 1        | 10000           |
| root      | *59C70DA2F3E3A5BDF46B68F5C8B8F25762BCCEF0 | 1                      | 1      | 0       | 1        | 10000           |
| sqlsender | *50572A5FABC7DA9CEE5EB5977EDDE59E38967422 | 1                      | 1      | 0       | 1        | 10000           |
| proxysql  | *BF27B4C7AAD278126E228AA8427806E870F64F39 | 1                      | 1      | 1       | 0        | 10000           |
| root      | *59C70DA2F3E3A5BDF46B68F5C8B8F25762BCCEF0 | 1                      | 1      | 1       | 0        | 10000           |
| sqlsender | *50572A5FABC7DA9CEE5EB5977EDDE59E38967422 | 1                      | 1      | 1       | 0        | 10000           |
+-----------+-------------------------------------------+------------------------+--------+---------+----------+-----------------+
6 rows in set (0.001 sec)

-  username, password: 鏈接後端db的用戶密碼。
這個密碼你能夠插入明文,也能夠插入hash加密後的密文,proxysql會檢查你插入的時候密碼是否以 * 開頭來判斷,並且密文要在其它地方使用 PASSWORD()生成。但到 runtime_mysql_users 裏,都統一變成了密文,因此能夠明文插入,再 SAVE MYSQL USERS TO MEM,此時看到的也是HASH密文。
-  active: 是否生效該用戶。
 default_hostgroup: 這個用戶的請求沒有匹配到規則時,默認發到這個 hostgroup,默認0
 default_schema: 這個用戶鏈接時沒有指定 database name 時,默認使用的schema
注意表面上看默認爲NULL,但實際上受到變量 mysql-default_schema 的影響,默認爲 information_schema。關於這個參考我所提的 issue #988
 transaction_persistent: 若是設置爲1,鏈接上ProxySQL的會話後,若是在一個hostgroup上開啓了事務,那麼後續的sql都繼續維持在這個hostgroup上,不倫是否會匹配上其它路由規則,直到事務結束。
雖然默認是0,但我建議仍是設成1,雖然通常來講因爲前段應用的空值,爲0出問題的狀況幾乎很小。做者也在考慮默認設成 1,refer this issue #793
-  frontend, backend: 目前版本這兩個都須要使用默認的1,未來有可能會把 Client -> ProxySQL (frontend) 與 ProxySQL -> BackendDB (backend)的認證分開。從 runtime_mysql_users 表內容看到,記錄數比 mysql_users 多了一倍,就是把前端認證與後端認證獨立出來的結果。
 fast_forward: 忽略查詢重寫/緩存層,直接把這個用戶的請求透傳到後端DB。至關於只用它的鏈接池功能,通常不用,路由規則 .* 就好了。

表 mysql_replication_hostgroups

MySQL [(none)]> 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),
    comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup))
1 row in set (0.001 sec)
 
ERROR: No query specified
 
MySQL [(none)]> select * from mysql_replication_hostgroups;
+------------------+------------------+---------+
| writer_hostgroup | reader_hostgroup | comment |
+------------------+------------------+---------+
| 10               | 20               | 1       |
+------------------+------------------+---------+
1 row in set (0.000 sec)

定義 hostgroup 的主從關係。ProxySQL monitor 模塊會監控 HG 後端全部servers 的 read_only 變量,若是發現從庫的 read_only 變爲0、主庫變爲1,則認爲角色互換了,自動改寫 mysql_servers 表裏面 hostgroup 關係,達到自動 Failover 效果。

表 mysql_query_rules
mysql_query_rules 是ProxySQL很是核心一個表,定義查詢路由規則

MySQL [(none)]> 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 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,
    replace_pattern VARCHAR,
    destination_hostgroup INT DEFAULT NULL,
    cache_ttl INT CHECK(cache_ttl > 0),
    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)),
    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.001 sec)
 
ERROR: No query specified
 
MySQL [(none)]> 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 | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+----------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+-----+-------+---------+
| 1       | 1      | NULL     | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT.*FOR UPDATE$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 10                    | NULL      | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL | 1     | NULL    |
| 2       | 1      | NULL     | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT              | NULL          | 0                    | CASELESS     | NULL    | NULL            | 20                    | NULL      | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+----------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+-----+-------+---------+
2 rows in set (0.000 sec)

 rule_id: 表主鍵,自增。規則處理是以 rule_id 的順序進行。
 active: 只有 active=1 的規則纔會參與匹配。
-  username: 若是非 NULL,只有鏈接用戶是 username 的值纔會匹配。
-  schemaname: 若是非 NULL,只有查詢鏈接使用的db是 schemaname 的值纔會匹配。
   注意若是是 NULL,不表明鏈接沒有使用schema,而是不倫任何schema都進一步匹配。
 flagIN, flagOUT, apply: 用來定義路由鏈 chains of rules。
    首先會檢查 flagIN=0 的規則,以rule_id的順序;若是都沒匹配上,則走這個用戶的 default_hostgroup。
    當匹配一條規則後,會檢查 flagOUT。
      -  若是不爲NULL,而且 flagIN != flagOUT ,則進入以flagIN爲上一個flagOUT值的新規則鏈。
       若是不爲NULL,而且 flagIN = flagOUT,則應用這條規則。
      -  若是爲NULL,或者 apply=1,則結束,應用這條規則。
      -  若是最終沒有匹配到,則找到這個用戶的 default_hostgroup。
-  client_addr: 匹配客戶端來源IP
-  proxy_addr, proxy_port: 匹配本地proxysql的IP、端口。我目前沒有想到它的應用場景,多是把proxysql監聽在多個接口上,分發到不一樣的業務?
 digest: 精確的匹配一類查詢。
 match_digest: 正則匹配一類查詢。query digest 是指對查詢去掉具體值後進行「模糊化」後的查詢,相似 pt-fingerprint / pt-query-digest 的效果。
-  match_pattern: 正則匹配查詢。

以上都是匹配查詢的規則,1.3.5版本使用的正則引擎只有 RE2 ,1.4版本能夠經過變量 mysql-query_processor_regex 設置 RE2 或者 PCRE,且1.4開始默認是PCRE。
推薦用 match_digest 。關於每條查詢都會計算digest對性能的影響,計算query digest確實會有性能損失,可是這倒是proxysql裏面很是重要的特性,主要是兩點:
   -  proxysql沒法知道鏈接複用(multipexing)是否必須被自動禁用,好比鏈接裏面有variables/tmp tables/lock table等特殊命令,是不能複用的。
   -  完整的查詢去匹配正則的效率,通常沒有參數化後的查詢匹配效率高,由於有很長的字符串內容須要處理。再者,SELECT * FROM randomtable WHERE comment LIKE ‘%INTO sbtest1 %                FROM sbtest2 %’字符串裏有相似這樣的語句,很難排除誤匹配。
 negate_match_pattern: 反向匹配,至關於對 match_digest/match_pattern 的匹配取反。
-  re_modifiers: 修改正則匹配的參數,好比默認的:忽略大小寫CASELESS、禁用GLOBAL.

上面都是匹配規則,下面是匹配後的行爲
 replace_pattern: 查詢重寫,默認爲空,不rewrite。
-  rewrite規則要遵照 RE2::Replace 。
destination_hostgroup: 路由查詢到這個 hostgroup。固然若是用戶顯式 start transaction 且 transaction_persistent=1,那麼即便匹配到了,也依然按照事務裏第一條sql的路由規則去走。
-  cache_ttl: 查詢結果緩存的毫秒數。
proxysql這個 Query Cache 與 MySQL 自帶的query cache不是同一個。proxysql query cache也不會關心後端數據是否被修改,它所作的就是針對某些特定種類的查詢結果進行緩存,好比一些歷史數據的count結果。通常不設。
 timeout: 這一類查詢執行的最大時間(毫秒),超時則自動kill。
這是對後端DB的保護機制,至關於阿里雲RDS loose_max_statement_time 變量的功能,可是注意不一樣的是,阿里雲這個變量的時間時不包括DML操做出現InnoDB行鎖等待的時間,而ProxySQL的這個 timeout 是計算從發送sql到等待響應的時間。默認mysql-default_query_timeout給的是 10h .
 retries: 語句在執行時失敗時,重試次數。默認由 mysql-query_retries_on_failure變量指定,爲1 。
   我的建議把它設成0,即不重試。由於執行失敗,對select而言不多見,主要是dml,但本身重試對數據不放心。
-  delay: 查詢延遲執行,這是ProxySQL提供的限流機制,會讓其它的查詢優先執行。
   默認值 mysql-default_query_delay,爲0。咱們通常不用,其實仍是要配合應用端使用,好比這邊延遲執行,但上層等待你返回,那前端不就堵住了,沒準出現雪崩效應。
 mirror_flagOUT,mirror_hostgroup
這兩個高級了,目前這部分文檔不全,功能是SQL鏡像。顧名思義,就是把匹配到的SQL除了發送到 destination_hostgroup,同時鏡像一份到這裏的hostgroup,好比咱們的測試庫。好比這種場景,數據庫要從5.6升級到5.7,要驗證現有查詢語句對5.7的適用狀況,就能夠把生產流量鏡像到5.7新庫上驗證。
-  error_msg: 默認爲NULL,若是指定了則這個查詢直接被 block 掉,立刻返回這個錯誤信息。
這個功能也很實用,好比線上忽然冒出一個 「壞查詢」,應用端不方便立刻發版解決,咱們就能夠在這配置一個規則,把查詢屏蔽掉,想正常的mysql報錯那樣拋異常。下一篇文章有演示。
 multiplex: 鏈接是否複用。
 log: 是否記錄查詢日誌。能夠看到log是否記錄的對象是根據規則。
要開啓日誌記錄,須要設置變量 mysql-eventslog_filename 來指定文件名,而後這個 log 標記爲1。可是目前proxysql記錄的日誌是二進制格式,須要特定的工具才能讀取: eventslog_reader_sample 。這個工具在源碼目錄 tools下面。

proxysql對後端server健康檢查

MySQL [monitor]> show variables like "mysql-monitor%";
+-----------------------------------------------------+------------+
| Variable_name                                       | Value      |
+-----------------------------------------------------+------------+
| mysql-monitor_enabled                               | true       |
| mysql-monitor_connect_timeout                       | 600        |
| mysql-monitor_ping_max_failures                     | 3          |
| mysql-monitor_ping_timeout                          | 1000       |
| mysql-monitor_read_only_max_timeout_count           | 3          |
| mysql-monitor_replication_lag_interval              | 10000      |
| mysql-monitor_replication_lag_timeout               | 1000       |
| mysql-monitor_groupreplication_healthcheck_interval | 5000       |
| mysql-monitor_groupreplication_healthcheck_timeout  | 800        |
| mysql-monitor_replication_lag_use_percona_heartbeat |            |
| mysql-monitor_query_interval                        | 60000      |
| mysql-monitor_query_timeout                         | 100        |
| mysql-monitor_slave_lag_when_null                   | 60         |
| mysql-monitor_wait_timeout                          | true       |
| mysql-monitor_writer_is_also_reader                 | true       |
| mysql-monitor_username                              | monitor    |
| mysql-monitor_password                              | P@ssword1! |
| mysql-monitor_history                               | 600000     |
| mysql-monitor_connect_interval                      | 60000      |
| mysql-monitor_ping_interval                         | 10000      |
| mysql-monitor_read_only_interval                    | 1500       |
| mysql-monitor_read_only_timeout                     | 500        |
+-----------------------------------------------------+------------+
22 rows in set (0.001 sec)

ProxySQL配置後端DB server
兩種方式,區別在於
1)  一種是在往mysql_servers表中添加server時就爲其劃分好hostgroup_id(例如0表示寫組,1表示讀組)
2)  另外一種往mysql_servers表中添加server時不區分hostgroup_id(例如所有設爲0),而後經過mysql_replication_hostgroups表中的值,
根據proxysql檢測到的各server的read_only變量值來自動爲後端server設置hostgroup_id

這裏強烈推薦用第一種方式
由於第一種是徹底由咱們控制的;而第二種假如咱們誤將讀server的read_only屬性設置爲0,則proxysql會將其從新分配到寫組,這絕對是不指望的。

ProxySQL下添加與修改配置

1) 添加配置
須要添加配置時,直接操做的是MEMORAY,例如:添加一個程序用戶,在mysql_users表中執行一個插入操做:
MySQL [(none)]> insert into mysql_users(username,password,active,default_hostgroup,transaction_persistent) values('myadmin','mypass',1,0,1);
 
這樣就完成了一個用戶的添加。要讓這個insert生效,還須要執行以下操做:
MySQL [(none)]>load mysql users to runtime;
表示將修改後的配置(MEMORY層)用到實際生產環境(RUNTIME層)
 
若是想保存這個設置永久生效,還須要執行以下操做:
MySQL [(none)]>save mysql users to disk;
表示將memoery中的配置保存到磁盤中去。
 
除了上面兩個操做,還能夠執行以下操做:
MySQL [(none)]>load mysql users to memory;
表示將磁盤中持久化的配置拉一份到memory中來。
 
MySQL [(none)]>load mysql users from config;
表示將配置文件中的配置加載到memeory中。
 
2) 持久化配置
以上SQL命令是對mysql_users進行的操做,同理,還能夠對mysql_servers表、mysql_query_rules表、global_variables表等執行相似的操做。
如對mysql_servers表插入完成數據後,要執行保存和加載操做,可執行以下SQL命令:
MySQL [(none)]> load mysql servers to runtime;
MySQL [(none)]> save mysql servers to disk;
 
對mysql_query_rules表插入完成數據後,要執行保存和加載操做,可執行以下SQL命令:
MySQL [(none)]> load mysql query rules to runtime;
MySQL [(none)]> save mysql query rules to disk;
 
對global_variables表插入完成數據後,要執行保存和加載操做,可執行以下SQL命令:
 
如下命令加載或保存mysql variables(global_variables):
MySQL [(none)]>load mysql variables to runtime;
MySQL [(none)]>save mysql variables to disk;
 
如下命令加載或保存admin variables(select * from global_variables where variable_name like 'admin-%'):
MySQL [(none)]> load admin variables to runtime;
MySQL [(none)]>save admin variables to disk;

2、ProxySQL功能驗證 (針對GTID模式的主從同步,另兩個從庫都要設置read_only=on)
接下來經過實戰操做來全面瞭解一下 ProxySQL 的特性和使用場景。

1. 實驗環境

172.16.60.211    mysql-master       安裝Mysql5.7
172.16.60.212    mysql-slave1       安裝Mysql5.7
172.16.60.213    mysql-slave2       安裝Mysql5.7
172.16.60.214    mysql-proxy        安裝ProxySQL,Mysql-client

系統都是CentOS7.5,MySQL版本是5.7,準備一主兩從架構(基於GTID的同步,兩個從庫都要開啓read_only=on)來配合ProxySQL。
[root@mysql-master ~]# cat /etc/redhat-release 
CentOS Linux release 7.5.1804 (Core) 

1) 三個節點各自設置主機名
[root@mysql-master ~]# hostnamectl --static set-hostname mysql-master
[root@mysql-master ~]# hostname
mysql-master
 
[root@mysql-slave1 ~]# hostnamectl --static set-hostname mysql-slave1
[root@mysql-slave1 ~]# hostname
mysql-slave

[root@mysql-slave2 ~]# hostnamectl --static set-hostname mysql-slave2
[root@mysql-slave2 ~]# hostname
mysql-slave

[root@mysql-proxy ~]# hostnamectl --static set-hostname mysql-proxy
[root@mysql-proxy ~]# hostname
mysql-proxy
 
2) 全部節點關閉selinux和iptables防火牆
[root@mysql-master ~]# setenforce 0
[root@mysql-master ~]# cat /etc/sysconfig/selinux |grep "SELINUX=disabled"
SELINUX=disabled
 
[root@mysql-master ~]# iptables -F
[root@mysql-master ~]# systemctl disable firewalld
[root@mysql-master ~]# systemctl stop firewalld  
[root@mysql-master ~]# firewall-cmd --state
not running

2. 安裝Mysql 5.7  (在三個mysql節點上安裝)

在三個mysql節點機上使用yum方式安裝Mysql5.7,參考:https://www.cnblogs.com/kevingrace/p/8340690.html
    
安裝MySQL yum資源庫
[root@mysql-master ~]# yum localinstall https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
    
安裝MySQL 5.7
[root@mysql-master ~]# yum install -y mysql-community-server
    
啓動MySQL服務器和MySQL的自動啓動
[root@mysql-master ~]# systemctl start mysqld.service
[root@mysql-master ~]# systemctl enable mysqld.service
    
設置登陸密碼
因爲MySQL從5.7開始不容許首次安裝後使用空密碼進行登陸!爲了增強安全性,系統會隨機生成一個密碼以供管理員首次登陸使用,
這個密碼記錄在/var/log/mysqld.log文件中,使用下面的命令能夠查看此密碼:
[root@mysql-master ~]# cat /var/log/mysqld.log|grep 'A temporary password'
2019-01-11T05:53:17.824073Z 1 [Note] A temporary password is generated for root@localhost: TaN.k:*Qw2xs
    
使用上面查看的密碼TaN.k:*Qw2xs 登陸mysql,並重置密碼爲123456
[root@mysql-master ~]# mysql -p                 #輸入默認的密碼:TaN.k:*Qw2xs
.............
mysql> set global validate_password_policy=0;
Query OK, 0 rows affected (0.00 sec)
    
mysql> set global validate_password_length=1;
Query OK, 0 rows affected (0.00 sec)
    
mysql> set password=password("123456");
Query OK, 0 rows affected, 1 warning (0.00 sec)
    
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
    
查看mysql版本
[root@mysql-master ~]# mysql -p123456
........
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.24    |
+-----------+
1 row in set (0.00 sec)
   
=====================================================================
舒適提示
mysql5.7經過上面默認安裝後,執行語句可能會報錯:
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
   
這個報錯與Mysql 密碼安全策略validate_password_policy的值有關,validate_password_policy能夠取0、一、2三個值:
解決辦法:
set global validate_password_policy=0;
set global validate_password_length=1;

3. 配置Mysql基於GTID的主從同步  (在mysql-master 和 mysql-slave一、mysql-slave2節點上)

1) 主數據庫mysql-master (172.16.60.211)的配置操做
[root@mysql-master ~]# >/etc/my.cnf
[root@mysql-master ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
       
symbolic-links = 0
       
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
   
#GTID:
server_id = 1
gtid_mode = on
enforce_gtid_consistency = on
     
#binlog
log_bin = master-bin
log-slave-updates = 1 
binlog_format = row 
sync-master-info = 1     
sync_binlog = 1         
    
#relay log
skip_slave_start = 1

配置完成以後,別忘了重啓Mysql
[root@mysql-master ~]# systemctl restart mysqld 

登陸mysql,查看一下master狀態, 發現多了一項"Executed_Gtid_Set "
[root@mysql-master ~]# mysql -p123456
.........
mysql> show master status;
+-------------------+----------+--------------+------------------+------------------------------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                        |
+-------------------+----------+--------------+------------------+------------------------------------------+
| master-bin.000002 |      550 |              |                  | fc39b161-22ca-11e9-a638-005056ac6820:1-2 |
+-------------------+----------+--------------+------------------+------------------------------------------+
1 row in set (0.00 sec)

mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value                                |
+---------------+--------------------------------------+
| server_uuid   | fc39b161-22ca-11e9-a638-005056ac6820 |
+---------------+--------------------------------------+
1 row in set (0.00 sec)

mysql> show global variables like '%gtid%';
+----------------------------------+------------------------------------------+
| Variable_name                    | Value                                    |
+----------------------------------+------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                       |
| enforce_gtid_consistency         | ON                                       |
| gtid_executed                    | fc39b161-22ca-11e9-a638-005056ac6820:1-2 |
| gtid_executed_compression_period | 1000                                     |
| gtid_mode                        | ON                                       |
| gtid_owned                       |                                          |
| gtid_purged                      |                                          |
| session_track_gtids              | OFF                                      |
+----------------------------------+------------------------------------------+
8 rows in set (0.00 sec)

主庫執行從庫複製受權
mysql> grant replication slave,replication client on *.* to slave@'172.16.60.212' identified by "slave@123"; 
Query OK, 0 rows affected, 1 warning (0.09 sec)

mysql> grant replication slave,replication client on *.* to slave@'172.16.60.213' identified by "slave@123";
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.03 sec)


mysql> show grants for slave@'172.16.60.212';
+-------------------------------------------------------------------------------+
| Grants for slave@172.16.60.212                                                |
+-------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'172.16.60.212' |
+-------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show grants for slave@'172.16.60.213';
+-------------------------------------------------------------------------------+
| Grants for slave@172.16.60.213                                                |
+-------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'172.16.60.213' |
+-------------------------------------------------------------------------------+
1 row in set (0.00 sec)

在主數據庫機器上建立一個測試庫kevin(爲了測試效果)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci;  
Query OK, 1 row affected (0.02 sec)

mysql> use kevin;
Database changed
mysql> create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.17 sec)

mysql> insert into kevin.haha values(1,"congcong"),(2,"huihui"),(3,"grace");  
Query OK, 3 rows affected (0.16 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
+----+----------+
3 rows in set (0.00 sec)

2) 從數據庫mysql-slave1 (172.16.60.212)的配置操做
與主服務器配置大概一致,除了server_id不一致外,從服務器還能夠在配置文件裏面添加:"read_only=on" ,
使從服務器只能進行讀取操做,此參數對超級用戶無效,而且不會影響從服務器的複製;
[root@mysql-slave1 ~]# >/etc/my.cnf
[root@mysql-slave1 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
       
symbolic-links = 0
       
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
   
#GTID:
server_id = 2
gtid_mode = on
enforce_gtid_consistency = on
     
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
     
#relay log
skip_slave_start = 1 
read_only = on

配置完成以後,別忘了重啓Mysql
[root@mysql-slave1 ~]# systemctl restart mysqld

接着登陸mysql,作主從同步
[root@mysql-slave1 ~]# mysql -p123456
........
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
  
在從數據庫裏,使用change master 配置主從複製
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> change master to master_host='172.16.60.211',master_user='slave',master_password='slave@123',master_auto_position=1; 
Query OK, 0 rows affected, 2 warnings (0.24 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.211
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000002
          Read_Master_Log_Pos: 2069
               Relay_Log_File: mysql-slave1-relay-bin.000002
                Relay_Log_Pos: 2284
        Relay_Master_Log_File: master-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
............
............
           Retrieved_Gtid_Set: fc39b161-22ca-11e9-a638-005056ac6820:1-8
            Executed_Gtid_Set: 2afbc2f5-22cb-11e9-b9c0-00505688047c:1-2,
fc39b161-22ca-11e9-a638-005056ac6820:1-8
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

查看從庫的gtid
mysql> show global variables like '%gtid%';
+----------------------------------+------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                              |
+----------------------------------+------------------------------------------------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                                                                 |
| enforce_gtid_consistency         | ON                                                                                 |
| gtid_executed                    | 2afbc2f5-22cb-11e9-b9c0-00505688047c:1-2,
fc39b161-22ca-11e9-a638-005056ac6820:1-8 |
| gtid_executed_compression_period | 1000                                                                               |
| gtid_mode                        | ON                                                                                 |
| gtid_owned                       |                                                                                    |
| gtid_purged                      | 2afbc2f5-22cb-11e9-b9c0-00505688047c:1-2                                           |
| session_track_gtids              | OFF                                                                                |
+----------------------------------+------------------------------------------------------------------------------------+
8 rows in set (0.01 sec)

接着查看從數據庫的數據,發現kevin庫已經同步過來了!
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
+----+----------+
3 rows in set (0.00 sec)

3) 從數據庫mysql-slave2 (172.16.60.213)的配置操做
[root@mysql-slave2 ~]# >/etc/my.cnf
[root@mysql-slave2 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
       
symbolic-links = 0
       
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
   
#GTID:
server_id = 3
gtid_mode = on
enforce_gtid_consistency = on
     
#binlog
log_bin = master-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
     
#relay log
skip_slave_start = 1 
read_only = on

重啓mysqld
[root@mysql-slave2 ~]#  systemctl restart mysqld  

登陸mysql,作主從複製
[root@mysql-slave2 ~]# mysql -p123456
.........
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> change master to master_host='172.16.60.211',master_user='slave',master_password='slave@123',master_auto_position=1; 
Query OK, 0 rows affected, 2 warnings (0.17 sec)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.60.211
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000002
          Read_Master_Log_Pos: 2069
               Relay_Log_File: mysql-slave2-relay-bin.000002
                Relay_Log_Pos: 2284
        Relay_Master_Log_File: master-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..........
..........
           Retrieved_Gtid_Set: fc39b161-22ca-11e9-a638-005056ac6820:1-8
            Executed_Gtid_Set: 26e410b4-22cb-11e9-be44-005056880888:1-2,
fc39b161-22ca-11e9-a638-005056ac6820:1-8
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

ERROR: 
No query specified

查看從庫的gtid
mysql> show global variables like '%gtid%';
+----------------------------------+------------------------------------------------------------------------------------+
| Variable_name                    | Value                                                                              |
+----------------------------------+------------------------------------------------------------------------------------+
| binlog_gtid_simple_recovery      | ON                                                                                 |
| enforce_gtid_consistency         | ON                                                                                 |
| gtid_executed                    | 26e410b4-22cb-11e9-be44-005056880888:1-2,
fc39b161-22ca-11e9-a638-005056ac6820:1-8 |
| gtid_executed_compression_period | 1000                                                                               |
| gtid_mode                        | ON                                                                                 |
| gtid_owned                       |                                                                                    |
| gtid_purged                      | 26e410b4-22cb-11e9-be44-005056880888:1-2                                           |
| session_track_gtids              | OFF                                                                                |
+----------------------------------+------------------------------------------------------------------------------------+
8 rows in set (0.01 sec)

接着查看從數據庫的數據,發現kevin庫已經同步過來了!
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
+----+----------+
3 rows in set (0.00 sec)

4)再回到主數據庫mysql-master (172.16.60.211)上

查看master狀態,發現已經有兩個slave節點正常存在同步關係了
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|         3 |      | 3306 |         1 | 26e410b4-22cb-11e9-be44-005056880888 |
|         2 |      | 3306 |         1 | 2afbc2f5-22cb-11e9-b9c0-00505688047c |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)

5)測試數據同步
在主數據庫mysql-master (172.16.60.211)上更新數據
mysql> insert into kevin.haha values(10,"heifei"),(11,"huoqiu"),(12,"chengxihu");
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0

而後在兩個slave從數據庫上查看,發現已正常同步過來了
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 10 | heifei    |
| 11 | huoqiu    |
| 12 | chengxihu |
+----+-----------+
6 rows in set (0.00 sec)

4. 安裝配置ProxySQL
已經在上面第一步中介紹了安裝方法,這裏採用rpm包方式安裝,安裝過程省略........

4.1 ProxySQL實現讀寫分離

向ProxySQL中添加MySQL節點

使用insert語句添加主機到mysql_servers表中,其中:hostgroup_id 爲10表示寫組,爲20表示讀組。
 
[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1
............
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.16.60.211',3306);
Query OK, 1 row affected (0.000 sec)
 
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.16.60.212',3306);
Query OK, 1 row affected (0.000 sec)
 
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port) values(10,'172.16.60.213',3306);
Query OK, 1 row affected (0.000 sec)

==========================================================================================================
若是在插入過程當中,出現報錯:
ERROR 1045 (#2800): UNIQUE constraint failed: mysql_servers.hostgroup_id, mysql_servers.hostname, mysql_servers.port

說明可能以前就已經定義了其餘配置,能夠清空這張表 或者 刪除對應host的配置
MySQL [(none)]> select * from mysql_servers;
MySQL [(none)]> delete from mysql_servers;
Query OK, 6 rows affected (0.000 sec)
=========================================================================================================
 
查看這3個節點是否插入成功,以及它們的狀態。
MySQL [(none)]> select * from mysql_servers\G;
*************************** 1. row ***************************
       hostgroup_id: 10
           hostname: 172.16.60.211
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
*************************** 2. row ***************************
       hostgroup_id: 10
           hostname: 172.16.60.212
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
*************************** 3. row ***************************
       hostgroup_id: 10
           hostname: 172.16.60.213
               port: 3306
             status: ONLINE
             weight: 1
        compression: 0
    max_connections: 1000
max_replication_lag: 0
            use_ssl: 0
     max_latency_ms: 0
            comment:
6 rows in set (0.000 sec)
 
ERROR: No query specified
 
如上修改後,加載到RUNTIME,並保存到disk
MySQL [(none)]> load mysql servers to runtime;
Query OK, 0 rows affected (0.006 sec)
 
MySQL [(none)]> save mysql servers to disk; 
Query OK, 0 rows affected (0.348 sec)

監控後端MySQL節點
添加Mysql節點以後,還須要監控這些後端節點。對於後端是主從複製的環境來講,這是必須的,由於ProxySQL須要經過每一個節點的read_only值來自動調整
它們是屬於讀組仍是寫組。

首先在後端master主數據節點上建立一個用於監控的用戶名(只需在master上建立便可,由於會複製到slave上),這個用戶名只需具備USAGE權限便可。若是還需
要監控複製結構中slave是否嚴重延遲於master(這個俗語叫作"拖後腿",術語叫作"replication lag"),則還需具有replication client權限。

在mysql-master主數據庫節點行執行:
[root@mysql-master ~]# mysql -p123456
..........

mysql> create user monitor@'172.16.60.%' identified by 'P@ssword1!';
Query OK, 0 rows affected (0.03 sec)

mysql> grant replication client on *.* to monitor@'172.16.60.%';
Query OK, 0 rows affected (0.02 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)

而後回到mysql-proxy代理層節點上配置監控
[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1 
..........
MySQL [(none)]> set mysql-monitor_username='monitor';
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> set mysql-monitor_password='P@ssword1!';
Query OK, 1 row affected (0.000 sec)

修改後,加載到RUNTIME,並保存到disk
MySQL [(none)]> load mysql variables to runtime;
Query OK, 0 rows affected (0.001 sec)

MySQL [(none)]> save mysql variables to disk;
Query OK, 94 rows affected (0.079 sec)

驗證監控結果:ProxySQL監控模塊的指標都保存在monitor庫的log表中。
 
如下是鏈接是否正常的監控(對connect指標的監控):
注意:可能會有不少connect_error,這是由於沒有配置監控信息時的錯誤,配置後若是connect_error的結果爲NULL則表示正常。
MySQL [(none)]> select * from mysql_server_connect_log;
+---------------+------+------------------+-------------------------+---------------+
| hostname      | port | time_start_us    | connect_success_time_us | connect_error |
+---------------+------+------------------+-------------------------+---------------+
| 172.16.60.211 | 3306 | 1548665195883957 | 762                     | NULL          |
| 172.16.60.212 | 3306 | 1548665195894099 | 399                     | NULL          |
| 172.16.60.213 | 3306 | 1548665195904266 | 483                     | NULL          |
| 172.16.60.211 | 3306 | 1548665255883715 | 824                     | NULL          |
| 172.16.60.212 | 3306 | 1548665255893942 | 656                     | NULL          |
| 172.16.60.211 | 3306 | 1548665495884125 | 615                     | NULL          |
| 172.16.60.212 | 3306 | 1548665495894254 | 441                     | NULL          |
| 172.16.60.213 | 3306 | 1548665495904479 | 638                     | NULL          |
| 172.16.60.211 | 3306 | 1548665512917846 | 487                     | NULL          |
| 172.16.60.212 | 3306 | 1548665512928071 | 994                     | NULL          |
| 172.16.60.213 | 3306 | 1548665512938268 | 613                     | NULL          |
+---------------+------+------------------+-------------------------+---------------+
20 rows in set (0.000 sec)

如下是對心跳信息的監控(對ping指標的監控)
MySQL [(none)]> select * from mysql_server_ping_log;
+---------------+------+------------------+----------------------+------------+
| hostname      | port | time_start_us    | ping_success_time_us | ping_error |
+---------------+------+------------------+----------------------+------------+
| 172.16.60.211 | 3306 | 1548665195883407 | 98                   | NULL       |
| 172.16.60.212 | 3306 | 1548665195885128 | 119                  | NULL       |
...........
| 172.16.60.213 | 3306 | 1548665415889362 | 106                  | NULL       |
| 172.16.60.213 | 3306 | 1548665562898295 | 97                   | NULL       |
+---------------+------+------------------+----------------------+------------+
110 rows in set (0.001 sec)

read_only日誌此時也爲空(正常來講,新環境配置時,這個只讀日誌是爲空的)
MySQL [(none)]> select * from mysql_server_read_only_log;
Empty set (0.000 sec)

replication_lag的監控日誌爲空
MySQL [(none)]> select * from mysql_server_replication_lag_log;
Empty set (0.000 sec)

指定寫組的id爲10,讀組的id爲20。
MySQL [(none)]> insert into mysql_replication_hostgroups values(10,20,1);
Query OK, 1 row affected (0.000 sec)

在該配置加載到RUNTIME生效以前,先查看下各mysql server所在的組。
MySQL [(none)]> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+---------------+------+--------+--------+
| hostgroup_id | hostname      | port | status | weight |
+--------------+---------------+------+--------+--------+
| 10           | 172.16.60.211 | 3306 | ONLINE | 1      |
| 10           | 172.16.60.212 | 3306 | ONLINE | 1      |
| 10           | 172.16.60.213 | 3306 | ONLINE | 1      |
+--------------+---------------+------+--------+--------+
3 rows in set (0.000 sec)

3個節點都在hostgroup_id=10的組中。
如今,將剛纔mysql_replication_hostgroups表的修改加載到RUNTIME生效。
MySQL [(none)]> load mysql servers to runtime;
Query OK, 0 rows affected (0.003 sec)

MySQL [(none)]> save mysql servers to disk;
Query OK, 0 rows affected (0.361 sec)

一加載,Monitor模塊就會開始監控後端的read_only值,當監控到read_only值後,就會按照read_only的值將某些節點自動移動到讀/寫組。
例如,此處全部節點都在id=10的寫組,slave1和slave2都是slave,它們的read_only=1,這兩個節點將會移動到id=20的組。
若是一開始這3節點都在id=20的讀組,那麼移動的將是Master節點,會移動到id=10的寫組。
 
如今看結果
MySQL [(none)]> select hostgroup_id,hostname,port,status,weight from mysql_servers;
+--------------+---------------+------+--------+--------+
| hostgroup_id | hostname      | port | status | weight |
+--------------+---------------+------+--------+--------+
| 10           | 172.16.60.211 | 3306 | ONLINE | 1      |
| 20           | 172.16.60.212 | 3306 | ONLINE | 1      |
| 20           | 172.16.60.213 | 3306 | ONLINE | 1      |
+--------------+---------------+------+--------+--------+
3 rows in set (0.000 sec)

MySQL [(none)]> select * from mysql_server_read_only_log;
+---------------+------+------------------+-----------------+-----------+-------+
| hostname      | port | time_start_us    | success_time_us | read_only | error |
+---------------+------+------------------+-----------------+-----------+-------+
| 172.16.60.212 | 3306 | 1548665728919212 | 1684            | 1         | NULL  |
| 172.16.60.211 | 3306 | 1548665728918753 | 3538            | 0         | NULL  |
| 172.16.60.213 | 3306 | 1548665728919782 | 3071            | 1         | NULL  |

配置mysql_users
上面的全部配置都是關於後端MySQL節點的,如今能夠配置關於SQL語句的,包括:發送SQL語句的用戶、SQL語句的路由規則、SQL查詢的緩存、SQL語句的重寫等等。本小節是SQL請求所使用的用戶配置,例如root用戶。這要求咱們須要先在後端MySQL節點添加好相關用戶。這裏以root和sqlsender兩個用戶名爲例.

首先,在mysql-master主數據庫節點上執行:(只需master執行便可,會複製給兩個slave)
[root@mysql-master ~]# mysql -p123456
.........
mysql> grant all on *.* to root@'172.16.60.%' identified by 'passwd';
Query OK, 0 rows affected, 1 warning (0.04 sec)

mysql> grant all on *.* to sqlsender@'172.16.60.%' identified by 'P@ssword1!';
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.03 sec)

而後回到mysql-proxy代理層節點,配置mysql_users表,將剛纔的兩個用戶添加到該表中。
admin> insert into mysql_users(username,password,default_hostgroup) values('root','passwd',10);
Query OK, 1 row affected (0.001 sec)
 
admin> insert into mysql_users(username,password,default_hostgroup) values('sqlsender','P@ssword1!',10);
Query OK, 1 row affected (0.000 sec)
 
admin> load mysql users to runtime;
Query OK, 0 rows affected (0.001 sec)
 
admin> save mysql users to disk;
Query OK, 0 rows affected (0.108 sec)
 
mysql_users表有很多字段,最主要的三個字段爲username、password和default_hostgroup:
-  username:前端鏈接ProxySQL,以及ProxySQL將SQL語句路由給MySQL所使用的用戶名。
-  password:用戶名對應的密碼。能夠是明文密碼,也能夠是hash密碼。若是想使用hash密碼,能夠先在某個MySQL節點上執行
   select password(PASSWORD),而後將加密結果複製到該字段。
-  default_hostgroup:該用戶名默認的路由目標。例如,指定root用戶的該字段值爲10時,則使用root用戶發送的SQL語句默認
   狀況下將路由到hostgroup_id=10組中的某個節點。

admin> select * from mysql_users\G
*************************** 1. row ***************************
              username: root
              password: passwd
                active: 1
               use_ssl: 0
     default_hostgroup: 10
        default_schema: NULL
         schema_locked: 0
transaction_persistent: 1
          fast_forward: 0
               backend: 1
              frontend: 1
       max_connections: 10000
*************************** 2. row ***************************
              username: sqlsender
              password: P@ssword1!
                active: 1
               use_ssl: 0
     default_hostgroup: 10
        default_schema: NULL
         schema_locked: 0
transaction_persistent: 1
          fast_forward: 0
               backend: 1
              frontend: 1
       max_connections: 10000
2 rows in set (0.000 sec)
 
雖然這裏沒有詳細介紹mysql_users表,但上面標註了"注意本行"的兩個字段必需要引發注意。只有active=1的用戶纔是有效的用戶。
至於transaction_persistent字段,當它的值爲1時,表示事務持久化:當某鏈接使用該用戶開啓了一個事務後,那麼在事務提交/回滾以前,
全部的語句都路由到同一個組中,避免語句分散到不一樣組。在之前的版本中,默認值爲0,不知道從哪一個版本開始,它的默認值爲1。
咱們指望的值爲1,因此在繼續下面的步驟以前,先查看下這個值,若是爲0,則執行下面的語句修改成1。

MySQL [(none)]> update mysql_users set transaction_persistent=1 where username='root';
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> update mysql_users set transaction_persistent=1 where username='sqlsender';
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> load mysql users to runtime;
Query OK, 0 rows affected (0.001 sec)

MySQL [(none)]> save mysql users to disk;
Query OK, 0 rows affected (0.123 sec)

而後,分別使用root用戶和sqlsender用戶測試下它們是否能路由到默認的hostgroup_id=10(它是一個寫組)讀、寫數據。
下面是經過轉發端口6033鏈接的,鏈接的是轉發到後端真正的數據庫!
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "create database proxy_test"
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "show databases;"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| proxy_test         |
| sys                |
+--------------------+
[root@mysql-proxy ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'use proxy_test;create table t(id int);'
[root@mysql-proxy ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'show tables from proxy_test;'
+----------------------+
| Tables_in_proxy_test |
+----------------------+
| t                    |
+----------------------+
[root@mysql-proxy ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'show databases;'            
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| proxy_test         |
| sys                |
+--------------------+

而後再刪除上面這個測試庫
[root@mysql-proxy ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'drop database proxy_test;'
[root@mysql-proxy ~]# mysql -usqlsender -pP@ssword1! -P6033 -h127.0.0.1 -e 'show databases;'          
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

讀寫分離:配置路由規則
ProxySQL的路由規則很是靈活,能夠基於用戶、基於schema以及基於每一個語句實現路由規則的定製。本案例做爲一個入門配置,實現一個最簡單的語句級路由規則,從而實現讀寫分離。

必須注意: 這只是實驗,實際的路由規則毫不應該僅根據所謂的讀、寫操做進行分離,而是從各項指標中找出壓力大、執行頻繁的語句單獨寫規則、作緩存等等。和查詢規則有關的表有兩個:mysql_query_rules和mysql_query_rules_fast_routing,後者是前者的擴展表,1.4.7以後才支持該快速路由表。本案例只介紹第一個表。插入兩個規則,目的是將select語句分離到hostgroup_id=20的讀組,但因爲select語句中有一個特殊語句SELECT...FOR UPDATE它會申請寫鎖,因此應該路由到hostgroup_id=10的寫組.

[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1                        
............
MySQL [(none)]> insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',10,1), (2,1,'^SELECT',20,1);
Query OK, 2 rows affected (0.000 sec)

MySQL [(none)]> load mysql query rules to runtime;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> save mysql query rules to disk;
Query OK, 0 rows affected (0.272 sec)

須要注意: select ... for update規則的rule_id必需要小於普通的select規則的rule_id,由於ProxySQL是根據rule_id的順序進行規則匹配的。
   
再來測試下,讀操做是否路由給了hostgroup_id=20的讀組, 以下發現server_id爲2和3的節點 (即slave從節點)在讀組內
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
|           3 |
+-------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
|           3 |
+-------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select @@server_id'
+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+

讀操做已經路由給讀組,再看看寫操做。這裏以事務持久化進行測試。
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'start transaction;select @@server_id;commit;select @@server_id;'
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
+-------------+
| @@server_id |
+-------------+
|           3 |
+-------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'start transaction;select @@server_id;commit;select @@server_id;'
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
+-------------+
| @@server_id |
+-------------+
|           2 |

顯然,一切都按照預期進行。最後,若是想查看路由的信息,可查詢stats庫中的stats_mysql_query_digest表。
如下是該表的一個輸出格式示例(和本案例無關)。
[root@mysql-proxy ~]# mysql -uadmin -padmin -P6032 -h127.0.0.1                        
............
MySQL [(none)]> SELECT hostgroup hg, sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
+----+----------+------------+----------------------------------+
| hg | sum_time | count_star | digest_text                      |
+----+----------+------------+----------------------------------+
| 10 | 283841   | 1          | drop database proxy_test         |
| 10 | 161020   | 1          | create table t(id int)           |
| 10 | 36002    | 1          | create database proxy_test       |
| 20 | 2719     | 5          | select @@server_id               |
| 10 | 1250     | 3          | select @@server_id               |
| 10 | 1102     | 2          | show databases                   |
| 10 | 789      | 2          | start transaction                |
| 10 | 655      | 1          | SELECT DATABASE()                |
| 10 | 629      | 1          | show databases                   |
| 10 | 564      | 1          | show tables from proxy_test      |
| 10 | 286      | 2          | commit                           |
| 10 | 0        | 8          | select @@version_comment limit ? |
| 10 | 0        | 5          | select @@version_comment limit ? |
+----+----------+------------+----------------------------------+
13 rows in set (0.002 sec)

測試讀寫分離效果

因爲讀寫操做都記錄在proxysql的stats_mysql_query_digest表內。
爲了測試讀寫分離的效果,能夠先清空此表中以前的記錄 (即以前在實現讀寫分配路由配置以前的記錄)

下面這個命令是專門清空stats_mysql_query_digest表的  (使用"delete from stats_mysql_query_digest"  清空不掉!)
MySQL [(none)]> SELECT 1 FROM stats_mysql_query_digest_reset LIMIT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.002 sec)

MySQL [(none)]> select hostgroup,username,digest_text,count_star from stats_mysql_query_digest;              
Empty set (0.001 sec)

在mysql-proxy代理層節點,經過proxysql進行數據寫入,並查看
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select * from kevin.haha;'
+----+-----------+
| id | name      |
+----+-----------+
|  1 | congcong  |
|  2 | huihui    |
|  3 | grace     |
| 11 | huoqiu    |
| 12 | chengxihu |
| 21 | zhongguo  |
+----+-----------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'delete from kevin.haha where id > 3;'
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'insert into kevin.haha values(21,"zhongguo"),(22,"xianggang"),(23,"taiwan");'
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'update kevin.haha set name="hangzhou" where id=22 ;'                 
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e 'select * from kevin.haha;'                                           
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
| 21 | zhongguo |
| 22 | hangzhou |
| 23 | taiwan   |
+----+----------+

在mysql-master主數據庫和mysql-slave一、mysql-slave2從數據上查看
[root@mysql-master ~]# mysql -p123456
.........
mysql> select * from kevin.haha;
+----+----------+
| id | name     |
+----+----------+
|  1 | congcong |
|  2 | huihui   |
|  3 | grace    |
| 21 | zhongguo |
| 22 | hangzhou |
| 23 | taiwan   |
+----+----------+
6 rows in set (0.00 sec)

發如今客戶端經過proxysql插件更新的數據,已經寫到mysql-master主數據庫上,並同步到mysql-slave1和mysql-slave2兩個從數據庫上了!

最後在proxysql管理端查看讀寫分離
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032            
............
............
MySQL [(none)]> select hostgroup,username,digest_text,count_star from stats_mysql_query_digest;
+-----------+----------+------------------------------------------------+------------+
| hostgroup | username | digest_text                                    | count_star |
+-----------+----------+------------------------------------------------+------------+
| 10        | root     | insert into kevin.haha values(?,?),(?,?),(?,?) | 1          |
| 10        | root     | delete from kevin.haha where id > ?            | 1          |
| 10        | root     | update kevin.haha set name=? where id=?        | 1          |
| 20        | root     | select * from kevin.haha                       | 2          |
| 10        | root     | select @@version_comment limit ?               | 5          |
+-----------+----------+------------------------------------------------+------------+
5 rows in set (0.001 sec)

從上述結果就能夠看出proxysql實現的讀寫分離配置是成功的,讀請求是轉發到group20的讀組內,寫請求轉發到group10的寫組內!!

4.2 負載均衡測試  (加權輪詢)
如上已經配置好一主(mysql-master,在hostgroup10寫組內)、兩從(mysql-slave1和mysql-slave2,在hostgroup20讀組內) ,而且已經在"mysql_query_rules"表中配置了路由規則,即寫操做轉發到hostgroup10組,讀操做轉發到hostgroup20組.

MySQL [(none)]> 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 | reconnect | timeout | retries | delay | next_query_flagIN | mirror_flagOUT | mirror_hostgroup | error_msg | OK_msg | sticky_conn | multiplex | log | apply | comment |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+----------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+-----+-------+---------+
| 1       | 1      | NULL     | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT.*FOR UPDATE$ | NULL          | 0                    | CASELESS     | NULL    | NULL            | 10                    | NULL      | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL | 1     | NULL    |
| 2       | 1      | NULL     | NULL       | 0      | NULL        | NULL       | NULL       | NULL   | ^SELECT              | NULL          | 0                    | CASELESS     | NULL    | NULL            | 20                    | NULL      | NULL      | NULL    | NULL    | NULL  | NULL              | NULL           | NULL             | NULL      | NULL   | NULL        | NULL      | NULL | 1     | NULL    |
+---------+--------+----------+------------+--------+-------------+------------+------------+--------+----------------------+---------------+----------------------+--------------+---------+-----------------+-----------------------+-----------+-----------+---------+---------+-------+-------------------+----------------+------------------+-----------+--------+-------------+-----------+-----+-------+---------+
2 rows in set (0.000 sec)
 
因爲hostgroup10寫組內只要一個節點(mysql-master節點),hostgroup20讀組內有兩個節點(mysql-slave一、mysql-slave2)
因此這裏只能測試讀節點的負載均衡
 
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
 
再實驗下mysql -e跟多條語句,看看如何
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;select @@hostname;select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;select @@hostname;select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;select @@hostname;select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;select @@hostname;select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave1 |
+--------------+
[root@mysql-proxy ~]# mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;select @@hostname;select @@hostname"
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
+--------------+
| @@hostname   |
+--------------+
| mysql-slave2 |
+--------------+
 
由以上結果可能會猜測並可印證:
在一個client的一個連接週期內,全部query路由到同一臺後端!
即在同一個client的連接週期內,query路由不會轉發到同組內的不一樣後端節點機上,只能轉發到同一臺後端節點機上!
 
可是這只是個假象!!!   是由於正好用到了select @ 語句。
如官網所介紹:  sends a query that implicitly disables multiplexing. For example, if you run 「SELECT @a」 , ProxySQL will disable
multiplexing for that client and will always use the same backend connection
 
最後能夠知道: proxysql的負載方式目前僅爲加權輪詢一種(經驗證所確認),並沒有其餘機制!

===============================================================================
能夠編寫一個負載均衡的shell測試腳本:
[root@mysql-proxy ~]# which mysql
/usr/bin/mysql
[root@mysql-proxy ~]# vim /opt/test_proxysql_lb.sh
#!/bin/bash

i=0
while(($i<200))
do
        /usr/bin/mysql -uroot -ppasswd -P6033 -h127.0.0.1 -e "select @@hostname;" >> /tmp/test_proxy_sql_lb.txt
        let "i++"
        echo "$i"
        sleep 0.1
done

執行測試腳本:
[root@mysql-proxy ~]# sh -x /opt/test_proxysql_lb.sh > /dev/null 2>&1

執行後檢查結果
[root@mysql-proxy ~]# grep "mysql-slave1" /tmp/test_proxy_sql_lb.txt|wc -l
86
[root@mysql-proxy ~]# grep "mysql-slave2" /tmp/test_proxy_sql_lb.txt|wc -l 
114

以上查詢結果符合預期

4.3 開啓ProxySQL的Web統計功能

首先打開web功能
[root@mysql-proxy ~]#  mysql -uadmin -padmin -h127.0.0.1 -P6032  
............
............
MySQL [(none)]> update global_variables set variable_value='true' where variable_name='admin-web_enabled';
Query OK, 1 row affected (0.001 sec)

MySQL [(none)]> LOAD ADMIN VARIABLES TO RUNTIME;
Query OK, 0 rows affected (0.001 sec)

MySQL [(none)]> SAVE ADMIN VARIABLES TO DISK;
Query OK, 31 rows affected (0.070 sec)

而後查看端口和登陸web界面的用戶名和密碼,用戶名和密碼與stat帳戶一致:
MySQL [(none)]> select * from global_variables where variable_name LIKE 'admin-web%' or variable_name LIKE 'admin-stats%';
+-----------------------------------+----------------+
| variable_name                     | variable_value |
+-----------------------------------+----------------+
| admin-stats_credentials           | stats:stats    |                #帳戶密碼
| admin-stats_mysql_connections     | 60             |
| admin-stats_mysql_connection_pool | 60             |
| admin-stats_mysql_query_cache     | 60             |
| admin-stats_system_cpu            | 60             |
| admin-stats_system_memory         | 60             |
| admin-web_enabled                 | true           |
| admin-web_port                    | 6080           |                     #端口
+-----------------------------------+----------------+
8 rows in set (0.003 sec)

查看web端口是否正常打開

[root@mysql-proxy ~]# lsof -i:6080
COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
proxysql 22324 root   27u  IPv4 23010645      0t0  TCP *:6080 (LISTEN)

訪問http://172.16.60.214:6080並使用stats:stats登陸便可查看一些統計信息。

4.4  scheduler打印proxysql狀態到日誌

[root@mysql-proxy ~]# mkdir -p /opt/proxysql/log
[root@mysql-proxy ~]# vim /opt/proxysql/log/status.sh
#!/bin/bash
DATE=`date "+%Y-%m-%d %H:%M:%S"`
echo "{\"dateTime\":\"$DATE\",\"status\":\"running\"}" >> /opt/proxysql/log/status_log

[root@mysql-proxy ~]# chmod 777 /opt/proxysql/log/status.sh

而後在proxysql插入一條scheduler (定義每分鐘打印一次,即60000毫秒)
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
............
............
MySQL [(none)]> insert into scheduler(active,interval_ms,filename) values (1,60000,'/opt/proxysql/log/status.sh');
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> LOAD SCHEDULER TO RUNTIME;
Query OK, 0 rows affected (0.001 sec)

MySQL [(none)]> SAVE SCHEDULER TO DISK;
Query OK, 0 rows affected (0.105 sec)

而後查看日誌就能夠看到proxysql 的運行結果了:
[root@mysql-proxy ~]# tail -f /opt/proxysql/log/status_log 
{"dateTime":"2019-02-19 14:24:03","status":"running"}
{"dateTime":"2019-02-19 14:25:03","status":"running"}
{"dateTime":"2019-02-19 14:26:03","status":"running"}
{"dateTime":"2019-02-19 14:27:03","status":"running"}
相關文章
相關標籤/搜索