MySQL ProxySQL讀寫分離使用初探


目的

      在美團點評DBProxy讀寫分離使用說明文章中已經說明了使用目的,本文介紹ProxySQL的使用方法以及和DBProxy的性能差異。具體的介紹可以看官網的相關說明,並且這個中間件也是percona推的一款中間件。其特性和其他讀寫分離的中間件差距不大,具體的會在文中介紹。本文大致簡單的介紹在使用過程中的一些說明,也可以看官方的wiki獲得使用幫助。

環境: 

Distributor ID:    Ubuntu
Description:    Ubuntu 14.04.5 LTS
Release:    14.04
Codename:    trusty

下載

percona站點:

github/官網:

安裝

1)編譯安裝:

1:下載
wget https://github.com/sysown/proxysql/archive/v1.3.6.tar.gz

2:安裝依賴包
apt-get install automake bzip2 cmake make g++ gcc git openssl debconf-utils

3:解壓、編譯
make
make install
...
 Adding system startup for /etc/init.d/proxysql ...
   /etc/rc0.d/K20proxysql -> ../init.d/proxysql
   /etc/rc1.d/K20proxysql -> ../init.d/proxysql
   /etc/rc6.d/K20proxysql -> ../init.d/proxysql
   /etc/rc2.d/S20proxysql -> ../init.d/proxysql
   /etc/rc3.d/S20proxysql -> ../init.d/proxysql
   /etc/rc4.d/S20proxysql -> ../init.d/proxysql
   /etc/rc5.d/S20proxysql -> ../init.d/proxysql

4:修改非root啟動
添加用戶:
useradd proxysql
修改相關文件權限:
cd /var/lib/
chown -R proxysql.proxysql proxysql/
cd /etc/
chown -R proxysql.proxysql proxysql.cnf 
修改啟動命令
vi /etc/init.d/proxysql ->75行
proxysql $OPTS
改成
sudo -u proxysql /usr/bin/proxysql $OPTS

5啟動&關閉 /etc/init.d/proxysql start
/etc/init.d/proxysql stop

2)deb包安裝:

1:下載
wget https://github.com/sysown/proxysql/releases/download/v1.3.6/proxysql_1.3.6-dbg-ubuntu14_amd64.deb

2:安裝
dpkg -i proxysql_1.3.5-1.1.trusty_amd64.deb

3:非root用戶啟動,參考編譯安裝部分。

文件說明

通過啟動文件 /etc/init.d/proxysql里可以知道ProxySQL安裝好的數據目錄在 /var/lib/proxysql/,配置文件目錄在 /etc/proxysql.cnf。

root@proxysql:/var/lib/proxysql# pwd
/var/lib/proxysql
root@proxysql:/var/lib/proxysql# ls -lh
total 48K
-rw------- 1 proxysql proxysql  33K  5月  9 1152 proxysql.db
-rw------- 1 proxysql proxysql 7.4K  5月  9 1156 proxysql.log

root@proxysql:~# ls -lh /etc/proxysql.cnf 
-rw------- 1 proxysql proxysql 4.2K  5月  9 1145 /etc/proxysql.cnf

啟動之后,可以看到這些文件:proxysql.db是SQLITE的數據文件,proxysql配置,如后端數據庫的賬號、密碼、路由等存儲在這個數據庫里面,proxysql.log是日志文件。proxysql.pid這個pid文件。proxysql.cnf是ProxySQL的一些靜態配置項,比如一些啟動選項,sqlite的數據目錄等等。配置文件只在第一次啟動的時候讀取進行初始化,后面只讀取db文件。

進程說明

root@proxysql:~# ps -ef | grep proxysql
proxysql  35740      1  0 1220 ?        000000 /usr/bin/proxysql -c /etc/proxysql.cnf -D /var/lib/proxysql
proxysql  35741  35740  0 1220 ?        000000 /usr/bin/proxysql -c /etc/proxysql.cnf -D /var/lib/proxysql

和MySQL的很相似,我們啟動一個進程,然后fork出一個子進程,父進程負責監控子進程運行狀況如果掛了則拉起來,子進程負責執行真正的任務。

接口說明

和DBProxy一樣,ProxySQL也是有管理接口和客戶端接口,通過配置文件/etc/proxysql.cnf可以看到管理和客戶端接口的信息:

admin_variables=
{
        admin_credentials="admin:admin"
        mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock"
#       refresh_interval=2000
#       debug=true
}

mysql_variables=
{
        ...
... interfaces
="0.0.0.0:6033;/tmp/proxysql.sock" default_schema="information_schema" ...
... }

看到管理接口的端口是6032,賬號密碼是admin(可以動態修改)只能通過本地連接,客戶端接口的端口是6033,賬號密碼通過管理接口去設置。

庫、表說明

通過管理接口登錄,需要先裝好mysql客戶端,並且設置prompt

[client]
prompt      = \\u@\\h : \\d \\r:\\m:\\s>

通過管理接口進入ProxySQL

庫:

root@proxysql:~# mysql -uadmin -padmin -h127.0.0.1 -P6032
...
...
admin@127.0.0.1 : (none) 124308>show databases;
+-----+---------+-------------------------------+
| seq | name    | file                          |
+-----+---------+-------------------------------+
| 0   | main    |                               |
| 2   | disk    | /var/lib/proxysql/proxysql.db |
| 3   | stats   |                               |
| 4   | monitor |                               |
+-----+---------+-------------------------------+
4 rows in set (0.00 sec)
  • main 內存配置數據庫,表里存放后端db實例、用戶驗證、路由規則等信息。表名以 runtime_開頭的表示proxysql當前運行的配置內容,不能通過dml語句修改,只能修改對應的不以 runtime_ 開頭的(在內存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盤以供下次重啟加載。
  • disk 是持久化到硬盤的配置,sqlite數據文件。
  • stats 是proxysql運行抓取的統計信息,包括到后端各命令的執行次數、流量、processlist、查詢種類匯總/執行時間等等。
  • monitor 庫存儲 monitor 模塊收集的信息,主要是對后端db的健康/延遲檢查。

1)main庫:

admin@127.0.0.1 : (none) 020154>show tables from main;
+--------------------------------------+
| tables                               |
+--------------------------------------+
| global_variables                     |
| mysql_collations                     |
| mysql_query_rules                    |
| mysql_replication_hostgroups         |
| mysql_servers                        |
| mysql_users                          |
| runtime_global_variables             |
| runtime_mysql_query_rules            |
| runtime_mysql_replication_hostgroups |
| runtime_mysql_servers                |
| runtime_mysql_users                  |
| runtime_scheduler                    |
| scheduler                            |
+--------------------------------------+
13 rows in set (0.00 sec)

global_variables 設置變量,包括監聽的端口、管理賬號等,詳細可參考 https://github.com/sysown/proxysql/wiki/Global-variables。通過set來設置,如:

set mysql-monitor_ping_interval =10001;

mysql_collations:相關字符集和校驗規則。
mysql_query_rules:定義查詢路由規則。

CREATE TABLE mysql_query_rules (
    rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0,
    username VARCHAR,
    schemaname VARCHAR,
    flagIN INT 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,
    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,
    mirror_flagOUT INT UNSIGNED,
    mirror_hostgroup INT UNSIGNED,
    error_msg VARCHAR,
    log INT CHECK (log IN (0,1)),
    apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0,
    comment VARCHAR
  • rule_id: 表主鍵,自增。規則處理是以 rule_id 的順序進行。
  • active: 只有 active=1 的規則才會參與匹配。
  • username: 如果非 NULL,只有連接用戶是 username 的值才會匹配
  • schemaname: 如果非 NULL,只有查詢連接使用的db是 schemaname 的值才會匹配。注意如果是 NULL,不代表連接沒有使用schema,而是不倫任何schema都進一步匹配。
  • client_addr: 匹配客戶端來源IP
  • proxy_addr, proxy_port: 匹配本地proxysql的IP、端口。
  • digest: 精確的匹配一類查詢。
  • match_digest: 正則匹配一類查詢。query digest 是指對查詢去掉具體值后進行“模糊化”后的查詢。
  • match_pattern: 正則匹配查詢。
  • negate_match_pattern: 反向匹配,相當於對 match_digest/match_pattern 的匹配取反。
  • re_modifiers: 修改正則匹配的參數,比如默認的:忽略大小寫CASELESS、禁用GLOBAL。
    上面都是匹配規則,下面是匹配后的行為:
  • replace_pattern: 查詢重寫,默認為空,不rewrite。
  • destination_hostgroup: 路由查詢到這個 hostgroup。當然如果用戶顯式 start transaction 且 transaction_persistent=1,那么即使匹配到了,也依然按照事務里第一條sql的路由規則去走。
  • cache_ttl: 查詢結果緩存的毫秒數。proxysql這個 Query Cache 與 MySQL 自帶的query cache不是同一個。proxysql query cache也不會關心后端數據是否被修改,它所做的就是針對某些特定種類的查詢結果進行緩存,比如一些歷史數據的count結果。一般不設。
  • timeout: 這一類查詢執行的最大時間(毫秒),超時則自動kill。這是對后端DB的保護機制,默認mysql-default_query_timeout給的是10h。
  • retries: 語句在執行時失敗時,重試次數。默認由 mysql-query_retries_on_failure變量指定,默認為1 。
  • delay: 查詢延遲執行,這是ProxySQL提供的限流機制,會讓其它的查詢優先執行。
  • error_msg: 默認為NULL,如果指定了則這個查詢直接被 block 掉,馬上返回這個錯誤信息。這個功能也很實用,比如線上突然冒出一個 “壞查詢”,應用端不方便馬上發版解決,我們就可以在這配置一個規則,把查詢屏蔽掉,想正常的mysql報錯那樣拋異常。
  • multiplex: 連接是否復用。
  • log: 是否記錄查詢日志。
  • flagIN,flagOUT,apply
    • 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

mysql_replication_hostgroups:監視指定主機組中所有服務器的read_only值,並且根據read_only的值將服務器分配給寫入器或讀取器主機組

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,
    UNIQUE (reader_hostgroup))

定義 hostgroup 的主從關系。ProxySQL monitor 模塊會監控 HG 后端所有servers 的 read_only 變量,如果發現從庫的 read_only 變為0、主庫變為1,則認為角色互換了,自動改寫 mysql_servers 表里面 hostgroup 關系,達到自動 Failover 效果。

mysql_servers:設置后端MySQL的表

CREATE TABLE mysql_servers (
    hostgroup_id INT 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) )
  • hostgroup_id: ProxySQL通過 hostgroup (下稱HG) 的形式組織后端db實例。一個 HG 代表同屬於一個角色
    該表的主鍵是 (hostgroup_id, hostname, port),可以看到一個 hostname:port 可以在多個hostgroup里面,這樣可以避免從庫全都不可用時,依然可以把讀請求發到主庫上。一個 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設置的 max_connections,如果后端實例 hostname:port 在多個 hostgroup 里,以較大者為准,而不是各自獨立允許的最大連接數。
  • max_replication_lag: 允許的最大延遲,主庫不受這個影響,默認0。如果 > 0, monitor 模塊監控主從延遲大於閥值時,會臨時把它變為 SHUNNED
  • max_latency_ms: mysql_ping 響應時間,大於這個閥值會把它從連接池剔除(即使是ONLINE),默認0。
  • comment: 備注。

mysql_users:配置后端數據庫的賬號和監控的賬號

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 0,
    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))
  • 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。
  • transaction_persistent: 如果設置為1,連接上ProxySQL的會話后,如果在一個hostgroup上開啟了事務,那么后續的sql都繼續維持在這個hostgroup上,不倫是否會匹配上其它路由規則,直到事務結束。雖然默認是0。
  • frontend, backend: 目前版本這兩個都需要使用默認的1,將來有可能會把 Client -> ProxySQL (frontend) 與 ProxySQL -> BackendDB (backend)的認證分開。從 runtime_mysql_users 表內容看到,記錄數比 mysql_users 多了一倍,就是把前端認證與后端認證獨立出來的結果。
  • fast_forward: 忽略查詢重寫/緩存層,直接把這個用戶的請求透傳到后端DB。相當於只用它的連接池功能,一般不用,路由規則 .* 就行了。

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

 CREATE TABLE scheduler (
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1,
    interval_ms INTEGER CHECK (interval_ms>=100 AND interval_ms<=100000000) NOT NULL,
    filename VARCHAR NOT NULL,
    arg1 VARCHAR,
    arg2 VARCHAR,
    arg3 VARCHAR,
    arg4 VARCHAR,
    arg5 VARCHAR,
    comment VARCHAR NOT NULL DEFAULT '')
  • id : 調度器唯一標識,自增主鍵。
  • active : 是否開啟,默認開啟。
  • interval_ms : 工作的開始頻率(以毫秒為單位)。 最小interval_ms為100毫秒
  • filename : 執行的可執行文件的絕對路徑
  • arg1 to arg5 : 傳遞給執行文件的參數,最大允許5個參數
  • comment : 備注

關於main庫下的表的說明可以看這篇文章的說明:http://seanlook.com/2017/04/10/mysql-proxysql-install-config/ 

2)disk庫:

show tables from disk;
+------------------------------+
| tables                       |
+------------------------------+
| global_variables             |
| mysql_collations             |
| mysql_query_rules            |
| mysql_replication_hostgroups |
| mysql_servers                |
| mysql_users                  |
| scheduler                    |
+------------------------------+
7 rows in set (0.00 sec)

和上面介紹的main庫一樣。

3)stats庫:

stats_mysql_commands_counters統計各種SQL類型的執行次數和時間,通過參數mysql-commands_stats控制開關,默認是ture。

CREATE TABLE stats_mysql_commands_counters (
    Command VARCHAR NOT NULL PRIMARY KEY,
    Total_Time_us INT NOT NULL,
    Total_cnt INT NOT NULL,
    cnt_100us INT NOT NULL,
    cnt_500us INT NOT NULL,
    cnt_1ms INT NOT NULL,
    cnt_5ms INT NOT NULL,
    cnt_10ms INT NOT NULL,
    cnt_50ms INT NOT NULL,
    cnt_100ms INT NOT NULL,
    cnt_500ms INT NOT NULL,
    cnt_1s INT NOT NULL,
    cnt_5s INT NOT NULL,
    cnt_10s INT NOT NULL,
    cnt_INFs)
  • command:已執行的SQL命令的類型。 如:FLUSH,INSERT,KILL,SELECT FOR UPDATE等。
  • Total_Time_us:執行該類型命令的總時間(以微秒為單位)。
  • total_cnt:執行該類型的命令的總數。
  • cnt_100us, cnt_500us, ..., cnt_10s, cnt_INFs:在指定的時間限制內執行的給定類型的命令總數和前一個命令的總數。

stats_mysql_connection_pool:連接后端MySQL的連接信息。

CREATE TABLE stats_mysql_connection_pool (
    hostgroup VARCHAR,
    srv_host VARCHAR,
    srv_port VARCHAR,
    status VARCHAR,
    ConnUsed INT,
    ConnFree INT,
    ConnOK INT,
    ConnERR INT,
    Queries INT,
    Bytes_data_sent INT,
    Bytes_data_recv INT,
    Latency_us INT)
  • hostgroup:后端服務器所屬的主機組。請注意,單個后端服務器可以屬於多個主機組。
  • srv_host,srv_port:mysqld后端服務器正在偵聽連接的TCP端點的IP和Port。
  • status:后端服務器的狀態。可以有ONLINE,SHUNNED,OFFLINE_SOFT,OFFLINE_HARD。有關每個狀態意味着什么的詳細信息,請參閱上面的mysql_servers表的描述。
  • ConnUsed:ProxySQL當前使用多少個連接來向后端服務器發送查詢。
  • ConnFree:目前有多少個連接是空閑。
  • ConnOK:成功建立了多少個連接。
  • ConnERR:沒有成功建立多少個連接。
  • Queries:路由到此特定后端服務器的查詢數。
  • Bytes_data_sent:發送到后端的數據量。
  • Bytes_data_recv:從后端接收的數據量。
  • Latency_ms:從Monitor報告的當前ping以毫秒為單位的延遲時間。

stats_mysql_global:代表與MySQL相關的代理級別的全局統計,如:

  • Client_Connections_aborted:由於無效憑據或max_connections而導致的前端連接數已達到。
  • Client_Connections_connected - 當前連接的前端連接數。
  • Client_Connections_created - 到目前為止創建的前端連接數。
  • Questions :從前端發送的查詢總數。
  • Slow_queries:在全局變量中定義的運行時間超過閾值的毫秒數的查詢數mysql-long_query_time
  • 等等...

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

CREATE TABLE stats_mysql_processlist (
    ThreadID INT NOT NULL,
    SessionID INTEGER PRIMARY KEY,
    user VARCHAR,
    db VARCHAR,
    cli_host VARCHAR,
    cli_port VARCHAR,
    hostgroup VARCHAR,
    l_srv_host VARCHAR,
    l_srv_port VARCHAR,
    srv_host VARCHAR,
    srv_port VARCHAR,
    command VARCHAR,
    time_ms INT NOT NULL,
    info VARCHAR)
  • ThreadID:ProxySQL內線程的內部ID。
  • SessionID:ProxySQL會話ID。通過這個ID可以進行kill操作。
  • user:與MySQL客戶端連接到ProxySQL的用戶。
  • db:當前選擇的數據庫。
  • cli_host,cli_port:連接ProxySQL的IP和TCP端口。
  • hostgroup:當前主機組。如果正在處理查詢,則是查詢已被路由或將要路由的主機組,或默認主機組。可以通過這個查看該SQL到底是到哪個HG里。
  • l_srv_host,l_srv_port:ProxySQL的IP和TCP端口。
  • srv_host,srv_port - 后端MySQL服務器的IP和端口。
  • command:正在執行的MySQL查詢的類型。
  • time_ms:命令執行的時間(以毫秒為單位)。
  • info:正在執行的SQL。

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

stats_mysql_query_digest
Create TableCREATE TABLE stats_mysql_query_digest (
    hostgroup INT,
    schemaname VARCHAR NOT NULL,
    username VARCHAR NOT NULL,
    digest VARCHAR NOT NULL,
    digest_text VARCHAR NOT NULL,
    count_star INTEGER NOT NULL,
    first_seen INTEGER NOT NULL,
    last_seen INTEGER NOT NULL,
    sum_time INTEGER NOT NULL,
    min_time INTEGER NOT NULL,
    max_time INTEGER NOT NULL,
    PRIMARY KEY(hostgroup, schemaname, username, digest))
  • hostgroup:發送查詢的主機組。值-1表示查詢查詢緩存。
  • schemaname:查詢的數據庫。
  • user:連接ProxySQL的用戶名。
  • digest:一個十六進制散列,表示其參數剝離的SQL。
  • digest_text:參數剝離的實際SQL文本。
  • count_star:執行查詢的總次數(參數的值不同)。
  • first_seen:unix時間戳,是通過代理路由查詢的第一時刻。
  • last_seen:unix時間戳,當查詢通過代理路由時的最后一刻(到目前為止)。
  • sum_time:執行此類查詢的總時間(以微秒為單位)。這對於確定應用程序工作負載中花費的最多時間在哪里是非常有用的,並為改進的地方提供了一個良好的起點。
  • min_time,max_time - 執行此類查詢時期望的持續時間范圍。 min_time是到目前為止所看到的最小執行時間,而max_time表示最大執行時間,以微秒為單位。

stats_mysql_query_digest_reset和stats_mysql_query_digest結構一樣,stats_mysql_query_digest_reset可以清空stats_mysql_query_digest的數據,如執行:

select * from stats_mysql_query_digest_reset;
show create table stats.stats_mysql_query_digest_reset;

執行上面的任意一條就可以清空stats_mysql_query_digest表。

stats_mysql_query_rules:路由命中次數統計。

 CREATE TABLE stats_mysql_query_rules (
    rule_id INTEGER PRIMARY KEY,
    hits INT NOT NULL)
  • rule_id:路由規則的ID與main.mysql_query_rules的id對應。
  • hits:此路由規則的匹配總數。 如果當前傳入的查詢符合規則,則會記錄一次命中。

4)monitor庫: 對后端MySQL的健康檢查。由變量mysql-monitor_enabled來確定是否開啟Monitor模塊。

  • mysql_server_connect/mysql_server_connect_log:連接到所有MySQL服務器以檢查它們是否可用,該表用來存放檢測連接的日志。由變量mysql-monitor_connect_interval來控制其檢測的時間間隔,由參數mysql-monitor_connect_timeout控制連接是否超時(默認200毫秒)。
  • mysql_server_ping/mysql_server_ping_log:使用mysql_ping API ping后端MySQL服務器檢查它們是否可用,該表用來存放ping的日志。由變量mysql-monitor_ping_interval控制ping的時間間隔,默認值:10000(毫秒,相當於10秒)。
  • mysql_server_replication_lag_log:后端MySQL服務主從延遲的檢測。由參數mysql-monitor_replication_lag_interval控制檢測間隔時間, 如果復制滯后太大,可以暫時關閉從。由mysql_servers.max_replication_lag列控制。默認值:10000(毫秒,相當於10秒)。

配置

ProxySQL有一個完備的配置系統,持配置修改之后的在線保存、應用,不需要重啟之后生效。整個配置系統分三層設計。配置系統分為三層的目的有三個:
(1).自動更新
(2).盡可能的不重啟proxysql就可以修改配置
(3).方便回滾錯誤配置
整個配置系統分為三層,如下所示:

+-------------------------+
|         RUNTIME         |
+-------------------------+
       /|\          |
        |           |
    [1] |       [2] |
        |          \|/
+-------------------------+
|         MEMORY          |
+-------------------------+ _
       /|\          |      |\
        |           |        \
    [3] |       [4] |         \ [5]
        |          \|/         \
+-------------------------+  +-------------------------+
|          DISK           |  |       CONFIG FILE       |
+-------------------------+  +-------------------------+

RUNTIME 代表的是ProxySQL當前生效的正在使用的配置,包括 global_variables, mysql_servers, mysql_users, mysql_query_rules。無法直接修改這里的配置,必須要從下一層load進來。也就是說RUNTIME這個頂級層,就是proxysql運行過程中實際采用的那一份配置,這一份配置就是要影響實際生產的,所以將你的配置加進RUNTIME層時需要三思而行。

MEMORY 用戶可以將MySQL客戶端連接到此接口(admin接口),並查詢不同的表和數據庫是在mysql命令行修改的 main 里頭配置,可以認為是SQLite數據庫在內存的鏡像。也就是說MEMORY這個中間層,上面接着生產配置項RUNTIME,下面接着持久化層DISK,CONFIG FILE。MEMORY也是我們修改proxysql的唯一正常入口。一般的,我們修改一個配置,先改Memory,確認無誤后再接入生產(RUNTIME),和持久化到磁盤(DISK)。也就是說memeory里面的配置隨便改,不影響生產,也不影響磁盤中保存的數據。通過此接口可以修改mysql_servers、mysql_users、mysql_query_rules、global_variables等。

DISK / CONFIG FILE 持久存儲的那份配置,一般在$(DATADIR)/proxysql.db,在重啟的時候會從硬盤里加載。 /etc/proxysql.cnf文件只在第一次初始化的時候用到,完了后,如果要修改監聽端口,還是需要在管理命令行里修改,再 save 到硬盤。 也就是說DISK和CONFIG FILE這一層是持久化層,我們做的任何配置更改,如果不持久化下來,重啟后,配置都將丟失。

說明:proxysql的每一個配置項在三層中都存在,但是這三層是獨立的,也就是說,proxysql可以同時擁有三份配置,每層都是獨立的,可能三份都不一樣,可能三份都一樣。

當proxysql啟動時,首先讀取配置文件CONFIG FILE(/etc/proxysql.cnf),然后從該配置文件中獲取datadir,datadir中存儲的是sqlite的數據目錄。如果該目錄存在,且sqlite數據文件存在,那么正常啟動,將sqlite中的配置項讀進內存,並且加載進RUNTIME,用於初始化proxysql的運行。如果datadir目錄下沒有sqlite的數據文件,proxysql就會使用config file中的配置來初始化proxysql,並且將這些配置保存至數據庫。

修改配置:需要修改配置時,直接操作的是 MEMORAY(main)

以下命令可用於加載或保存 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中

以下命令加載或保存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

到此,PrxoySQL的說明已經大致介紹完,更多的信息可以看官方文檔介紹和官方wiki說明,后面接着開始測試ProxySQL的相關功能。

測試說明

1)讀寫分離

環境:

APP:192.168.200.25192.168.200.64
DB:
   M:192.168.200.202
   S:192.168.200.132
ProxySQL:192.168.200.24

① 配置后端MySQL。登入ProxySQL,把MySQL主從的信息添加進去。將主庫master也就是做寫入的節點放到HG 100中,salve節點做讀放到HG 1000。

admin@127.0.0.1 : (none) 12:37:05>insert into mysql_servers(hostgroup_id,hostname,port,weight,max_connections,max_replication_lag,comment) values(100,'192.168.200.202',3306,1,1000,10,'test proxysql');
Query OK, 1 row affected (0.00 sec)

admin@127.0.0.1 : (none) 12:37:13>insert into mysql_servers(hostgroup_id,hostname,port,weight,max_connections,max_replication_lag,comment) values(1000,'192.168.200.132',3306,1,1000,10,'test proxysql');
Query OK, 1 row affected (0.00 sec)

admin@127.0.0.1 : (none) 12:37:19>select * from mysql_servers;     
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------------+
| hostgroup_id | hostname        | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment       |
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------------+
| 100          | 192.168.200.202 | 3306 | ONLINE | 1      | 0           | 1000            | 10                  | 0       | 0              | test proxysql |
| 1000         | 192.168.200.132 | 3306 | ONLINE | 1      | 0           | 1000            | 10                  | 0       | 0              | test proxysql |
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------------+
2 rows in set (0.00 sec)

② 配置后端MySQL用戶。這個用戶需要先在后端MySQL(202,132)里真實存在,一個是監控賬號、一個是程序賬號:

-- 監控
dba@192.168.200.202 : 12:38:21>GRANT USAGE ON *.* TO 'proxysql'@'192.168.200.24' IDENTIFIED BY 'proxysql';
Query OK, 0 rows affected (0.00 sec)

-- 程序
dba@192.168.200.202 : 12:38:22>GRANT SELECT, INSERT, UPDATE, DELETE ON `sbtest`.* TO 'sbuser'@'192.168.200.24' identified by 'sbuser';
Query OK, 0 rows affected (0.00 sec)

在后端MySQL里添加完之后再配置ProxySQL:這里需要注意,default_hostgroup需要和上面的對應。

admin@127.0.0.1 : (none) 12:39:52>insert into mysql_users(username,password,active,default_hostgroup,transaction_persistent) values('sbuser','sbuser',1,100,1);
Query OK, 1 row affected (0.00 sec)

admin@127.0.0.1 : (none) 12:41:07>select * from mysql_users;
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| username | password | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| sbuser   | sbuser   | 1      | 0       | 100               | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
1 row in set (0.00 sec)

上面看到是一個明文密碼,也可以用password函數加密后的密碼進行代替。

③ 設置健康監測賬號:

admin@127.0.0.1 : (none) 12:42:38>UPDATE global_variables SET variable_value='proxysql' WHERE variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.00 sec)

admin@127.0.0.1 : (none) 12:42:44>UPDATE global_variables SET variable_value='proxysql' WHERE variable_name='mysql-monitor_password';
Query OK, 1 row affected (0.00 sec)

或則還行下面的:

admin@127.0.0.1 : (none) 12:44:24>set mysql-monitor_username='proxysql';
Query OK, 1 row affected (0.01 sec)

admin@127.0.0.1 : (none) 12:45:14>set mysql-monitor_password='proxysql';
Query OK, 1 row affected (0.01 sec)

其他變量的修改,登入管理接口按照需要可以自行調整: 

set mysql-default_charset='utf8mb4';
set mysql-query_retries_on_failure=0;
set mysql-ping_timeout_server=500;
set mysql-monitor_connect_timeout=1000;
set mysql-default_max_latency_ms=2000;
set mysql-monitor_replication_lag_interval=500;
set mysql-ping_interval_server_msec=3000;
set mysql-monitor_ping_interval=5000;
set mysql-connect_timeout_server_max=3000;

④ 加載配置和變量:因為修改了servers、users和variables,所以加載的時候要執行: 

-- 應用到線上
admin@127.0.0.1 : (none) 12:51:28>load mysql servers to runtime;
Query OK, 0 rows affected (0.00 sec)

admin@127.0.0.1 : (none) 12:56:27>load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

admin@127.0.0.1 : (none) 12:56:31>load mysql variables to runtime;
Query OK, 0 rows affected (0.01 sec)

-- 持久化
admin@127.0.0.1 : (none) 12:56:37>save mysql servers to disk;
Query OK, 0 rows affected (0.01 sec)

admin@127.0.0.1 : (none) 12:56:45>save mysql users to disk;
Query OK, 0 rows affected (0.00 sec)

admin@127.0.0.1 : (none) 12:56:50>save mysql variables to disk;
Query OK, 72 rows affected (0.00 sec)

要是是用明文密碼設置mysql_users,在這里可以用save命令來轉換成了hash值的密碼:

admin@127.0.0.1 : (none) 04:25:23>save mysql users to mem;
Query OK, 0 rows affected (0.00 sec)

admin@127.0.0.1 : (none) 04:25:33>select username,password from mysql_users;
+----------+-------------------------------------------+
| username | password                                  |
+----------+-------------------------------------------+
| sbuser   | *CA96E56547F43610DDE9EB7B12B4EF4C51CDDFFC |
+----------+-------------------------------------------+
1 row in set (0.00 sec)

⑤ 連接數據庫,通過proxysql的客戶端接口訪問(6033):

~$ mysql -usbuser -psbuser -h192.168.200.24 -P6033
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.33 (ProxySQL)
...
sbuser@192.168.200.24 : (none) 04:41:34>show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| sbtest             |
+--------------------+
2 rows in set (0.00 sec)

寫入測試數據:

sbuser@192.168.200.24 : sbtest 04:42:35>insert into sb values(1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

sbuser@192.168.200.24 : sbtest 04:44:12>select * from sb;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

sbuser@192.168.200.24 : sbtest 04:44:14>begin;
Query OK, 0 rows affected (0.00 sec)

sbuser@192.168.200.24 : sbtest 04:44:17>insert into sb values(11),(22),(33);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

sbuser@192.168.200.24 : sbtest 04:44:26>commit;
Query OK, 0 rows affected (0.00 sec)

sbuser@192.168.200.24 : sbtest 04:44:29>select * from sb;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|   11 |
|   22 |
|   33 |
+------+
6 rows in set (0.00 sec)

通過proxysql接口正常操作數據,從管理接口看看ProxySQL的統計信息:

-- 查看各類命令的執行情況
admin@127.0.0.1 : (none) 04:52:59>select Command,Total_Time_us,Total_cnt from stats_mysql_commands_counters where Total_cnt >0;
+---------+---------------+-----------+
| Command | Total_Time_us | Total_cnt |
+---------+---------------+-----------+
| BEGIN   | 314           | 1         |
| COMMIT  | 493           | 1         |
| INSERT  | 5021          | 2         |
| SELECT  | 2224          | 9         |
| SHOW    | 4577          | 5         |
+---------+---------------+-----------+
-- 查看各類SQL的執行情況
admin@127.0.0.1 : (none) 04:54:47>select * from stats_mysql_query_digest;

通過上面看到,ProxySQL已經正常啟動,但是在stats_mysql_query_digest的hostgroup中發現,讀和寫全部都是走100這個Master的HG,沒有用到從庫。主要原因就是ProxySQL的核心mysql_query_rules路由表沒有配置。proxysql是通過自定義sql路由規則就可以實現讀寫分離。

⑥ 定義路由規則,如:除select * from tb for update的select全部發送到slave,其他的的語句發送到master。

-- 發送到M
admin@127.0.0.1 : (none) 04:58:11>INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT.*FOR UPDATE$',100,1);
Query OK, 1 row affected (0.00 sec)
-- 發送到S
admin@127.0.0.1 : (none) 05:08:17>INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT',1000,1);
Query OK, 1 row affected (0.00 sec)

-- 加載
admin@127.0.0.1 : (none) 05:09:37>load mysql query rules to runtime;
Query OK, 0 rows affected (0.00 sec)
admin@127.0.0.1 : (none) 05:09:57>save mysql query rules to disk;
Query OK, 0 rows affected (0.00 sec)

說明:active表示是否啟用這個sql路由項,match_pattern就是我們正則匹配項,destination_hostgroup表示我們要將該類sql轉發到哪些mysql上面去,apply為1表示該正則匹配后,將不再接受其他匹配,直接轉發。具體的信息看上面的表介紹說明。路由規則添加完成,現在來測試下讀寫分離,先清空stats_mysql_query_digest統計表:

admin@127.0.0.1 : (none) 05:16:21>select * from stats_mysql_query_digest_reset;

寫入測試數據: 

sbuser@192.168.200.24 : sbtest 10:20:27>insert into sb values(1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

sbuser@192.168.200.24 : sbtest 10:20:29>select * from sb;
...

sbuser@192.168.200.24 : sbtest 10:20:34>start transaction;
Query OK, 0 rows affected (0.01 sec)

sbuser@192.168.200.24 : sbtest 10:20:41>insert into sb values(11),(22),(33);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

sbuser@192.168.200.24 : sbtest 10:20:46>commit;
Query OK, 0 rows affected (0.00 sec)

sbuser@192.168.200.24 : sbtest 10:20:51>select * from sb;
...

sbuser@192.168.200.24 : sbtest 10:20:56>select * from sb for update;
..

sbuser@192.168.200.24 : sbtest 10:21:11>insert into sb values(111),(222),(333);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

sbuser@192.168.200.24 : sbtest 10:21:20>select * from sb;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|   11 |
|   22 |
|   33 |
|    1 |
|    2 |
|    3 |
|   11 |
|   22 |
|   33 |
|  111 |
|  222 |
|  333 |
+------+
15 rows in set (0.01 sec)

查看統計信息:

select * from stats_mysql_query_digest;

看到讀寫分離已經成功。為了更直觀一點,使用sysbench測試讀寫分離是否正常:

./bin/sysbench --test=./share/sysbench/oltp_read_write.lua --mysql-host=192.168.200.24 --mysql-port=6033 --mysql-user=sbuser --mysql-password=sbuser --mysql-db=sbtest  --report-interval=10  --max-requests=0 --time=300 --threads=4 --tables=1  --table-size=500000 --skip-trx=on --db-ps-mode=disable --mysql-ignore-errors=1062 prepare/run/clean

為了更好的驗證,可以在sysbench運行期間,可以到后端的從MySQL上查看是否有查詢進來。執行完之后來看下統計表:

admin@127.0.0.1 : (none) 10:31:52>select hostgroup,schemaname,username,substr(digest_text,120,-120),count_star from stats_mysql_query_digest; +-----------+------------+----------+--------------------------------------------------------------------+------------+
| hostgroup | schemaname | username | substr(digest_text,120,-120)                                       | count_star |
+-----------+------------+----------+--------------------------------------------------------------------+------------+
| 100       | sbtest     | sbuser   | show processlist                                                   | 15         |
| 100       | sbtest     | sbuser   | INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)            | 123932     |
| 100       | sbtest     | sbuser   | DELETE FROM sbtest1 WHERE id=?                                     | 123932     |
| 100       | sbtest     | sbuser   | UPDATE sbtest1 SET c=? WHERE id=?                                  | 123932     |
| 100       | sbtest     | sbuser   | UPDATE sbtest1 SET k=k+? WHERE id=?                                | 123932     |
| 1000      | sbtest     | sbuser   | SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?                | 123932     |
| 100       | sbtest     | sbuser   | show tables                                                        | 1          |
| 100       | sbtest     | sbuser   | select * from sb for update                                        | 1          |
| 100       | sbtest     | sbuser   | start transaction                                                  | 1          |
| 1000      | sbtest     | sbuser   | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c          | 123932     |
| 1000      | sbtest     | sbuser   | SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ?                     | 123932     |
| 1000      | sbtest     | sbuser   | SELECT c FROM sbtest1 WHERE id=?                                   | 1239320    |
| 1000      | sbtest     | sbuser   | select * from sb                                                   | 3          |
| 1000      | sbtest     | sbuser   | SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c | 123932     |
| 100       | sbtest     | sbuser   | drop table sbtest1                                                 | 1          |
| 100       | sbtest     | sbuser   | commit                                                             | 1          |
| 100       | sbtest     | sbuser   | insert into sb values(?),(?),(?)                                   | 3          |
+-----------+------------+----------+--------------------------------------------------------------------+------------+

從上面的結果可知,路由規則已經生效,select語句均到從庫上執行了。

總結:

本文初步介紹了ProxySQL的安裝、相關表說明和讀寫分離。 后續還有ProxySQL其本身的特性說明:延遲讀取主庫、重寫查詢以及和DBProxy對比等,由於篇幅原因,放到下一篇文章里介紹。

參考文檔:

https://github.com/sysown/proxysql/wiki

http://proxysql.blogspot.jp/2015/09/proxysql-tutorial-setup-in-mysql.html

ProxySQL之安裝及配置詳解  推薦

ProxySQL之讀寫分離與分庫路由演示 推薦

MySQL中間件之ProxySQL安裝部署篇

MySQL中間件之ProxySQL_讀寫分離/查詢重寫配置

 


免責聲明!

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



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