天天看點

MySQL 主從複制與讀寫分離概念及架構分析

1.MySQL主從複制入門

首先,我們看一個圖:

<a href="http://s3.51cto.com/wyfs02/M01/4C/42/wKiom1Q6MmzyVOk1AAC1h1tFlco436.jpg" target="_blank"></a>

影響MySQL-A資料庫的操作,在資料庫執行後,都會寫入本地的日志系統A中。

假設,實時的将變化了的日志系統中的資料庫事件操作,在MYSQL-A的3306端口,通過網絡發給MYSQL-B。

MYSQL-B收到後,寫入本地日志系統B,然後一條條的将資料庫事件在資料庫中完成。

那麼,MYSQL-A的變化,MYSQL-B也會變化,這樣就是所謂的MYSQL的複制,即MYSQL replication。

在上面的模型中,MYSQL-A就是主伺服器,即master,MYSQL-B就是從伺服器,即slave。

日志系統A,其實它是MYSQL的日志類型中的二進制日志,也就是專門用來儲存修改資料庫表的所有動作,即bin log。【注意MYSQL會在執行語句之後,釋放鎖之前,寫入二進制日志,確定事務安全】

日志系統B,并不是二進制日志,由于它是從MYSQL-A的二進制日志複制過來的,并不是自己的資料庫變化産生的,有點接力的感覺,稱為中繼日志,即relay log。

可以發現,通過上面的機制,可以保證MYSQL-A和MYSQL-B的資料庫資料一緻,但是時間上肯定有延遲,即MYSQL-B的資料是滞後的。

【即便不考慮什麼網絡的因素,MYSQL-A的資料庫操作是可以并發的執行的,但是MYSQL-B隻能從relay log中讀一條,執行下。是以MYSQL-A的寫操作很頻繁,MYSQL-B很可能跟不上。】

2.主從複制的幾種方式

同步複制

所謂的同步複制,意思是master的變化,必須等待slave-1,slave-2,...,slave-n完成後才能傳回。

這樣,顯然不可取,也不是MYSQL複制的預設設定。比如,在WEB前端頁面上,使用者增加了條記錄,需要等待很長時間。

異步複制

如同AJAX請求一樣。master隻需要完成自己的資料庫操作即可。至于slaves是否收到二進制日志,是否完成操作,不用關心。MYSQL的預設設定。

半同步複制

master隻保證slaves中的一個操作成功,就傳回,其他slave不管。

這個功能,是由google為MYSQL引入的。

3.主從複制分析

問題1:master的寫操作,slaves被動的進行一樣的操作,保持資料一緻性,那麼slave是否可以主動的進行寫操作?

假設slave可以主動的進行寫操作,slave又無法通知master,這樣就導緻了master和slave資料不一緻了。是以slave不應該進行寫操作,至少是slave上涉及到複制的資料庫不可以寫。實際上,這裡已經揭示了讀寫分離的概念。

問題2:主從複制中,可以有N個slave,可是這些slave又不能進行寫操作,要他們幹嘛?

可以實作資料備份。

類似于高可用的功能,一旦master挂了,可以讓slave頂上去,同時slave提升為master。

異地容災,比如master在北京,地震挂了,那麼在上海的slave還可以繼續。

主要用于實作scale out,分擔負載,可以将讀的任務分散到slaves上。

【很可能的情況是,一個系統的讀操作遠遠多于寫操作,是以寫操作發向master,讀操作發向slaves進行操作】

問題3:主從複制中有master,slave1,slave2,...等等這麼多MYSQL資料庫,那比如一個JAVA WEB應用到底應該連接配接哪個資料庫?

當然,我們在應用程式中可以這樣,insert/delete/update這些更新資料庫的操作,用connection(for master)進行操作,select用connection(for slaves)進行操作。那我們的應用程式還要完成怎麼從slaves選擇一個來執行select,例如簡單的輪循算法。

這樣的話,相當于應用程式完成了SQL語句的路由,而且與MYSQL的主從複制架構非常關聯,一旦master挂了,某些slave挂了,那麼應用程式就要修改了。能不能讓應用程式與MYSQL的主從複制架構沒有什麼太多關系呢?可以看下面的圖:

<a href="http://s3.51cto.com/wyfs02/M02/4C/46/wKioL1Q6Z3aj0qD3AAFTRVV5DP0026.jpg" target="_blank"></a>

找一個元件,application program隻需要與它打交道,用它來完成MYSQL的代理,實作SQL語句的路由。

mysql proxy并不負責,怎麼從衆多的slaves挑一個?可以交給另一個元件(比如haproxy)來完成。

這就是所謂的MYSQL READ WRITE SPLITE,MYSQL的讀寫分離。

問題4:如果mysql proxy , direct , master他們中的某些挂了怎麼辦?

總統一般都會弄個副總統,以防不測。同樣的,可以給這些關鍵的節點來個備份。

問題5:當master的二進制日志每産生一個事件,都需要發往slave,如果我們有N個slave,那是發N次,還是隻發一次?

如果隻發一次,發給了slave-1,那slave-2,slave-3,...它們怎麼辦?

顯然,應該發N次。實際上,在MYSQL master内部,維護N個線程,每一個線程負責将二進制日志檔案發往對應的slave。master既要負責寫操作,還的維護N個線程,負擔會很重。可以這樣,slave-1是master的從,slave-1又是slave-2,slave-3,...的主,同時slave-1不再負責select。slave-1将master的複制線程的負擔,轉移到自己的身上。這就是所謂的多級複制的概念。

問題6:當一個select發往mysql proxy,可能這次由slave-2響應,下次由slave-3響應,這樣的話,就無法利用查詢緩存了。

應該找一個共享式的緩存,比如memcache來解決。将slave-2,slave-3,...這些查詢的結果都緩存至mamcache中。

問題7:随着應用的日益增長,讀操作很多,我們可以擴充slave,但是如果master滿足不了寫操作了,怎麼辦呢?

scale on ?更好的伺服器? 沒有最好的,隻有更好的,太貴了。。。

scale out ? 主從複制架構已經滿足不了。

可以分庫【垂直拆分】,分表【水準拆分】。

本文轉自zfz_linux_boy 51CTO部落格,原文連結:http://blog.51cto.com/zhangfengzhe/1563032,如需轉載請自行聯系原作者