Mycat中介軟體---MySQL讀寫分離
MySQL主從複製的幾種方案
資料庫讀寫分離對於大型系統或者訪問量很高的網際網路應用來說,是必不可少的一個重要功能。 從資料庫的角度來說,對於大多數應用來說,從集中到分佈,最基本的一個需求不是資料儲存的瓶頸,而是在於計算的瓶頸,即SQL查詢的瓶頸,我們知道,正常情況下,Insert SQL就是幾十個毫秒的時間內寫入完成,而系統中的大多數Select SQL則要幾秒到幾分鐘才能有結果,很多複雜的SQL,其消耗伺服器CPU的能力超強,不亞於死迴圈的威力。在沒有讀寫分離的系統上,很可能高峰時段的一些複雜SQL查詢就導致資料庫伺服器CPU爆表,系統陷入癱瘓,嚴重情況下可能導致資料庫崩潰。因此,從保護資料庫的角度來說,我們應該儘量避免沒有主從複製機制的單節點資料庫。 對於MySQL來說,標準的讀寫分離是主從模式,一個寫節點Master後面跟著多個讀節點,讀節點的數量取決於系統的壓力,通常是1-3個讀節點的配置,如下圖所示:
MySQL主從複製的幾個問題
MySQL主從複製並不完美,存在著幾個由來已久的問題,首先一個問題是複製方式:
- 基於SQL語句的複製(statement-based replication, SBR),
- 基於行的複製(row-based replication, RBR),
- 混合模式複製(mixed-based replication, MBR)。
- 基於SQL語句的方式最古老的方式,也是目前預設的複製方式,後來的兩種是MySQL 5以後才出現的複製方式。 RBR 的優點:
- 任何情況都可以被複制,這對複製來說是最安全可靠的
- 和其他大多數資料庫系統的複製技術一樣
- 多數情況下,從伺服器上的表如果有主鍵的話,複製就會快了很多
RBR的缺點:
- binlog 大了很多
- 複雜的回滾時 binlog 中會包含大量的資料
- 主伺服器上執行 UPDATE 語句時,所有發生變化的記錄都會寫到 binlog 中,而 SBR 只會寫一次,這會導致頻繁發生 binlog 的併發寫問題
- 無法從 binlog 中看到都複製了寫什麼語句
SBR 的優點:
-
歷史悠久,技術成熟
-
binlog檔案較小
-
binlog中包含了所有資料庫更改資訊,可以據此來稽核資料庫的安全等情況
-
binlog可以用於實時的還原,而不僅僅用於複製
-
主從版本可以不一樣,從伺服器版本可以比主伺服器版本高
SBR 的缺點:
-
不是所有的UPDATE語句都能被複制,尤其是包含不確定操作的時候。
-
複製需要進行全表掃描(WHERE 語句中沒有使用到索引)的 UPDATE 時,需要比 RBR 請求更多的行級鎖
-
對於一些複雜的語句,在從伺服器上的耗資源情況會更嚴重,而 RBR 模式下,只會對那個發生變化的記錄產生影響
-
資料表必須幾乎和主伺服器保持一致才行,否則可能會導致複製出錯
-
執行復雜語句如果出錯的話,會消耗更多資源
選擇哪種方式複製,會影響到複製的效率以及伺服器的損耗,甚以及資料一致性性問題,目前其實沒有很好的客觀手手段去評估一個系統更適合哪種方式的複製,Mycat未來希望能通過智慧調優模組給出更科學的建議。 第二個問題是關於主從同步的監控問題,Mysql有主從同步的狀態資訊,可以通過命令show slave status獲取,除了獲知當前是否主從同步正常工作,另外一個重要指標就是Seconds_Behind_Master,從字面理解,它表示當前MySQL主從資料的同步延遲,單位是秒,但這個指標從DBA的角度並不能簡單的理解為延遲多少秒,感興趣的同學可以自己去研究,但對於應用來說,簡單的認為是主從同步的時間差就可以了,另外,當主從同步停止以後,重新啟動同步,這個數值可能會是幾萬秒,取決於主從同步停止的時間長短,我們可以認為資料此時有很多天沒有同步了,而這個數值越接近零,則說明主從同步延遲最小,我們可以採集這個指標並匯聚曲線圖,來分析我們的資料庫的同步延遲曲線,然後根據此曲線,給出一個合理的閥值,主從同步的時延小於閥值時,我們認為從庫是同步的,此時可以安全的從從庫讀取資料。Mycat未來將支援這種優化,讓應用更加可靠的讀取到預期的從庫資料。
Mycat支援的讀寫分離
1.配置mysql端主從的資料自動同步,mycat不負責任何的資料同步問題。 2.Mycat配置讀寫分離,具體引數參加前面章節。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root" password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS1" url="localhost2:3306" user="root" password="123456" weight="1" />
</writeHost> </dataHost>
或者
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> </writeHost>
<writeHost host="hostS1" url="localhost:3307" user="root" password="123456">
</writeHost> </dataHost>
以上兩種取模第一種當寫掛了讀不可用,第二種可以繼續使用,事務內部的一切操作都會走寫節點,所以讀操作不要加事務,如果讀延時較大,使用根據主從延時的讀寫分離,或者強制走寫節點: 應用強制走寫: 一個查詢SQL語句以/balance/註解來確定其是走讀節點還是寫節點。 1.6以後添加了強制走讀走寫處理: 強制走從:
/*!mycat:db_type=slave*/ select * from travelrecord
/*#mycat:db_type=slave*/ select * from travelrecord
強制走寫:
/*#mycat:db_type=master*/ select * from travelrecord /*!mycat:db_type=master*/ select * from travelrecord
根據主從延時切換: 1.4開始支援MySQL主從複製狀態繫結的讀寫分離機制,讓讀更加安全可靠,配置如下: MyCAT心跳檢查語句配置為 show slave status ,dataHost 上定義兩個新屬性: switchType=”2” 與 slaveThreshold=”100”,此時意味著開啟MySQL主從複製狀態繫結的讀寫分離與切換機制,Mycat心跳機制通過檢測 show slave status 中的 “Seconds_Behind_Master”, “Slave_IO_Running”, “Slave_SQL_Running” 三個欄位來確定當前主從同步的狀態以及Seconds_Behind_Master主從複製時延, 當Seconds_Behind_Master>slaveThreshold時,讀寫分離篩選器會過濾掉此Slave機器,防止讀到很久之前的舊資料,而當主節點宕機後,切換邏輯會檢查Slave上的Seconds_Behind_Master是否為0,為0時則表示主從同步,可以安全切換,否則不會切換。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<heartbeat>show slave status </heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> </writeHost>
<writeHost host="hostS1" url="localhost:3316" user="root" password="123456" />
</dataHost>
1.4.1 開始支援MySQL 叢集模式,讓讀更加安全可靠,配置如下: MyCAT心跳檢查語句配置為 show status like ‘wsrep%’ , dataHost 上定義兩個新屬性: switchType=”3” 此時意味著開啟MySQL叢集複製狀態狀態繫結的讀寫分離與切換機制,Mycat心跳機制通過檢測叢集複製時延時,如果延時過大或者叢集出現節點問題不會負載改節點。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="3" >
<heartbeat> show status like ‘wsrep%’</heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root"password="123456"> </writeHost>
<writeHosthost="hostS1"url="localhost:3316"user="root"password="123456" ></writeHost> </dataHost>