MySQL Proxy 學習筆記

作者:heiyeluren
時間:2008-1-28
博客:http://blog.csdn.net/heiyeshuwu

【 測試平臺 】

服務器端:
OS:FreeBSD 6.2
Lua: 5.1.1
MySQL Server:4.1.22-log
MySQL Proxy: 0.6.0


客戶端:
OS:Windows XP Pro SP2
PHP: PHP 5.2.4 (cli)
MySQL Client: Ver 14.13 Distrib 5.1.19-beta for Win32

注意:本文使用的是最新版本 MySQL Proxy alpha 0.6.0 ,如果是0.5.0版本可能部分選項和操作不一致,同樣的,以後如果除了新版本,請參照新版本文檔。


【 MySQL Proxy 安裝 】

$ fetch http://mirror.mysql-partners-jp.biz/Downloads/MySQL-Proxy/mysql-proxy-0.6.0-freebsd6-x86.tar.gz
$ tar zxvf mysql-proxy-0.6.0-freebsd6-x86.tar.gz
$ cd mysql-proxy-0.6.0-freebsd6-x86
$ cp sbin/mysql-proxy /usr/local/sbin/如果無法正常使用,請檢查相應的其他組件是否安裝了,mysql-proxy 需要依賴 lua、libtool、glib、libevent 等庫。


【 初步使用 】

執行 mysql-proxy --help-all 查看所有的設置選項,比較重要的選項大致描述一下功能:

管理功能選項

--admin-address=host:port — 指定一個mysqo-proxy的管理端口,缺省是 4041代理功能選項

--proxy-address=host:port — 這個是mysql-proxy 服務器端的監聽端口,缺省是 4040
--proxy-read-only-backend-addresses=<host:port> — 遠程只讀Slave服務器的地址和端口,缺省爲不設置(本選項在mysql-proxy0.5.0版本中沒有)
--proxy-backend-addresses=host:port — 指定遠程MySQL服務器地址和端口,可以設置多個,缺省是 127.0.0.1:3306
--proxy-skip-profiling — 關閉查詢分析功能,缺省是打開的
--proxy-fix-bug-25371 — 修正 mysql的libmysql版本大於5.1.12的一個#25371號bug
--proxy-lua-script=file — 指定一個Lua腳本程序來控制mysql-proxy的運行和設置,這個腳本在每次新建連接和腳本發生修改的的時候將重新調用其他選項

--daemon — mysql-proxy以守護進程方式運行
--pid-file=file — 設置mysql-proxy的存儲PID文件的路徑我們執行試試,監聽本地MySQL是3000端口:
/usr/local/sbin/mysql-proxy --proxy-backend-addresses=127.0.0.1:3000

然後從我的windows機器使用mysql客戶端連接過去:
mysql -uroot -h 192.168.0.2 -P 4040

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 3
Server version: 4.1.22-log
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql>遠程的mysql-proxy缺省對外監聽的是4040端口,它會對連接4040端口的連接做處理後丟給後端3000端口的mysql服務器處理,把結果返回。
我們執行一條sql試試:

mysql> select version();
+------------+
| version()  |
+------------+
| 4.1.22-log |
+------------+
1 row in set (0.01 sec)
 

【 對兩臺/多臺MySQL的負載均衡 】

首先我們目前MySQL Proxy 是支持多臺後端MySQL數據庫的,它可以支持同時設置多個 --proxy-backend-addresses 選項來使用多個MySQL,比如:
/usr/local/sbin/mysql-proxy --proxy-address=192.168.0.2:3306 --proxy-backend-addresses=127.0.0.1:3000 --proxy-backend-addresses=192.168.0.2:4000
就分別連接了兩臺MySQL,一臺是3000端口,一臺是4000端口。

假設有兩臺Slave的讀數據服務器,我們使用mysql_proxy多個數據庫的輪詢技術來進行兩臺Slave數據庫的負載均衡分散訪問措施,mysql-proxy可以做到,缺省就具有了簡單的均衡功能,它自帶的均衡功能是當有多臺MySQL服務器的時候,進行逐個訪問的原則,比如有A、B兩臺MySQL服務器,那麼第一個連接就訪問A,第二個連接訪問B,第三個連接訪問A,一次分佈,達到A、B兩臺MySQL訪問均衡。

對於mysql-proxy這個功能,我們進行檢測一下。增加一個Lua檢測腳本 test-conn.lua,就一個函數:

function read_query( packet )
    print("read_query: connection.backend_ndx: ", proxy.connection.backend_ndx)
end執行:
/usr/local/sbin/mysql-proxy --proxy-address=192.168.0.2:3306 --proxy-backend-addresses=127.0.0.1:3000 --proxy-backend-addresses=192.168.0.2:4000 --proxy-lua-script=./test-conn.lua

在windows上調用mysql客戶端連接過去,打開多個cmd窗口進行連接:mysql -u root -h 192.168.0.2 -P 3306

看到mysql-proxy服務器端輸出結果:

read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2
很明顯是按照逐個來輪詢,這樣能夠達到平均分配連接的目的。

但是一個問題就是如果一臺機器硬件設備比另外一臺設備差,那麼對數據庫的連接就不能使用平均的方式了,那麼完全使用Lua腳本構建自己的輪詢連接算法,mysql-proxy的強大之處就在於能夠支持Lua腳本進行各種控制,包括 連接服務器(connect_server)、連接握手(read_handshake)、提交驗證(read_auth)、驗證結果(read_auth_result)、提交查詢(read_query)、查詢結果(read_query_result) 等控制都是通過簡單的在 --proxy-lua-script 選項中指定腳本來進行控制。

現在我們來簡單改進一下連接服務器連接分配的算法,就在Lua腳本中增加一個 connect_server 函數就行。
比如按照當前時間進行分佈連接到兩臺MySQL上:

function connect_server()
    if (tonumber(os.date("%M")) % 2 == 0) then
        proxy.connection.backend_ndx = 2
    else
        proxy.connection.backend_ndx = 1
    end
end或者我們採取隨機方式,在兩臺MySQL之間隨機挑選一臺:

function connect_server()
    local server_index = math.random(1, 2)
    proxy.connection.backend_ndx
end我們客戶端繼續連接多次,監測連接的服務器,發現連接的機器是隨機展開的:

read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     2
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     1
read_query: connection.backend_ndx:     2

【 壓力測試 】

1. 連接數據庫壓力測試

測試代碼使用PHP5.2,測試文件 php_mysql_proxy.php 代碼:

<?php
//連接函數
function mysql_proxy_connect($is_close=true){
    $link = mysql_connect("192.168.0.2:3306", "root", "", true);
    if (!$link){
        die('Could not connect: ' . mysql_error());
    }
    if ($is_close){
        echo ' close connection ... ';
        mysql_close($link);
    }
    return true;
}

//測試函數
function test($sum, $is_close=true){
    for($i=0; $i<$sum; $i++){
        echo "Connect mysql-proxy ". $i .".. ";
        if (mysql_proxy_connect($is_close)){
            echo "Succeed ";
        } else {
            echo "Failed ";
        }
       
    }
}
?>//測試1 (連續連接1w次,每次連接後不關閉連接)
test(10000);

Server: mysql-proxy 的CPU佔用是從0.1%一直升到 12.4% 左右,然後結束後慢慢減下來,mysqld 的cpu佔用率很低,%0.2左右
Client: 客戶端在連接後馬上關閉連接的狀態下,一直持續到3948個連接的時候無法再連接到mysql-proxy
客戶端輸出:

...
Connect mysql-proxy 3945.. close connection ... Succeed
Connect mysql-proxy 3946.. close connection ... Succeed
Connect mysql-proxy 3947.. close connection ... Succeed
Connect mysql-proxy 3948..
Warning: mysql_connect(): Can't connect to MySQL server on '192.168.0.2' (10048)
 in C:php_mysql_proxy.php on line 4
Could not connect: Can't connect to MySQL server on '192.168.0.2' (10048)//測試2(連續連接1w次,每次連接後不關閉連接)
test(10000, false);

Server: mysql-proxy 的CPU佔用是從0.1%一直升到 14.5% 左右,然後結束後慢慢減下來, mysqld 的cpu佔用率也很低,%0.2左右
Client: 客戶端在連接後馬上不關閉連接的狀態下,一直持續到3946個連接的時候無法再連接到mysql-proxy,基本跟關閉連接的最終處理數量差不多
輸出信息:

Connect mysql-proxy 3944.. Succeed
Connect mysql-proxy 3945.. Succeed
Connect mysql-proxy 3946..
Warning: mysql_connect(): Can't connect to MySQL server on '192.168.0.2' (10048)
 in C:php_mysql_proxy.php on line 4
Could not connect:

2. 執行查詢測試

測試腳本,php_mysql_proxy.php,代碼如下:

<?php
//時間函數
function microtime_float(){
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

//測試函數1(簡單查詢)
function test1(){
    $link = mysql_connect("192.168.0.2:3306", "root", "", true);
    if (!$link){
        die('Could not connect: ' . mysql_error());
    }
    for($i=0; $i<10000; $i++){
        $res = mysql_query("select now()",$link);
        echo "Query ".$i." ... ";
        if (!$res){
            echo('Could not query: ' . mysql_error());
            return false;
        }
        $row = mysql_fetch_row($res);
        echo " Succeed ";
    }
}

//測試函數2(複雜查詢)
function test2(){
    $link = mysql_connect("192.168.0.2:3306", "root", "", true);
    if (!$link){
        die('Could not connect: ' . mysql_error());
    }
    mysql_select_db("replaction", $link);
    for($i=0; $i<10000; $i++){
        $res = mysql_query("select * from t1 where id in (select id from t1)",$link);
        echo "Query ".$i." ... ";
        if (!$res){
            echo('Could not query: ' . mysql_error());
            return false;
        }
        while($row = mysql_fetch_row($res)){}
        echo " Succeed ";
    }   
}
?>
//執行測試1
$start_time = microtime_float();
test1();
$end_time = microtime_float();
echo "/nExecute Time: ". ($end_time - $start_time) ."/n";

測試結果:PHP執行時間和服務器端cpu佔用率
Execute Time: 39.4633390903
mysql-proxy: 17.56%
mysqld-1: 5.26%
mysqld-2: 2.12%

//執行測試2
$start_time = microtime_float();
test2();
$end_time = microtime_float();
echo "/nExecute Time: ". ($end_time - $start_time) ."/n";

測試結果:PHP執行時間和服務器端cpu佔用率
Execute Time: 62.6189789772
mysql-proxy: 19.09%
mysqld-1: 6.25%
mysqld-2: 3.08%

可以基本看出兩者差別不是非常大,也可能是因爲數據太少的緣故。


【 管理MySQL Proxy 】

在啓動 mysql-proxy 之後,就會打開兩個端口,一個是4040,這個是缺省用於提供給MySQL客戶端連接使用的端口,可以通過 --proxy-address 選項修改爲其他的,比如設置爲 --proxy-address=192.168.0.2:3306,就完全模擬成了一臺MySQL數據庫了。另外默認開放 4041 的端口,這個是用來提供給管理 mysql-proxy 使用的,可以使用標準的mysql客戶端來連接,同樣能夠通過 --admin-address 選項來設置爲其他管理端口。

目前版本的管理功能還比較弱,只能夠查看兩個貌似是數據表的關於 mysql-proxy 的一些信息:
 mysql -u root -h 192.168.0.2 -P 4041

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 1
Server version: 5.1.20-agent MySQL Enterprise Agent說明這是一個版本爲5.1.20的MySQL的代理程序,查看目前mysql-proxy的運行信息:


mysql> select * from proxy_connections;
+------+--------+-------+------------+
| id   | type   | state | db         |
+------+--------+-------+------------+
|    0 | server | 0     |            |
|    1 | proxy  | 0     |            |
|    2 | proxy  | 10    | replaction |
|    3 | server | 10    |            |
+------+--------+-------+------------+
4 rows in set (0.02 sec)

mysql> select * from proxy_config;
+----------------------------+------------------+
| option                     | value            |
+----------------------------+------------------+
| admin.address              | :4041            |
| proxy.address              | 192.168.0.2:3306 |
| proxy.lua_script           | NULL             |
| proxy.backend_addresses[0] | 127.0.0.1:3000   |
| proxy.fix_bug_25371        | 0                |
| proxy.profiling            | 1                |
+----------------------------+------------------+
6 rows in set (0.02 sec) 除了這兩個狀態信息,我貌似沒有發現別的,不過基本的運行信息都包含了。


【 總結 】

先說說優點,使用簡單,安裝方便,各種平臺的二進制版都有(這個是MySQL的傳統優點),同時性能不錯。
再說說缺點,缺點同樣很明顯,說兩個典型的缺點:

1. 無法 Master/Slave 的區分
我一開始興沖沖的以爲 --proxy-read-only-backend-addresses 選項來構建一個支持Master/Slave的環境進行測試,但是我反覆測試,發現無法實現,每次都是連接到Master,或者是做到每次都是按照連接算法來進行,mysql-proxy無法區分本次操作是寫入操作還是讀取操作而且劃分到不同的MySQL機器。我後來又嘗試也力求通過Lua腳本的方式來解決問題,自己定義連接情況,不過目前來看,定義的基本Lua接口,connect_server 是連接服務器,read_query 是整理SQL語句,我發現不論如何都是先執行了 connect_server 纔去執行 read_query 的, 就是是先連接MySQL,然後執行的查詢,這樣就無法實現先拿到SQL語句,然後進行分析,發現是 insert/update/delete 全部拿到Master去執行,剩餘的拿到Slave去執行,但是目前貌似無法實現,可能是我文檔讀的不夠,或者是操作方法不對,非常希望在日後新版本中有比較方便簡單的方式實現,因爲一般使用 mysql-proxy 的人來說,都是因爲負載高,數據連接太多或者是需要管理多臺Slave機器,目前讓 mysql-proxy 管理多臺服務器是沒有問題的,負載均衡也可以通過自行寫Lua腳本控制。

2. mysql-proxy admin的管理功能太弱
目前發現除了能夠查看兩項信息之外,mysql-proxy admin 功能沒有別的,比如重啓服務呀,或者是查看目前執行連接和執行的SQL語句等等都沒有,稍微弱了一點,希望在後期版本中加強。

大致功能都比較清楚了,測試速度也比較快,基本上目前來說,用於一些應用問題是不大的,穩定性也還好,畢竟目前是alpha版本,我們完全有熱情去期待在正式版中會有很多新功能和對目前功能的改進,我無比的期待着。


【 相關URL 】

[ MySQL Proxy 相關URL ]
下載地址:http://dev.mysql.com/downloads/mysql-proxy/index.html
官方手冊:http://dev.mysql.com/doc/refman/5.1/en/mysql-proxy.html
官方wiki:http://forge.mysql.com/wiki/MySQL_Proxy

[ Lua 相關URL ]
Lua官方網站:http://www.lua.org/
Lua英文手冊:http://www.lua.org/manual/5.1/
Lua中文手冊:http://www.codingnow.com/2000/download/lua_manual.html


(轉載請著名來源:http://blog.csdn.net/heiyeshuwu,本文如有紕漏或者不正確的地方,歡迎指正,謝謝!)


【補充】

added 2008-01-29: 今天在InfoQ上面看到一篇文章《用MySQL-Proxy實現讀寫分離》文章使用了一個Lua腳本實現了讀寫分離的實現,大家可以參考。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/heiyeshuwu/archive/2008/01/28/2069190.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章