文章目錄
- 說明
- 安裝部署
- 1.1 yum 安裝
- 1.2 啟停管理
- 1.3 查詢版本
- 1.4 Admin 管理接口
- 入門體驗
- 功能介紹
- 3.1 多層次配置系統
- 讀寫分離
- 將實例接入到代理服務
- 定義主機組之間的復制關系
- 配置路由規則
- 事務讀的配置
- 延遲閾值和請求轉發
- ProxySQL 核心表
- mysql_users
- mysql_servers
- mysql_replication_hostgroups
- mysql_query_rules
- 高級特性
- SQL 審計
- SQL 黑名單
- ProxySQL Cluster
- 搭建 ProxySQL Cluster
- 參考文檔
說明
MySQL 常見代理有 MySQ Proxy、Atlas、MaxScale、ProxySQ L其中 MySQL Proxy 是 MySQL 原廠研發的,沒有發布過 GA 版,項目已經 9 年沒有維護,官方不建議生產環境使用。另外三個項目都是第三方研發的開源代理,其中 ProxySQL 項目的 Star 最多,而且一直都在維護。本篇 SOP 主要介紹 ProxySQL 運維管理。
ProxySQL 官網:https://www.proxysql.com/
安裝部署
1.1 yum 安裝
以 CentOS Linux release 7.8.2003 (Core) 系統版本為例:
cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/centos/$releasever
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key
EOF
使用 yum 安裝,可以指定版本:
yum install proxysql OR yum install proxysql-version
1.2 啟停管理
service proxysql start # 啟動 proxysql
service proxysql stop # 停止 proxysql
service proxysql status # 查看 proxysql 狀態
1.3 查詢版本
proxysql --version
1.4 Admin 管理接口
當 ProxySQL 啟動后,將會監聽兩個端口:
**Admin 管理接口:**默認為 6032 該端口用于管理配置 ProxySQL。
**接收業務 SQL 接口:**默認為 6033 用于服務業務端口,類似于 MySQL 的 3306 端口。
Admin 管理接口兼容 MySQL 客戶端協議,所以可以直接使用 MySQL 客戶端連接這個管理接口。
mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '
一般來講 Admin 接口不需要額外配置,最有可能需要配置的是 Admin 用戶的密碼。
Admin> select @@admin-admin_credentials;
+---------------------------+
| @@admin-admin_credentials |
+---------------------------+
| admin:admin |
+---------------------------+
修改 Admin 接口密碼:
set admin-admin_credentials='admin:YouPassword';load admin variables to runtime; -- 立即生效
save admin variables to disk; -- 持久化磁盤
入門體驗
以下是測試使用的環境信息,操作系統均為 CentOS 7.9 版本。
ip 地址 | 角色 | 程序 |
---|---|---|
172.16.104.56 | 主節點 | MySQL 5.7.33 |
172.16.104.57 | 備節點 | MySQL 5.7.33 |
172.16.104.55 | 代理節點 | ProxySQL 2.4.3 |
接下來,一起簡單的測試一下 ProxySQL,使用下方命令登入管理端。
mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '-- 設置監控后端使用的賬號信息
set mysql-monitor_username = 'monitor';
set mysql-monitor_password = 'monitor';-- 配置生效
load mysql variables to runtime;
save mysql variables to disk;
在后端創建 ProxySQL 的監控賬戶:
create user 'monitor'@'%' identified with mysql_native_password by 'monitor';grant replication client on *.* to 'monitor'@'%';-- group replication
grant select on performance_schema.replication_group_member_stats to 'monitor'@'%';grant select on performance_schema.replication_group_members to 'monitor'@'%';
配置后端節點,寫入后端節點的 ip、端口、主機組。
insert into mysql_servers (hostgroup_id, hostname, port) values (1, '172.16.104.56', 3306);LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
配置訪問用戶,這里的用戶分為兩種含義:
- 前端用戶:客戶端用來訪問 ProxySQL 的用戶。
- 后端用戶:ProxySQL 用來訪問后端 MySQL 節點的用戶。
在此,案例中我們配置的前后端用戶一致。在 MySQL 中創建后端使用的賬號:
-- 創建后端用戶
create user 'op_user'@'%' identified by 'abc123';
grant all privileges on *.* to 'op_user'@'%';
將賬號信息錄入到 ProxySQL 中:
-- 寫入用戶信息
insert into mysql_users(username, password, default_hostgroup, comment) values ('op_user', 'abc123', 1, '后端用戶');-- 加載 & 持久化
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
連接代理節點,訪問數據庫:
mysql -u op_user -pabc123 -h 172.16.104.55 -P6033 -e'select @@hostname;'
+---------------+
| @@hostname |
+---------------+
| 172-16-104-56 |
+---------------+
功能介紹
ProxySQL 默認的配置文件位于/etc/proxysql.cnf,第一次啟動 ProxySQL 會初始化配置數據庫,往后的所有配置都可以在 ProxySQL 數據庫中修復,直接修改配置文件則不會生效,除非重新初始化。
3.1 多層次配置系統
ProxySQL 為了實現動態修改大部分配置項,不需要重啟,設計了多級配置系統,將配置從運行時環境移到內存,并在有需求時持久化到磁盤上。
- 最底層的是 DISK 庫和 CONFIG FILE,負責持久化保存配置。這里的 CONFIG FILE 就是傳統的配置文件,ProxySQL 啟動時,主要是從 DISK 庫中讀取配置加載到內存并最終加載到 runtime 生效,只有極少的幾個特定配置內容是從 CONFIG FILE 中加載的,除非是第一次初始化 ProxySQL 運行環境或者 DISK 庫為空。
- 中間層的是 MEMORY,表示的是內存數據庫,管理接口中的 main 庫。通過管理接口可以修改所有配置,都保存在內存數據庫中,此時并沒有生效也沒有持久化,需要 load 到上層 RUNTIME 才能生效,save 到下層 DISK 才能持久化保存。
- 最上層的是 RUNTIME,它是 ProxySQL 相關線程運行時讀取的數據結構。該數據結構中的配置都是已生效的配置。修改了 main 庫中的配置后,必須 load 到 runtime 數據結構中才能使其生效。
在上面的多層配置系統圖中,標注了** [1]、[2]、[3]、[4]、[5] ** 的序號。每個序號都有兩個操作方向 from/to b 以下是各序號對應的操作:
- [1] LOAD FROM MEMORY / LOAD TO RUNTIME
- [2] SAVE FROM RUNTIME / SAVE TO MEMORY
- [3] LOAD FROM DISK / LOAD TO MEMORY
- [4] SAVE FROM MEMORY / SAVE TO DISK
- [5] LOAD FROM CONFIG
另外,上面的 是什么?這表示要 加載/保存 的是哪類配置。 詳細如下:
+------------------------------------+
| tables |
+------------------------------------+
| global_variables | # (1)
| mysql_collations | # (N)
| mysql_group_replication_hostgroups | # (2)
| mysql_query_rules | # (3)
| mysql_query_rules_fast_routing | # (4)
| mysql_replication_hostgroups | # (5)
| mysql_servers | # (6)
| mysql_users | # (7)
| proxysql_servers | # (8)
| scheduler | # (9)
+------------------------------------+
(1)
中包含兩類變量,以 amdin 為前綴的表示 admin variables,以 mysql 為前綴的表示 mysql variables。(2,5,6)
對應的都是 mysql servers。(3,4)
對應的是 mysql query rules。(7)
對應的 mysql users。(9)
對應的 scheduler。(N)
只是一張表,保存的是 ProxySQL 支持的字符集和排序規則,不需要修改。(8)
是 ProxySQL 的集群配置表,對應 proxysql_servers。
在 ProxySQL 客戶端使用 DML/SET 語句修改配置,是直接在內存中修改的,所以需要使用命令持久化和激活,這也是官方推薦的管理方式。下面提供常見的管理語句:
- 激活/持久化 MySQL 用戶配置:
# Active current in-memory MySQL User configuration
LOAD MYSQL USERS TO RUNTIME;# Save the current in-memory MySQL User configuration to disk
SAVE MYSQL USERS TO DISK;
- 激活/持久化 MySQL 服務器配置和主機組配置:
# Active current in-memory MySQL Server and Replication Hostgroup configuration
LOAD MYSQL SERVERS TO RUNTIME;# Save the current in-memory MySQL Server and Replication Hostgroup configuration to disk
SAVE MYSQL SERVERS TO DISK;
- 激活/持久化 MySQL 查詢規則:
# Active current in-memory MySQL Query Rule configuration
LOAD MYSQL QUERY RULES TO RUNTIME;# Save the current in-memory MySQL Query Rule configuration to disk
SAVE MYSQL QUERY RULES TO DISK;
- 激活/持久化 MySQL 管理變量:
# Active current in-memory MySQL Variable configuration
LOAD MYSQL VARIABLES TO RUNTIME;# Save the current in-memory MySQL Variable configuration to disk
SAVE MYSQL VARIABLES TO DISK;
- 激活/持久化 ProxySQL 管理變量:
# Active current in-memory ProxySQL Admin Variable configuration
LOAD ADMIN VARIABLES TO RUNTIME;# Save the current in-memory ProxySQL Admin Variable configuration to disk
SAVE ADMIN VARIABLES TO DISK;
讀寫分離
在入門體驗中,已完成監控賬號、業務賬號的創建和配置,并將主節點完成接入。本小節,將介紹一個高頻的使用場景,就是讀寫分離。
將實例接入到代理服務
下圖,是當前的 mysql_servers 表的配置,只添加了主庫。
Admin> select * from mysql_servers;
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 1 | 172.16.104.56 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | |
+--------------+---------------+------+-----------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
現在將備庫也接入進來:
insert into mysql_servers (hostgroup_id, hostname, port) values (2, '172.16.104.57', 3306);LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
定義主機組之間的復制關系
主機之間的復制關系是通過 hostgroup_id 來綁定的,關系定義使用的是 mysql_replication_hostgroups 表。
insert into mysql_replication_hostgroups(writer_hostgroup, reader_hostgroup, check_type, comment) values(1, 2, 'read_only', 'op 集群');LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
ProxySQL 會基于后端節點 check_type 的值,來動態調整它所屬的主機組,所以必須保證從庫的 read_only 參數為 on 的狀態。
配置路由規則
路由的規則是在 mysql_query_rules 中配置:
insert into mysql_query_rules(rule_id, active, match_pattern, destination_hostgroup, apply) values (1, 1, '^SELECT.*FOR UPDATE$', 1, 1);
insert into mysql_query_rules(rule_id, active, match_pattern, destination_hostgroup, apply) values (2, 1, '^SELECT', 2, 1);
- rule_id:是規則 ID。
- active:表示是否啟動規則。
- match_pattern:表示匹配規則,支持正則匹配。
- apply:設置為 1,如果當前的規則匹配,則不再進行后續其他規則的匹配。
- destination_hostgroup:SQL轉發目的 hostgroup。
上方配置的路由規則效果如下:
- 所有的 SELECT FOR UPDATE 操作將發往主庫執行。
- 其他所有的 SELECT 操作將發往備庫執行。
- 除此之外的所有操作將默認發往主庫處理。
配置完成后,驗證一下:
mysql -u op_user -pabc123 -h 172.16.104.55 -P6033-- 測試執行 SQL 語句
select * from test_semi;
select * from test_semi where a = 10 for update;
連接管理節點,查看日志:
mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '-- 查詢 SQL 執行情況
select hostgroup, digest_text from stats.stats_mysql_query_digest order by first_seen desc;
+-----------+------------------------------------------------+
| hostgroup | digest_text |
+-----------+------------------------------------------------+
| 1 | select * from test_semi where a = ? for update |
| 2 | select * from test_semi |
+-----------+------------------------------------------------+
事務讀的配置
接下來我們驗證另外一個操作,顯式開啟事務后執行 SELECT 操作。
begin;
select * from test_semi;
update test_semi set c = 123 where a = 10;
select * from test_semi;
commit;
執行結果可以通過 stats.stats_mysql_query_digest 表進行觀測。這里直接說結論,顯式開啟事務后,會直接路由到主庫執行,該行為由 mysql_users 表中的 transaction_persistent 參數有關。創建用戶時,如果不指定 transaction_persistent 參數,其默認值為 1,表示事務開啟后,所有的操作都會在事務開啟的主機組中執行,此時會忽略所有的路由規則。
我們將 transaction_persistent 設置為 0 測試一下。
update mysql_users set transaction_persistent = 0 where username = 'op_user';-- 配置生效
LOAD MYSQL USERS TO RUNTIME;
開啟事務后,執行查詢可以看到是路由到了備庫,不過 transaction_persistent = 1 更符合我們對事務的認知習慣。
Admin> select hostgroup, digest_text from stats.stats_mysql_query_digest order by first_seen desc;
+-----------+----------------------------------------+
| hostgroup | digest_text |
+-----------+----------------------------------------+
| 1 | commit |
| 1 | update test_semi set c = ? where a = ? |
| 2 | select * from test_semi |
| 1 | begin |
+-----------+----------------------------------------+
延遲閾值和請求轉發
上方是一個比較簡單的讀寫分離配置,實際上我們還會遇到如下問題:
- 如果備庫宕機了,所有轉發的查詢都會失敗。
- 如果備庫的延遲過高,查詢會讀取到舊數據。
接下來我們通過配置 延遲閾值 和 路由權重 來解決。
- 備庫宕機了,所有的請求都會轉發到主庫。
- 為備庫設置延遲閾值,如果延遲大于該值,請求會自動轉發到主庫。
-- 寫入一個規則
insert into mysql_servers (hostgroup_id, hostname, port) values (2, '172.16.104.56', 3306);-- 修改備庫配置
update mysql_servers set weight = 100, max_replication_lag = 30 where hostname = '172.16.104.57';
第一條 SQL 將主庫加入到了 reader_hostgroup 中,這樣當備庫出現故障的時候,查詢會自動路由到主庫中。
第二條 SQL 調大了備庫的權重,這樣只有極少部分 SQL 會路由到主庫,同時將 max_replication_lag 調整到了 30,表示延遲如果大于 30 的時候,查詢會路由到主庫。
ProxySQL 核心表
本節會介紹 ProxySQL 中常用的表,熟悉這些表中字段的含義。
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 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,attributes VARCHAR CHECK (JSON_VALID(attributes) OR attributes = '') NOT NULL DEFAULT '',comment VARCHAR NOT NULL DEFAULT '',PRIMARY KEY (username, backend),UNIQUE (username, frontend))
- username & password:用戶名和密碼。
- active:是否激活賬號。
- use_ssl:設置為 1,則強制用戶使用 SSL 證書進行身份驗證。
- default_hostgroup:默認的主機組。如果沒有匹配的路由規則或路由規則沒配置,請求會轉發到默認主機組。
- default_schema:默認的 schema。如果不設置,則由 mysql-default_schema 決定。
- schema_locked:目前未實現。
- transaction_persistent:設置為 1,則代表一個事務內的所有請求都會轉發到第一個主機組內執行。
- fast_forward:設置為 1,則表示由該用戶發起的 SQL 會跳過重寫、緩存 等查詢處理層,執行轉發到后端。
- backend & frontend:當前沒有實現前后端分離,默認為 1 即可。
- max_connections:賬號的最大連接數,默認為 1。
- attributes:目前未實現。
- comment:注釋。
mysql_servers
用于配置后端的 MySQL 節點。
CREATE TABLE mysql_servers (hostgroup_id INT CHECK (hostgroup_id>=0) NOT NULL DEFAULT 0,hostname VARCHAR NOT NULL,port INT CHECK (port >= 0 AND port <= 65535) NOT NULL DEFAULT 3306,gtid_port INT CHECK ((gtid_port <> port OR gtid_port=0) AND gtid_port >= 0 AND gtid_port <= 65535) NOT NULL DEFAULT 0,status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE',weight INT CHECK (weight >= 0 AND weight <=10000000) NOT NULL DEFAULT 1,compression INT CHECK (compression IN(0,1)) 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:主機組 ID。
- hostname:后端節點的主機名或 IP。
- port:后端節點的端口。
- gtid_port:不詳。
- status:節點的狀態,有 ONLINE、SHUNNED、OFFLINE_SOFT、OFFLINE_HARD 四個取值。
- ONLINE:節點狀態正常,可對外服務。
- SHUNNED:節點暫時離線,無法對外服務。
- OFFLINE_SOFT:節點離線,在離線前會等待該節點的事務執行完。
- OFFLINE_HARD:節點離線,如果當前節點有事務正在執行會 Kill 掉。
- weight:讀寫分離的權重,權重越高被分發的請求就越多。
- compression:是否開啟壓縮。
- max_connections:限制 ProxySQL 到后端節點的最大連接數。
- max_replication_lag:主備的延遲閾值。一旦超過該值,該節點的狀態會被設置為 SHUNNED,直到延遲恢復。
- use_ssl:是否開啟 SSL 連接,針對的是 ProxySQL 與后端之間的連接。
- max_latency_ms:ProxySQL 會定期對后端節點進行 ping 操作,如果 ping 的響應時間超過該參數,則會將該節點從連接池中剔除。
- comment:注釋。
mysql_replication_hostgroups
用于配置復制關系的表。
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),check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only','innodb_read_only','super_read_only','read_only|innodb_read_only','read_only&innodb_read_only')) NOT NULL DEFAULT 'read_only',comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup))
- writer_hostgroup:定義可寫的主機組。
- reader_hostgroup:定義只讀的主機組。
- check_type:檢測類型,提供了多種選擇,基本都是通過 read_only 的值來區分的。
- comment:注釋。
將主庫和備庫的 hostgroup 配置到 mysql_replication_hostgroups 表中后,ProxySQL 會檢測主備庫的 read_only 狀態。
當檢測到 read_only 從 OFF 變成 ON 時,會將 writer_hostgroup 中的主機添加的 reader_hostgrup 中。
反之,當 read_only 從 ON 變成 OFF 時,會將其調整到 writer_hostgroup 組中。
由此可見,在 ProxySQL 中,一定要將備庫的 read_only 設置為 on,否則可能會出現雙寫。
當一個后端 MySQL 實例的 read_only 狀態從 ON 變成 OFF 時,會將該實例加入到 writer_hostgroup 中,同時該實例依然位于 read_hostgroup 中。如果需要將該實例從 read_hostgroup 中移除,需要將參數 mysql-monitor_writer_is_also_reader 設置為 false。
set mysql-monitor_writer_is_also_reader='false';
load mysql variables to runtime;
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 CHECK (flagIN >= 0) NOT NULL DEFAULT 0,client_addr VARCHAR,proxy_addr VARCHAR,proxy_port INT CHECK (proxy_port >= 0 AND proxy_port <= 65535),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 CHECK (flagOUT >= 0),replace_pattern VARCHAR CHECK(CASE WHEN replace_pattern IS NULL THEN 1 WHEN replace_pattern IS NOT NULL AND match_pattern IS NOT NULL THEN 1 ELSE 0 END),destination_hostgroup INT DEFAULT NULL,cache_ttl INT CHECK(cache_ttl > 0),cache_empty_result INT CHECK (cache_empty_result IN (0,1)) DEFAULT NULL,cache_timeout INT CHECK(cache_timeout >= 0),reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,timeout INT UNSIGNED CHECK (timeout >= 0),retries INT CHECK (retries>=0 AND retries <=1000),delay INT UNSIGNED CHECK (delay >=0),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)),gtid_from_hostgroup INT UNSIGNED,log INT CHECK (log IN (0,1)),apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0,attributes VARCHAR CHECK (JSON_VALID(attributes) OR attributes = '') NOT NULL DEFAULT '',comment VARCHAR)
- rule_id:指定規則的 ID。該值越小,越先匹配。
- active:是否啟用規則。
- username:基于用戶名進行匹配。
- schemaname:基于 schema 名進行匹配。
- flagIN & flagOUT:定義規則的入口和出口,用于實現鏈式匹配規則。
- client_addr:基于客戶端地址進行匹配。通過 client_addr 實現簡單的白名單功能。
- proxy_addr & proxy_port:如果 ProxySQL 部署的服務器中有多個 IP 地址,可匹配來自指定 IP 的流量。
- digest:基于 Query ID 進行匹配。
- match_digest & match_pattern:基于正則表達式進行匹配,match_digest 是匹配模版化后的 SQL,match_pattern 是匹配原 SQL。
- negate_match_pattern:設置為 1,表示沒匹配上 match_digest & match_pattern 的規則才為真。
- re_modifiers:設置正則引起的修飾符。
- replace_pattern:替換后的文本,用于查詢重寫。
- destination_hostgroup:規則目標的主機組。
- cache_ttl:設置結果集的緩存時長,單位是毫秒。
- cache_empty_result:是否緩存空的結果集。
- cache_timeout:暫未實現。
- reconnect:暫無實現。
- timeout:定義查詢的超時時長,單位是毫秒。如果查詢在指定時間沒有完成,則會被 ProxySQL kill 掉,如果不指定該字段,則由全局參數控制該行為 mysql-default_query_timeout 默認為 10 小時。
- retries:查詢失敗重試的次數。
- delay:定義查詢延遲執行的時長,單位是毫秒。
- mirror_flagOUT & mirror_hostgroup:用于景象功能。
- error_msg:匹配規則的操作將返回 error_msg,用于實現黑名單的功能。
- log:是否將匹配規則的查詢記錄到審計日志中。不指定的話,則由全局參數 mysql-eventlog_defalut_log 決定,默認為 0。
- apply:若設置為 1 的話,則操作匹配到該規則時,會直接被轉發給后端節點處理,不會再進行其他規則的匹配。
高級特性
本小節,介紹一下 ProxySQL 實用的高級特性。
SQL 審計
ProxySQL 可將流經它的 SQL 語句全部記錄下來,用于審計分析和問題定位。是一個非常實用的功能,不過數據庫流量如果比較大的話,會占用很大的存儲空間。
Admin> show variables like 'mysql-eventslog%';
+-----------------------------+-----------+
| Variable_name | Value |
+-----------------------------+-----------+
| mysql-eventslog_filename | |
| mysql-eventslog_filesize | 104857600 |
| mysql-eventslog_default_log | 0 |
| mysql-eventslog_format | 1 |
+-----------------------------+-----------+
各參數含義如下:
- mysql-eventslog_filename:日志前綴名。默認為空,代表 SQL 審計沒有開啟。
- mysql-eventslog_filesize:日志的最大大小。超過此限制,會對日志進行切割,默認為 100MB。
- mysql-eventslog_default_log:是否開啟操作審計,默認為 0 不記錄。
- mysql-eventslog_format:日志的格式。1 表示二進制格式 2 表示 JSON 格式。如果要查看二進制格式的內容,必須使用專用的解析工具 eventslog_reader_sample。
下面我們進行一個測試:
set mysql-eventslog_filename = 'query';
set mysql-eventslog_format = 2;
set mysql-eventslog_default_log = 1;LOAD MYSQL VARIABLES TO RUNTIME;
{"client":"172.16.104.56:38474","digest":"0xDC257DF652F9B5E6","duration_us":1764,"endtime":"2024-06-26 14:43:39.203870","endtime_timestamp_us":1719384219203870,"event":"COM_QUERY","hostgroup_id":2,"query":"select * from fractest1","rows_affected":0,"rows_sent":1,"schemaname":"test","server":"172.16.104.57:3306","starttime":"2024-06-26 14:43:39.202106","starttime_timestamp_us":1719384219202106,"thread_id":2,"username":"op_user"}
SQL 黑名單
當有一類 SQL 突然并發較高,打滿數據庫資源時,往往會導致數據庫整體變慢。此時處理的方法,往往是讓研發定位接口,然后停掉相關業務,及時止血,但也需要一定的時間,此時業務可能已經受損。
如果使用 ProxySQL 可以通過 SQL 黑名單的方式解決。接下來我們介紹通過 SQL 指紋來屏蔽 SQL 語句。
狀態庫 stats_mysql_query_digest 表中,記錄了一些 TOP SQL 的信息,可從該表中獲取 SQL 指紋。
select * from stats.stats_mysql_query_digest;-- digest 字段是 SQL 指紋
-- 0xDC257DF652F9B5E6 | select * from fractest1
獲取指紋后,需要寫入路由規則,需要注意的是,路由規則是按 rule_id 順序匹配的,所以屏蔽規則需要放在 rule_id 小的規則中,之前演示 rule_id = 1 和 2,所以限制改大。
Admin> update mysql_query_rules set rule_id = 11 where rule_id = 1;
Query OK, 1 row affected (0.00 sec)Admin> update mysql_query_rules set rule_id = 12 where rule_id = 2;
Query OK, 1 row affected (0.00 sec)
插入屏蔽規則:·
insert into mysql_query_rules (rule_id, destination_hostgroup, digest, error_msg, active, apply, comment) values (1, 1, '0xDC257DF652F9B5E6', 'request denied by rule', 1, 1, 'request denied by rule');load mysql query rules to runtime;
save mysql query rules to disk;
驗證屏蔽效果:
op_user@mysql 15:15: [test]>select * from fractest1;
ERROR 1148 (42000): request denied by rule
ProxySQL Cluster
ProxySQL 作為一個中間價,本身是無狀態的,如果代理節點出現故障,那就會導致業務無法訪問。所以線上一般會部署多個節點,使用 VIP 或者 LVS 來進行故障切換。既然涉及到多個節點,ProxySQL 的配置調整需要實時同步,這樣將流量切換到任意一個代理都是正確可用的。這就是接下來 ProxySQL Cluster 的作用。
搭建 ProxySQL Cluster
開啟 proxysql 的集群功能,需要:
- 配置 cluster 賬號,用于查詢對比集群內各 proxysql 節點的配置信息
- 配置 proxysql_servers,將集群內的 proxysql 節點信息添加到 proxysql_servers 表
以上操作需要到組成集群的每一個 proxysql 節點上執行。
通過參數 admin-cluster_username 和 admin-cluster_password 設置 cluster 賬號。不能使用 admin 賬號作為cluster 賬號,因為 admin 賬號只能在本地(127.0.0.1)登陸。
同時還需要將 cluster 賬號添加到參數 admin-admin_credentials 中。
set admin-admin_credentials = 'admin:admin;clusteradmin:passadmin';set admin-cluster_username='clusteradmin';
set admin-cluster_password='passadmin';load admin variables to runtime;
save admin variables to disk;
將組成 proxysql 集群的多個節點的信息添加到 proxysql_servers 表。
mysql> show create table proxysql_servers\G
*************************** 1. row ***************************table: proxysql_servers
Create Table: CREATE TABLE proxysql_servers (hostname VARCHAR NOT NULL,port INT NOT NULL DEFAULT 6032,weight INT CHECK (weight >= 0) NOT NULL DEFAULT 0,comment VARCHAR NOT NULL DEFAULT '',PRIMARY KEY (hostname, port) )
1 row in set (0.00 sec)insert into proxysql_servers values('172.16.104.55', 6032, 1, 'proxysql node 1');
insert into proxysql_servers values('172.16.104.56', 6032, 1, 'proxysql node 2');LOAD PROXYSQL SERVERS TO RUNTIME;
save PROXYSQL SERVERS TO disk;
參考文檔
【1】ProxySQL Multi layer configuration system