一、亮點
幾乎所有的配置均可在線更改(其配置數據基於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之流的連接池實現。文中有詳細對比說明
二、安裝
rpm包下載地址
https://github.com/sysown/proxysql/releases 推薦rpm形式安裝
Installing from source
Make sure you have installed the equivalent for each of these packages for your operating system:
git clone https://github.com/sysown/proxysql.git
Go to the directory where you cloned the repo (or unpacked the tarball) and run:
Compilation time should be around a couple of minutes for the first time around. The configuration file will be found at /etc/proxysql.cnf afterwards.
在make這一步遇到了錯誤:
網查是由於gcc版本低導致,centos 6的yum源(以及epel源)都只能獲取到4.4.7版本
換到centos7上,將上述軟件安裝/更新之後,make步驟完成,但是make install步驟又出了問題:
update-rc.d是ubuntu的自啓動腳本管理軟件,未成功安裝不影響使用。
安裝完成後,自動在/etc/init.d/proxysql增加服務管理腳本(需要把/usr/local/bin/加入$PATH或者軟鏈至 $PATH目錄下,腳本中直接用到proxysql命令)
三、配置
配置文件/etc/proxysql.cnf和配置數據庫文件/var/lib/proxysql/proxysql.db,如果存在 “proxysql.db”文件,則啓動過程不解析proxysql.cnf文件;配置文件只在第一次啓動的時候讀取
官方推薦用admin interface方式
登陸admin interface:
注意:admin interface對配置的存儲是基於SQLite的,SQLite支持標準的SQL語法,與mysql也基本兼容。但是無法用use語句切換數據庫,作者對use語句做了兼容(不報錯),但是卻沒有實際效果。
配置後端DB server:
四、功能測試
實驗環境
負載均衡測試
配置好一主(db1,hostgroup0)兩從(db2和db3,hostgroup1) ,並且在’mysql_query_rules’表中增加一條路由規則
意爲所有以select開頭的語句路由到hostgroup1,其餘語句路由到hostgroup0
在兩臺server的mysql-client分別連接至proxysql的6033端口,執行’select @@hostname’觀察其分配到的後端server
以mysql -e的形式執行該命令則能夠看到請求在兩臺讀server之間變換
由以上結果可能會猜想並可印證:在一個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的負載方式目前僅爲加權輪詢
一種(經過作者確認的),並無其他機制。
後端server宕機測試
對上述架構用sysbench做只讀測試,過程中關閉(service mysqld stop)某一臺server (測試均在mysql-monitor_enabled=false的前提下)
測試命令
結果如下
不是說好的自動重連/重執行嗎?爲毛報錯了呢(atlas有同樣問題)
測試方法錯了:其實關閉後端mysql服務來測試“reconnect”特性應該說從本質上就是不對的,mysql正常關閉會kill掉其上的所有processlist,我們可以用mysql-client來做一些驗證
可以看到mysql-client是具有重連(reconnect)功能的,然後我們來做一個kill掉mysql-client線程(也就是mysql在關閉時會kill掉所有線程)的操作
我們看到了之前sysbenche測試過程中關閉一臺從庫時的報錯。也就是說這個場景下這個報錯不是proxysql的‘reconnect’機制的問題,倒更像是‘re-execute’機制的問題。而kill操作應該理解爲是mysql“主動”的動作,而非“異常”,所以這就不符合proxysql 的”re-execute”特性了,故而會報錯。
應該換一種方式來進行這個測試:
模擬網絡層無法通信的異常
我們在兩臺slave上通過iptables阻斷peoxysql到本機的3306端口來模擬無法鏈接和鏈接中斷異常
在sysbench開始之後再重啓iptables已經建立的鏈接會被保留,所以新規則要放到第一條的位置
-A INPUT -s 192.168.1.34 -p tcp -m tcp –dport 3306 -j DROP首先 :啓動sysbench只讀測試
然後 :在測試結束前,修改db1的iptables,禁止來自proxysql的請求進入
然後 :觀察sysbench的輸出和proxysql.log的輸出
結果 :sysbench等待很長時間,依然無法完成,同時,proxysql也不會把db1標記爲SHUNNED
proxysql.log輸出:然後,直接對後端node(db1)進行同樣的測試,發現結果是一樣的,sysbench等待很長時間依然無法完成也無報錯。
從這一點似乎可以判定在這個測試方法下,未達到預期結果的原因可能不在proxysql,而在sysbench本身。通過對重啓iptables之後的通信進行抓包(分別對針對proxysql和mysql在這個測試場景下進行抓包),命令如下:
~]# date; service iptables restart; tcpdump -i em2 host 192.168.1.35 and port 3306 and host not 192.168.1.10 -w /tmp/sysbench-proxysql-network-issue.pacp
~]# date; service iptables restart; tcpdump -i em2 host 192.168.1.34 and port 3306 and host not 192.168.1.10 -w /tmp/sysbench-proxysql-network-issue.pacp發現,sysbench“一直”在重傳由於iptables新規則而無法返回的幾個請求,所以就成了“無窮盡等待的樣子” (atlas 在這個場景下有同樣問題)
照理說,proxysql kill掉了一些查詢,會返回給sysbench錯誤,但爲什麼sysbench並未將錯誤展示出來呢(可能是因爲re-execute機制)
最後,通過跟作者溝通,發現是由於沒開啓monitor模塊,導致proxysql無法檢測到後端出了什麼類型的錯誤,也就無法執行對應各種後端錯誤的一些操作(之前我是特意關掉了monitor模塊)
1
2
3
4
5
6
7
8
測試對prepare
語句的支持
好多框架用prepare語句來避免SQL注入等安全問題,同時能在MySQL解析查詢方面降低一些開銷,所以對於prepare語句支持與否也很重要
首先要從MySQL協議層面瞭解prepare語句,分爲兩種(參考)
Prepared Statements in Application Programs
或者稱爲BINARY protocol
抓包分析一次prepare
,set
,execute
過程,可以觀察到,客戶端發送的是COM_STMT_PREPARE
Prepared Statements in SQL Scripts
或者稱爲TEXT protocol
抓包分析一次prepare
,set
,execute
過程,可觀察到客戶端發送的是COM_QUERY
關於prepare語句,作者給出的回覆和計劃如下:
這是我在實驗1.2.1版本時跟作者的溝通。現在已經發布1.3.5了,從1.3版本開始,兩種協議都支持了。但是在設置字符集方面,對於binary protocol 的prepare set names xxx和普通query(set names ‘utf8’ collate ‘utf8_general_ci’)(注意加了校對規則,不加校對規則可以)語句還無法正確處理(例如,php的laravel框架默認就是以第一種形式設置字符集)。
修正:經測試1.3.7版本,以上兩prepare語句的小bug都已解決
MySQL supports two type of prepared statements:
using API
using SQL Further details here
SQL support currently not supported either, because PREPARE doesn’t disable multiplexing, so it is possible that ProxySQL sends PREPARE in a connection, and EXECUTE into another.SQL support will be fixed in v1.2.3 , see #684 .
API support is planned in ProxySQL 1.3 .
五、connection-pool和multiplexing(並對比Atlas)
首先來精確理解一下這兩個詞,依作者回復
They are very related to each other
Connection pool
is a cache of connections that can be reused.Multiplexing
is a technique to reuse these connections.
後期逐漸瞭解到了proxysql的multiplexing。連接池是一個共享的池子裏面有跟後端創建好的一些連接,一個服務端腳本的執行過程中可能有多次sql請求:
atlas的連接池:從連接池中分配一條連接,在整個腳本執行期間一直佔有並使用該連接直到腳本執行完畢,然後將連接歸還連接池
而proxysql的連接池:腳本執行過程中的每次sql請求都經歷一次分配連接—-使用—-歸還的過程
很顯然,對於連接池的使用效率上來說,理論上多數情況下proxysql的方式會更加高效並且與DB間維護的鏈接數量會更少
測試場景:
分兩次測試,第一次測試腳本如下(每條命令一次連接)
第二次測腳本如下(一次連接,執行所有命令)
對ProxySQL進行測試分析
通過tcpdump抓包wireshark分析,通過ProxySQL對20條查詢的路由情況及其和後端MySQL之間的建立連接情況(通過ProxySQL上的原端口號)來分析連接池和禁用multiplexing的情況。結果彙總如下
第一次測試(每條命令一次連接)
第二次測試(一次連接,執行所有命令)
對比來看Atlas的分時分析
第一次測試(每條命令一次連接)
第二次測腳本如下(一次連接,執行所有命令)
由上面測試分析結果可以明顯的看到
六、proxysql對後端server健康檢查
可以主動
這兩種檢測的區別,據作者回復和抓包分析,總結如下:
Ping is done using mysql_ping()
通過抓包分析,是通過現有的鏈接(連接池中)發送一個Request Ping
語句
Connect is done using mysql_real_connect()
這是一個客戶端到服務器建立鏈接
,登錄
,退出登錄
,關閉鏈接
的完整過程這兩個函數的返回值不同,可以幫助proxysql理解與後端鏈接除了哪些問題。
模擬場景,驗證以上各設置並加深理解其故障檢測機制:
兩個前提修改web1 MySQL配置文件中
max_connections = 3
;重啓web1 MySQL,在其他tty打開幾個MySQL鏈接以確保proxysql無法鏈接該MySQL。同時在proxysql server上打開抓包功能tcpdump -i em2 host 192.168.1.4 and port 3306 -w /tmp/web_shun.pcap
,然後通過wireshark對比上面各值進行分析。
附件:數據包文件通過分析可驗以以下設置的有效性
1
2
3
4
5
1
2
3
4
5
6
7
8
在web1和web5在proxysql均爲online狀態下;
無客戶端訪問ProxySQL,即只驗證monitor模塊的行爲
可以被動
被動就是將全局變量‘mysql-monitor_enabled’置爲false,這種情況下,後端server故障後,proxysql不會主動探知,而是在有請求被“正常”路由到該server之後纔會在runtime層更改該server狀態爲‘SHUNNED’ 或者重新變爲‘ONLINE’。這個過程,應用無感知(表現爲mysql-client命令和sysbench均無報錯)
相關變量爲
1
2
3
4
5
6
7
8
七、關於proxysql和mysql中的最大連接數
首先明確下MySQL中的最大連接數由max_connections
變量控制,proxysql中的最大連接數有兩個方面的設置mysql_users.max_connections
和mysql_servers.max_connections
下面就直接說下我的結論 摘自我github上的issue
if the
mysql_servers.max_connections
is reached, some of the connections will wait until themysql-connect_timeout_server_max
is reached. then proxysql will return error messageSQLSTATE[HY000]: General error: 9001 Max connect timeout reached while reaching hostgroup 1 after 10000ms
.if the
mysql_users.max_connections
is reached, then the client will see the error message1040: Too many connections
If backend’s global variable ‘max_connections’ is reached and proxysql has no
ConnFree
with the backend, then client can accomplish the connection with proxysql but all queries will returnERROR 1040 (#HY00): Too many connections
, and the monitor will consider this backend isshun
and will be loged to the proxysql.log
八、據我所知的bug和不足
bug:
1. 對於prepare語句(Prepared Statements in Application Programs,見上文解釋。例如laravel框架的prepare語句),如果在backend上更改了表結構,在一些情況下會導致proxysql返回如下錯誤 SQLSTATE[HY000]: General error: 2057 A stored procedure returning result sets of different size was called. This is not supported by libmysql
2. 對於prepare語句的set names xxx
語句還不能有效處理
3. 對於非prepare語句的set names xxx collate xxxx
還不能有效處理
不足:
1. 前後端賬號分離:可以多個frontend用戶對應一個或少數banckend用戶,簡化後端MySQL上的授權操作,尤其是項目多而且之間庫表關聯較緊密時;還能將前端用戶和stats中相關表或者錯誤日誌關聯,非常方便的在衆多接入到ProxySQL的項目中定位到異常項目。
2. 錯誤日誌中對於SQL類錯誤只記錄了SQL語句和MySQL返回的錯誤信息,沒有關聯到用戶和庫表,在衆多項目中僅憑一條SQL語句去尋找源頭難度可想而知(其實這個跟第一條是有關聯的)。
3. 通過admin接口進行管理時,在作出多處修改時,無法一次性將修改應用到內存,也無法一次性將所有修改保存至磁盤。例如對mysql_servers, mysql_users,mysql_query_rules都
做了修改,就得分別使這三個方面的更改生效和保存至磁盤。反過來同理,假如做了一些更改但是最終想丟棄這些更改也無法方便的將其回覆到修改之前的狀態。
總結
穩定性方面:目前我們已經部分業務切換到了ProxySQL上,運行一直穩定,未遇到cpu負載高或者佔用內存多等情況。
運維/DBA友好:藉助於ProxySQL的錯誤日誌,我們發現了之前沒注意到的一些SQL問題(如主鍵重複類的問題等)。還通過stats庫裏的相關表定位了一些問題。
性能方面:也強於atlas(參見文章)
個人覺得,解決掉上述幾點bug和不足的話(且不說可能會出現的其他feature),ProxySQL就會更加強大和完美。
轉自:http://blog.csdn.net/kai404