1. 程式人生 > 實用技巧 >proxysql的讀寫分離設定

proxysql的讀寫分離設定

目的

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

環境:

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

下載

percona站點:

https://www.percona.com/downloads/proxysql/

github/官網:

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

安裝

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 11:52 proxysql.db
-rw------- 1 proxysql proxysql 7.4K  5月  9 11:56 proxysql.log

root@proxysql:~# ls -lh /etc/proxysql.cnf 
-rw------- 1 proxysql proxysql 4.2K  5月  9 11:45 /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 12:20 ?        00:00:00 /usr/bin/proxysql -c /etc/proxysql.cnf -D /var/lib/proxysql
proxysql  35741  35740  0 12:20 ?        00:00:00 /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
...
...
[email protected] : (none) 12:43:08>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庫:

[email protected] : (none) 02:01:54>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 Table: CREATE 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.25、192.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。

[email protected] : (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)

[email protected] : (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)

[email protected] : (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)裡真實存在,一個是監控賬號、一個是程式賬號:

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

-- 程式
[email protected] : 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需要和上面的對應。

[email protected] : (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)

[email protected] : (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函式加密後的密碼進行代替。

③ 設定健康監測賬號:

[email protected] : (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)

[email protected] : (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)

或則還行下面的:

[email protected] : (none) 12:44:24>set mysql-monitor_username='proxysql';
Query OK, 1 row affected (0.01 sec)

[email protected] : (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,所以載入的時候要執行:

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

[email protected] : (none) 12:56:27>load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

[email protected] : (none) 12:56:31>load mysql variables to runtime;
Query OK, 0 rows affected (0.01 sec)

-- 持久化
[email protected] : (none) 12:56:37>save mysql servers to disk;
Query OK, 0 rows affected (0.01 sec)

[email protected] : (none) 12:56:45>save mysql users to disk;
Query OK, 0 rows affected (0.00 sec)

[email protected] : (none) 12:56:50>save mysql variables to disk;
Query OK, 72 rows affected (0.00 sec)

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

[email protected] : (none) 04:25:23>save mysql users to mem;
Query OK, 0 rows affected (0.00 sec)

[email protected] : (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)
...
[email protected] : (none) 04:41:34>show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| sbtest             |
+--------------------+
2 rows in set (0.00 sec)

寫入測試資料:

[email protected] : 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

[email protected] : sbtest 04:44:12>select * from sb;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

[email protected] : sbtest 04:44:14>begin;
Query OK, 0 rows affected (0.00 sec)

[email protected] : 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

[email protected] : sbtest 04:44:26>commit;
Query OK, 0 rows affected (0.00 sec)

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

通過proxysql介面正常操作資料,從管理介面看看ProxySQL的統計資訊:

-- 檢視各類命令的執行情況
[email protected] : (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的執行情況
[email protected] : (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
[email protected] : (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
[email protected] : (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)

-- 載入
[email protected] : (none) 05:09:37>load mysql query rules to runtime;
Query OK, 0 rows affected (0.00 sec)
[email protected] : (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統計表:

[email protected] : (none) 05:16:21>select * from stats_mysql_query_digest_reset;

寫入測試資料:

[email protected] : 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

[email protected] : sbtest 10:20:29>select * from sb;
...

[email protected] : sbtest 10:20:34>start transaction;
Query OK, 0 rows affected (0.01 sec)

[email protected] : 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

[email protected] : sbtest 10:20:46>commit;
Query OK, 0 rows affected (0.00 sec)

[email protected] : sbtest 10:20:51>select * from sb;
...

[email protected] : sbtest 10:20:56>select * from sb for update;
..

[email protected] : 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

[email protected] : 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上檢視是否有查詢進來。執行完之後來看下統計表:

[email protected] : (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對比等,由於篇幅原因,放到下一篇文章裡介紹