第一節 數據庫集群技術(shù)的現狀目前數據庫集群系統應用得比較成功,應用范圍比較廣泛的是:Oracle公司的Oracle9與IBM公司DB2。Oracle9采用Shared-storage的技術(shù),DB2選擇了Shared-nothing的技術(shù),二者各有長(cháng)短。
最新的數據庫集群系統的理論基礎是分布式計算,將數據分布到每個(gè)節點(diǎn),所有的計算節點(diǎn)并行處理數據,將結果匯總。這樣的方式無(wú)疑是最完美的。但是目前仍然不能實(shí)現全部的功能。
對于Shared-storage以及Shared-nothing的技術(shù)請參考Oracle以及IBM網(wǎng)站上的相關(guān)資料。
第二節 目前數據庫應用狀況目前數據庫應用狀況大致分為兩類(lèi),第一類(lèi)是數據量在100G以下,數據庫訪(fǎng)問(wèn)頻繁,請求密集。主要是Web APP類(lèi)型的應用,例如:網(wǎng)站,論壇等。這些Web APP類(lèi)型的應用訪(fǎng)問(wèn)數據庫的特點(diǎn)是:訪(fǎng)問(wèn)頻繁,數據庫每秒鐘要接受幾千次以上的查詢(xún),需要經(jīng)常追加數據,同時(shí)對數據的響應速度要求比較高。另一類(lèi)是用于科學(xué)計算、存儲歷史數據的應用,數據量往往達到幾百G。這些應用訪(fǎng)問(wèn)數據庫的特點(diǎn)是:多為查詢(xún)操作,數據都是分批、定時(shí)、集中倒入數據庫,數據庫的記錄非常多,積累了大量的數據,對數據庫的響應速度沒(méi)有太高要求。
第三節 暴露出來(lái)的問(wèn)題第一類(lèi)應用,由于訪(fǎng)問(wèn)比較頻繁,而且為了支持更多的訪(fǎng)問(wèn),Web Server一般都使用了負載均衡的集群,但是對于數據庫來(lái)說(shuō),由于無(wú)法實(shí)現集群操作,每秒鐘的請求不斷增加,隨著(zhù)服務(wù)器負載的增加,響應單個(gè)請求的速度越來(lái)越慢,如果庫文件比較大,出現寫(xiě)操作的時(shí)候還會(huì )出現鎖表時(shí)間過(guò)長(cháng)等影響訪(fǎng)問(wèn)效率的事情。
第二類(lèi)應用,主要是數據文件太大,每次處理數據都需要大量的時(shí)間,如果寫(xiě)錯一個(gè)語(yǔ)句就需要花幾個(gè)小時(shí)來(lái)重做查詢(xún)。
第四節 如何解決首先應當從硬件、軟件、程序、索引、SQL語(yǔ)句這幾個(gè)方面進(jìn)行優(yōu)化,如果仍然不能解決問(wèn)題,我們就要考慮數據庫系統的集群(并行處理)了。
對于第一類(lèi)的應用,在數據庫服務(wù)器正常運行,負載不高的情況下,應用對數據庫系統的狀況還是滿(mǎn)意的。但是數據庫系統負載過(guò)高之后,就會(huì )出現完成請求的時(shí)間加長(cháng),達不到系統的要求時(shí)間。既然負載是由于過(guò)多的請求造成的,我們就采取分擔請求的方式,讓一部分的請求去訪(fǎng)問(wèn)另外一臺服務(wù)器,讓單臺服務(wù)器的負載降低,從而解決問(wèn)題。
對于第二類(lèi)的應用,就需要分布式計算的系統來(lái)解決了,一般的系統是無(wú)能為力了。
第五節 針對于"Linux+Apache+PHP+MySQL"的第一類(lèi)應用問(wèn)題的解決方式一個(gè)實(shí)際案例的解決:
我在工作當中遇到了這樣的問(wèn)題,我們的Web Server是Linux+Apache+Php的三臺機器組成的集群,MySQL運行在SUN450,2G內存的平臺上。由于WEB的訪(fǎng)問(wèn)量在高峰的時(shí)候幾乎滿(mǎn)負荷運轉,LoadAvg(就是一分鐘之內處于Running狀態(tài)的進(jìn)程數量)都在10-20之間,反映出來(lái)就是大量的請求都在訪(fǎng)問(wèn)數據庫的時(shí)候被掛住了,導致一個(gè)請求沒(méi)有完成,下一個(gè)請求又進(jìn)來(lái),最后惡性循環(huán)。LoadAvg會(huì )在瞬間飆升至800以上。數據庫那邊就更糟糕了,LoadAvg達到 300多,數據庫的線(xiàn)程非常多,CPU忙于切換線(xiàn)程狀態(tài),這個(gè)時(shí)候除非Restart MySQL,否則怎么都不會(huì )好。在對SQL語(yǔ)句優(yōu)化完成后還是不能很好的解決問(wèn)題,我們增加了一臺數據庫服務(wù)器,通過(guò)MySQL的數據同步機制,讓兩臺數據庫上的數據保持同步,修改了一部分只會(huì )發(fā)生讀取操作的php程序,讓這些程序連接另外一臺數據庫,算是把負載分離出去一部分,問(wèn)題得到了初步的解決。但是后來(lái)業(yè)務(wù)做大,我們又增加了多臺服務(wù)器,修改了很多程序,分離他們對數據庫的讀取操作,訪(fǎng)問(wèn)不同的服務(wù)器。
第六節 MySQL-HA-Proxy方案的提出通過(guò)修改程序的方式實(shí)現將系統的負載分離,是件很痛苦的事情,工程浩大,而且不能弄錯,因為除了主服務(wù)器可以寫(xiě)入、修改數據,而其它的服務(wù)器只能通過(guò)數據同步更新自身的數據,所以如果你對那些數據庫進(jìn)行了寫(xiě)操作,結果將是災難性的。
如果我們能夠有一個(gè)程序分揀SQL語(yǔ)句,根據他的類(lèi)型(讀取/寫(xiě)入),分別傳送給不同的服務(wù)器,然后再將結果返回。采用一種類(lèi)似HTTP的PROXY的方式,這樣我們就不需要通過(guò)修改源程序的方式來(lái)分擔負載了,如果再能夠根據服務(wù)器的負載狀況,或者是表的狀態(tài)(可用/鎖定),來(lái)判斷應該將這個(gè)請求分配到哪臺服務(wù)器,那就比我們修改源程序所能達到的效果還要好。
第七節 MySQL Client 與 Server之間如何通信四處尋找,也沒(méi)有找到一篇關(guān)于Mysql通訊協(xié)議的文章,看來(lái)只有分析Mysql的源程序了。于是找來(lái)mysql 3.23.49的代碼,打開(kāi)sniffer工具。MySQL的通訊協(xié)議可能變更過(guò)多次,在3.23.49的版本里面,通訊協(xié)議的版本竟然是10。
簡(jiǎn)單的分析了一下通訊協(xié)議,現在規整如下,有些地方還不是很完善,由于我實(shí)在沒(méi)有太多的時(shí)間仔細研讀mysql的代碼,目前我只了解到了這些。
Server 對 Client 請求的響應數據格式:
| 偏移 | 區域 | 類(lèi)型 | 長(cháng)度(byte) | 說(shuō)明 |
| 0 | HEAD | Data Length | 3 | |
| 1 | |
| 2 | |
| 3 | | FLAG | 1 | =0普通信息 =1多段信息 =2認證返回 >2段結束字 |
| 4 | DATA | CMD Code | 1 | |
| 5 | | Message | DataLength - 1 | |
當FLAG=0 , 2的時(shí)候 CMD Code 與 Message 的定義
| CMDCode | 類(lèi)型 | Message的結構 |
| 00 | 狀態(tài)碼 | 偏移 | 類(lèi)型 | Length(byte) | |
| | 0 | Affect rows | 2 | |
| 0A | 服務(wù)器版本號 | 偏移 | 類(lèi)型 | Length(byte) | |
| 只有在剛剛連接上Server的時(shí)候有效,Server會(huì )馬上返回一個(gè)數據節段的信息 | 0 | VersionString | 8 | end of ‘\0‘ |
| 8 | Session ID | 4 | 32bits |
| 12 | UnKnown | 11 | |
| | | | |
| FF | 當出現錯誤的時(shí)候返回信息 | 偏移 | 類(lèi)型 | Length(byte) | |
| | 0 | ErrCode | 2 | |
| | 2 | ErrMsg | END | |
| FE | 多段信息傳輸的結束 | 空 |
Client 對 Server 提交數據的格式:
| 偏移 | 區域 | 類(lèi)型 | Length(byte) |
| 0 | HEAD | Data Length | 3 |
| 1 | | | |
| 2 | | | |
| 3 | | Compressed | 1 |
| 4 | DATA | Command ID | 1 |
| 5 | | Command Data | Data Length - 1 |
Command ID 與 Command Data 的說(shuō)明:
| ID | 類(lèi)型 | 數據格式 |
| 0 | COM_SLEEP | |
| 1 | COM_QUIT | NULL |
| 2 | COM_INIT_DB | Database name |
| 3 | COM_QUERY | stand query string |
| 4 | COM_FIELD_LIST | table name [128] wildcard[128] |
| 5 | COM_CREATE_DB | Database name |
| 6 | COM_DROP_DB | Database name |
| 7 | COM_REFRESH | options(bits) |
| 8 | COM_SHUTDOWN | NULL |
| 9 | COM_STATISTICS | NULL |
| 10 | COM_PROCESS_INFO | NULL |
| 11 | COM_CONNECT | |
| 12 | COM_PROCESS_KILL | sid[4] |
| 13 | COM_DEBUG | NULL |
| 14 | COM_PING | NULL |
| 15 | COM_TIME | |
| 16 | COM_DELAYED_INSERT | |
| 17 | COM_CHANGE_USER | [user][passwd][db] |
| 18 | COM_BINLOG_DUMP | |
| 19 | COM_TABLE_DUMP | |
| 20 | COM_CONNECT_OUT | |
第八節 Client 如何通過(guò) Server 的用戶(hù)認證協(xié)議分析完成了,我嘗試著(zhù)讓它工作起來(lái),可是認證這個(gè)部分遇到了麻煩,Mysql Server在Client連接上它的時(shí)候,會(huì )首先返回給Client一個(gè)數據包,包含協(xié)議的版本號,版本信息,SessionID,一個(gè)8字節的 Key,就是這個(gè)Key的原因。Client會(huì )使用這個(gè)Key來(lái)加密密碼,然后將用戶(hù)名,密碼,需要打開(kāi)的數據庫等信息發(fā)送給Server,這樣就完成認證了。我不知道Client是如何利用這個(gè)Key來(lái)加密的,所以我打算跳過(guò)密碼,我將Client的數據包重組,去掉Password的信息之后,我成功了,但是集群里面的Mysql用戶(hù)都是沒(méi)有密碼的,安全性多多少少有些問(wèn)題,不過(guò)這些服務(wù)器都是放在HA后面的,沒(méi)有外部的IP地址,應該問(wèn)題不大,不過(guò)多多少少是個(gè)缺憾。
但是我總要知道用戶(hù)的密碼是否正確吧?怎么辦呢?使用一個(gè)專(zhuān)用的Mysql來(lái)完成密碼認證。安裝一個(gè)最小化資源的Mysql Server用來(lái)做MysqlAuth(專(zhuān)用認證服務(wù)器),當Client連接后,就將MysqlAuth的第一個(gè)數據包返回給Client,這里面當然就包含著(zhù)Key,然后Client會(huì )使用這個(gè)Key,加密密碼之后,將認證信息發(fā)回來(lái),這個(gè)時(shí)候,MysqlHA系統就會(huì )將這個(gè)信息轉發(fā)給 MysqlAuth,并且自己保留一份,如果認證通過(guò)了,就把保留的那一份進(jìn)行重組,去掉密碼信息,然后用重組后的認證信息去連接集群中的服務(wù)器。
圖中HA就是使用HeartBeat方式建立的高可靠性系統(具體實(shí)現方法請參考
http://www.linuxvirtualserver.org/)。Proxy為Mysql-Proxy系統,MysqlAuth是專(zhuān)用的認證服務(wù)器。紅色的RealServer為主要服務(wù)器,可以進(jìn)行數據更新操作,同時(shí)將數據同步到其它的RealServer。
第十節 結束語(yǔ)我現在已經(jīng)基本完成了mysql-proxy的程序的開(kāi)發(fā),但是目前仍然處于測試階段,最新的版本是0.0.4,下一個(gè)版本仍然還在修訂中。從0.0.3版本開(kāi)始,mysql-proxy已經(jīng)可以完整的跑完mysql自身提供的sql-bench了,但是這個(gè)sql-bench只能提供單點(diǎn)的性能,沒(méi)有對集群的mysql系統提供測試功能。
系統提供了動(dòng)態(tài)采集RealServer上的LoadAvg然后反饋給Mysql Proxy的程序,但是由于這部分我沒(méi)有進(jìn)行測試,所以我在前面的測試中采用的請求分配方式是輪詢(xún)方式,如果出現兩個(gè)負載一樣的RealServer系統會(huì )自動(dòng)的在它們之間輪換選擇。
如何進(jìn)行系統測試?
既然是專(zhuān)門(mén)為L(cháng)inux+Apache+Php+Mysql這樣的系統做的集群,就應該找一個(gè)實(shí)際的應用來(lái)跑跑看,然后模擬大量的訪(fǎng)問(wèn),來(lái)進(jìn)行測試。
選擇一個(gè)論壇系統也許不錯,VBB吧,用的比較多,也比較流行。模擬訪(fǎng)問(wèn)就用Apache自身提供的AB來(lái)做。
測試系統的最小環(huán)境就是:(五臺機器)
1 x Apache + PHP1 x AB1 x Mysql Proxy + Mysql Auth Server2 x Mysql Real Server