基于MySQL的數據庫集群系統的實現
添加時間:2013-1-19 17:51:04
添加:
思海網絡
WebApp系統是否正在使用一個MySQL的數據庫系統?您的客戶是不是總是抱怨頁面結果反饋的非常慢?您的MySQL系統的負載是不是總是維持在一個非常高的狀態下?本文將為您提供一個分擔MySQL系統的負載的方法,以及由此派生出來的一個MySQL-HA-Proxy的開發項目。使用本文提供的方法,您將以最小的源代碼改動,獲得MySQL系統的高效運轉。
第一節 數據庫集群技術的現狀
目前數據庫集群系統應用得比較成功,應用范圍比較廣泛的是:Oracle公司的Oracle9與IBM公司DB2。Oracle9采用Shared-storage的技術,DB2選擇了Shared-nothing的技術,二者各有長短。
最新的數據庫集群系統的理論基礎是分布式計算,將數據分布到每個節點,所有的計算節點并行處理數據,將結果匯總。這樣的方式無疑是最完美的。但是目前仍然不能實現全部的功能。
對于Shared-storage以及Shared-nothing的技術請參考Oracle以及IBM網站上的相關資料。
第二節 目前數據庫應用狀況
目前數據庫應用狀況大致分為兩類,第一類是數據量在100G以下,數據庫訪問頻繁,請求密集。主要是Web APP類型的應用,例如:網站,論壇等。這些Web APP類型的應用訪問數據庫的特點是:訪問頻繁,數據庫每秒鐘要接受幾千次以上的查詢,需要經常追加數據,同時對數據的響應速度要求比較高。另一類是用于科學計算、存儲歷史數據的應用,數據量往往達到幾百G。這些應用訪問數據庫的特點是:多為查詢操作,數據都是分批、定時、集中倒入數據庫,數據庫的記錄非常多,積累了大量的數據,對數據庫的響應速度沒有太高要求。
第三節 暴露出來的問題
第一類應用,由于訪問比較頻繁,而且為了支持更多的訪問,Web Server一般都使用了負載均衡的集群,但是對于數據庫來說,由于無法實現集群操作,每秒鐘的請求不斷增加,隨著服務器負載的增加,響應單個請求的速度越來越慢,如果庫文件比較大,出現寫操作的時候還會出現鎖表時間過長等影響訪問效率的事情。
第二類應用,主要是數據文件太大,每次處理數據都需要大量的時間,如果寫錯一個語句就需要花幾個小時來重做查詢。
第四節 如何解決
首先應當從硬件、軟件、程序、索引、SQL語句這幾個方面進行優化,如果仍然不能解決問題,我們就要考慮數據庫系統的集群(并行處理)了。
對于第一類的應用,在數據庫服務器正常運行,負載不高的情況下,應用對數據庫系統的狀況還是滿意的。但是數據庫系統負載過高之后,就會出現完成請求的時間加長,達不到系統的要求時間。既然負載是由于過多的請求造成的,我們就采取分擔請求的方式,讓一部分的請求去訪問另外一臺服務器,讓單臺服務器的負載降低,從而解決問題。
對于第二類的應用,就需要分布式計算的系統來解決了,一般的系統是無能為力了。
第五節 針對于"Linux+Apache+PHP+MySQL"的第一類應用問題的解決方式
一個實際案例的解決:
我在工作當中遇到了這樣的問題,我們的Web Server是Linux+Apache+Php的三臺機器組成的集群,MySQL運行在SUN450,2G內存的平臺上。由于WEB的訪問量在高峰的時候幾乎滿負荷運轉,LoadAvg(就是一分鐘之內處于Running狀態的進程數量)都在10-20之間,反映出來就是大量的請求都在訪問數據庫的時候被掛住了,導致一個請求沒有完成,下一個請求又進來,最后惡性循環。LoadAvg會在瞬間飆升至800以上。數據庫那邊就更糟糕了,LoadAvg達到300多,數據庫的線程非常多,CPU忙于切換線程狀態,這個時候除非Restart MySQL,否則怎么都不會好。在對SQL語句優化完成后還是不能很好的解決問題,我們增加了一臺數據庫服務器,通過MySQL的數據同步機制,讓兩臺數據庫上的數據保持同步,修改了一部分只會發生讀取操作的php程序,讓這些程序連接另外一臺數據庫,算是把負載分離出去一部分,問題得到了初步的解決。但是后來業務做大,我們又增加了多臺服務器,修改了很多程序,分離他們對數據庫的讀取操作,訪問不同的服務器。
第六節 MySQL-HA-Proxy方案的提出
通過修改程序的方式實現將系統的負載分離,是件很痛苦的事情,工程浩大,而且不能弄錯,因為除了主服務器可以寫入、修改數據,而其它的服務器只能通過數據同步更新自身的數據,所以如果你對那些數據庫進行了寫操作,結果將是災難性的。
如果我們能夠有一個程序分揀SQL語句,根據他的類型(讀取/寫入),分別傳送給不同的服務器,然后再將結果返回。采用一種類似HTTP的PROXY的方式,這樣我們就不需要通過修改源程序的方式來分擔負載了,如果再能夠根據服務器的負載狀況,或者是表的狀態(可用/鎖定),來判斷應該將這個請求分配到哪臺服務器,那就比我們修改源程序所能達到的效果還要好。
第七節 MySQL Client與Server之間如何通信
四處尋找,也沒有找到一篇關于Mysql通訊協議的文章,看來只有分析Mysql的源程序了。于是找來mysql 3.23.49的代碼,打開sniffer工具。MySQL的通訊協議可能變更過多次,在3.23.49的版本里面,通訊協議的版本竟然是10。
簡單的分析了一下通訊協議,現在規整如下,有些地方還不是很完善,由于我實在沒有太多的時間仔細研讀mysql的代碼,目前我只了解到了這些。
偏移區域類型長度(byte)說明0HEADData Length3 1 2 3 FLAG1=0普通信息
=1多段信息
=2認證返回
>2段結束字4DATACMD Code1 5 MessageDataLength - 1
當FLAG=0 , 2的時候 CMD Code 與 Message 的定義
CMDCode類型Message的結構00狀態碼偏移類型Length(byte) 0Affect rows2 0A服務器版本號偏移類型Length(byte) 只有在剛剛連接上Server的時候有效,Server會馬上返回一個數據節段的信息0VersionString8end of '\0' 8Session ID432bits 12UnKnown11 FF當出現錯誤的時候返回信息偏移類型Length(byte) 0ErrCode2 2ErrMsgEND FE多段信息傳輸的結束空
Client對Server提交數據的格式:
偏移區域類型Length(byte)0HEADData Length31 2 3 Compressed14DATACommand ID15Command DataData Length - 1
Command ID與Command Data的說明:
ID 類型數據格式0COM_SLEEP 1COM_QUITNULL2COM_INIT_DBDatabase name3COM_QUERYstand query string4COM_FIELD_LISTtable name [128] wildcard[128]5COM_CREATE_DBDatabase name6COM_DROP_DBDatabase name7COM_REFRESHoptions(bits)8COM_SHUTDOWNNULL9COM_STATISTICSNULL10COM_PROCESS_INFONULL11COM_CONNECT 12COM_PROCESS_KILLsid[4]13COM_DEBUGNULL14COM_PINGNULL15COM_TIME 16COM_DELAYED_INSERT 17COM_CHANGE_USER[user][passwd][db]18 COM_BINLOG_DUMP 19COM_TABLE_DUMP 20COM_CONNECT_OUT
第八節 Client如何通過Server的用戶認證
協議分析完成了,我嘗試著讓它工作起來,可是認證這個部分遇到了麻煩,Mysql Server在Client連接上它的時候,會首先返回給Client一個數據包,包含協議的版本號,版本信息,SessionID,一個8字節的Key,就是這個Key的原因。Client會使用這個Key來加密密碼,然后將用戶名,密碼,需要打開的數據庫等信息發送給Server,這樣就完成認證了。我不知道Client是如何利用這個Key來加密的,所以我打算跳過密碼,我將Client的數據包重組,去掉Password的信息之后,我成功了,但是集群里面的Mysql用戶都是沒有密碼的,安全性多多少少有些問題,不過這些服務器都是放在HA后面的,沒有外部的IP地址,應該問題不大,不過多多少少是個缺憾。
第一節 數據庫集群技術的現狀
目前數據庫集群系統應用得比較成功,應用范圍比較廣泛的是:Oracle公司的Oracle9與IBM公司DB2。Oracle9采用Shared-storage的技術,DB2選擇了Shared-nothing的技術,二者各有長短。
最新的數據庫集群系統的理論基礎是分布式計算,將數據分布到每個節點,所有的計算節點并行處理數據,將結果匯總。這樣的方式無疑是最完美的。但是目前仍然不能實現全部的功能。
對于Shared-storage以及Shared-nothing的技術請參考Oracle以及IBM網站上的相關資料。
第二節 目前數據庫應用狀況
目前數據庫應用狀況大致分為兩類,第一類是數據量在100G以下,數據庫訪問頻繁,請求密集。主要是Web APP類型的應用,例如:網站,論壇等。這些Web APP類型的應用訪問數據庫的特點是:訪問頻繁,數據庫每秒鐘要接受幾千次以上的查詢,需要經常追加數據,同時對數據的響應速度要求比較高。另一類是用于科學計算、存儲歷史數據的應用,數據量往往達到幾百G。這些應用訪問數據庫的特點是:多為查詢操作,數據都是分批、定時、集中倒入數據庫,數據庫的記錄非常多,積累了大量的數據,對數據庫的響應速度沒有太高要求。
第三節 暴露出來的問題
第一類應用,由于訪問比較頻繁,而且為了支持更多的訪問,Web Server一般都使用了負載均衡的集群,但是對于數據庫來說,由于無法實現集群操作,每秒鐘的請求不斷增加,隨著服務器負載的增加,響應單個請求的速度越來越慢,如果庫文件比較大,出現寫操作的時候還會出現鎖表時間過長等影響訪問效率的事情。
第二類應用,主要是數據文件太大,每次處理數據都需要大量的時間,如果寫錯一個語句就需要花幾個小時來重做查詢。
第四節 如何解決
首先應當從硬件、軟件、程序、索引、SQL語句這幾個方面進行優化,如果仍然不能解決問題,我們就要考慮數據庫系統的集群(并行處理)了。
對于第一類的應用,在數據庫服務器正常運行,負載不高的情況下,應用對數據庫系統的狀況還是滿意的。但是數據庫系統負載過高之后,就會出現完成請求的時間加長,達不到系統的要求時間。既然負載是由于過多的請求造成的,我們就采取分擔請求的方式,讓一部分的請求去訪問另外一臺服務器,讓單臺服務器的負載降低,從而解決問題。
對于第二類的應用,就需要分布式計算的系統來解決了,一般的系統是無能為力了。
第五節 針對于"Linux+Apache+PHP+MySQL"的第一類應用問題的解決方式
一個實際案例的解決:
我在工作當中遇到了這樣的問題,我們的Web Server是Linux+Apache+Php的三臺機器組成的集群,MySQL運行在SUN450,2G內存的平臺上。由于WEB的訪問量在高峰的時候幾乎滿負荷運轉,LoadAvg(就是一分鐘之內處于Running狀態的進程數量)都在10-20之間,反映出來就是大量的請求都在訪問數據庫的時候被掛住了,導致一個請求沒有完成,下一個請求又進來,最后惡性循環。LoadAvg會在瞬間飆升至800以上。數據庫那邊就更糟糕了,LoadAvg達到300多,數據庫的線程非常多,CPU忙于切換線程狀態,這個時候除非Restart MySQL,否則怎么都不會好。在對SQL語句優化完成后還是不能很好的解決問題,我們增加了一臺數據庫服務器,通過MySQL的數據同步機制,讓兩臺數據庫上的數據保持同步,修改了一部分只會發生讀取操作的php程序,讓這些程序連接另外一臺數據庫,算是把負載分離出去一部分,問題得到了初步的解決。但是后來業務做大,我們又增加了多臺服務器,修改了很多程序,分離他們對數據庫的讀取操作,訪問不同的服務器。
第六節 MySQL-HA-Proxy方案的提出
通過修改程序的方式實現將系統的負載分離,是件很痛苦的事情,工程浩大,而且不能弄錯,因為除了主服務器可以寫入、修改數據,而其它的服務器只能通過數據同步更新自身的數據,所以如果你對那些數據庫進行了寫操作,結果將是災難性的。
如果我們能夠有一個程序分揀SQL語句,根據他的類型(讀取/寫入),分別傳送給不同的服務器,然后再將結果返回。采用一種類似HTTP的PROXY的方式,這樣我們就不需要通過修改源程序的方式來分擔負載了,如果再能夠根據服務器的負載狀況,或者是表的狀態(可用/鎖定),來判斷應該將這個請求分配到哪臺服務器,那就比我們修改源程序所能達到的效果還要好。
第七節 MySQL Client與Server之間如何通信
四處尋找,也沒有找到一篇關于Mysql通訊協議的文章,看來只有分析Mysql的源程序了。于是找來mysql 3.23.49的代碼,打開sniffer工具。MySQL的通訊協議可能變更過多次,在3.23.49的版本里面,通訊協議的版本竟然是10。
簡單的分析了一下通訊協議,現在規整如下,有些地方還不是很完善,由于我實在沒有太多的時間仔細研讀mysql的代碼,目前我只了解到了這些。
偏移區域類型長度(byte)說明0HEADData Length3 1 2 3 FLAG1=0普通信息
=1多段信息
=2認證返回
>2段結束字4DATACMD Code1 5 MessageDataLength - 1
當FLAG=0 , 2的時候 CMD Code 與 Message 的定義
CMDCode類型Message的結構00狀態碼偏移類型Length(byte) 0Affect rows2 0A服務器版本號偏移類型Length(byte) 只有在剛剛連接上Server的時候有效,Server會馬上返回一個數據節段的信息0VersionString8end of '\0' 8Session ID432bits 12UnKnown11 FF當出現錯誤的時候返回信息偏移類型Length(byte) 0ErrCode2 2ErrMsgEND FE多段信息傳輸的結束空
Client對Server提交數據的格式:
偏移區域類型Length(byte)0HEADData Length31 2 3 Compressed14DATACommand ID15Command DataData Length - 1
Command ID與Command Data的說明:
ID 類型數據格式0COM_SLEEP 1COM_QUITNULL2COM_INIT_DBDatabase name3COM_QUERYstand query string4COM_FIELD_LISTtable name [128] wildcard[128]5COM_CREATE_DBDatabase name6COM_DROP_DBDatabase name7COM_REFRESHoptions(bits)8COM_SHUTDOWNNULL9COM_STATISTICSNULL10COM_PROCESS_INFONULL11COM_CONNECT 12COM_PROCESS_KILLsid[4]13COM_DEBUGNULL14COM_PINGNULL15COM_TIME 16COM_DELAYED_INSERT 17COM_CHANGE_USER[user][passwd][db]18 COM_BINLOG_DUMP 19COM_TABLE_DUMP 20COM_CONNECT_OUT
第八節 Client如何通過Server的用戶認證
協議分析完成了,我嘗試著讓它工作起來,可是認證這個部分遇到了麻煩,Mysql Server在Client連接上它的時候,會首先返回給Client一個數據包,包含協議的版本號,版本信息,SessionID,一個8字節的Key,就是這個Key的原因。Client會使用這個Key來加密密碼,然后將用戶名,密碼,需要打開的數據庫等信息發送給Server,這樣就完成認證了。我不知道Client是如何利用這個Key來加密的,所以我打算跳過密碼,我將Client的數據包重組,去掉Password的信息之后,我成功了,但是集群里面的Mysql用戶都是沒有密碼的,安全性多多少少有些問題,不過這些服務器都是放在HA后面的,沒有外部的IP地址,應該問題不大,不過多多少少是個缺憾。
但是我總要知道用戶的密碼是否正確吧?怎么辦呢?使用一個專用的Mysql來完成密碼認證。安裝一個最小化資源的Mysql Server用來做MysqlAuth(專用認證服務器),當Client連接后,就將MysqlAuth的第一個數據包返回給Client,這里面當然就包含著Key,然后Client會使用這個Key,加密密碼之后,將認證信息發回來,這個時候,MysqlHA系統就會將這個信息轉發給MysqlAuth,并且自己保留一份,如果認證通過了,就把保留的那一份進行重組,去掉密碼信息,然后用重組后的認證信息去連接集群中的服務器。
關鍵字:MySQL、服務器、數據庫
新文章:
- CentOS7下圖形配置網絡的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統后丟失windows啟動項
- CentOS單網卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網打印機IP講解
- CentOS7使用hostapd實現無AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網絡重啟出錯
- 解決Centos7雙系統后丟失windows啟動項
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統有什么不同呢
- Centos 6.6默認iptable規則詳解