Mysql主從複製

今天咱們聊聊複製,複製對於mysql的重要性不言而喻,mysql集羣的負載均衡,讀寫分離和高可用都是基於複製實現。下文主要從4個方面展開,mysql的異步複製,半同步複製和並行複製,最後會簡單聊下第三方複製工具。因爲生產環境中,innodb存儲引擎支持事務,而且行級複製使用普遍,因此下文的討論都是基於這種假設。mysql

異步複製sql

異步複製是mysql自帶的最原始的複製方式,主庫和備庫成功創建起復制關係後,在備庫上會有一個IO線程去主庫拉取binlog,並將binlog寫到本地,就是圖1中的Relay log,而後備庫會開啓另一個SQL線程去讀取回放Relay log,經過這種方式達到Master-Slave數據同步的目的。一般狀況下,Slave是隻讀的,能夠承擔一部分讀流量,並且能夠根據實際須要,添加一個或多個Slave,這樣在必定程度上能夠緩解主庫的讀壓力;另外一方面,若Master出現異常(crash,硬件故障等),沒法對外提供服務,此時Slave能夠承擔起Master的重任,避免了單點的產生,因此複製就是爲容災和提升性能而生。



                            圖1

半同步複製數據庫

通常狀況下,異步複製就已經足夠應付了,但因爲是異步複製,備庫極有多是落後於主庫,特別是極端狀況下,咱們沒法保證主備數據是嚴格一致的(即便咱們觀察到Seconds Behind Master 這個值爲0)。好比,當用戶發起commit命令時,Master並不關心Slave的執行狀態,執行成功後,當即返回給用戶。試想下,若一個事務提交後,Master成功返回給用戶後crash,這個事務的binlog還沒來得及傳遞到Slave,那麼Slave相對於Master而言就少了一個事務,此時主備就不一致了。對於要求強一致的業務是不能夠接受的,半同步複製就是爲了解決數據一致性而產生的。

  爲何叫半同步複製?先說說同步複製,所謂同步複製就是一個事務在Master和Slave都執行後,才返回給用戶執行成功。而半同步複製不要求Slave執行,而僅僅是接收到日誌後,就通知Master能夠返回了。這裏關鍵點是Slave接受日誌後是否執行,若執行後才通知Master則是同步複製,若僅僅是接受日誌成功,則是半同步複製。對於Mysql而言,咱們談到的日誌都是binlog,對於其餘的關係型數據庫多是redo log或其餘日誌。 

  半同步複製如何實現?半同步複製實現的關鍵點是Master對於事務提交過程特殊處理。目前實現半同步複製主要有兩種模式,AFTER_SYNC模式和AFTER_COMMIT模式。兩種方式的主要區別在因而否在存儲引擎提交後等待Slave的ACK。先來看看AFTER_COMMIT模式,如圖2,Start和End分別表示用戶發起Commit命令和Master返回給用戶的時間點,中間部分就是整個Commit過程Master和Slave作的事情。



                                       圖2

  Master提交時,會首先將該事務的redo log刷入磁盤,而後將事務的binlog刷入磁盤(這裏其實還涉及到兩階段提交的問題,這裏不展開講),而後進入innodb commit流程,這個步驟主要是釋放鎖,標記事務爲提交狀態(其餘用戶能夠看到該事務的更新),這個過程完成後,等待Slave發送的ACK消息,等到Slave的響應後,Master才成功返回給用戶。看到圖中紅色虛線部分,這段是Master和Slave的同步邏輯,是Master-Slave一致性的保證。

 半同步複製是否能保證不丟數據?咱們經過幾種場景來簡單分析下。第一種狀況:假設Master第1,2步執行成功後,binlog還沒來得及傳遞給Slave,此時Master掛了,Slave做爲新Master提供服務,那麼備庫比主庫要少一個事務(由於主庫的redo 和binlog已經落盤),可是不影響用戶,對於用戶而言,這個事務沒有成功返回,那麼提交與否,用戶均可以接受,用戶必定會進行異常捕獲而重試。第二種狀況,假設第3步innodb commit執行成功後,binlog還沒來得及傳遞給Slave,此時Master掛了,此時與第一種狀況同樣,備庫比主庫少一個事務,可是其餘用戶在3執行完後,能夠看到該事務的更新,而切換到備庫後,卻發現再次讀這個更新又沒了,這個就發生了「幻讀」,若是其餘事務依賴於這個更新,則會對業務邏輯產生影響。固然這僅僅是極端狀況。

  對於第二種狀況產生的影響,AFTER_SYNC模式能夠解決這一問題。與AFTER_COMMIT相比,master在AFTER_SYNC模式下,Fsync binlog後,就開始等待SLAVE同步。那麼在進行第5步innodbcommit後,即其它事務能看到該事務的更新時,Slave已經成功接收到binlog,即便發生切換,Slave擁有與Master一樣的數據,不會發生「幻讀」現象。可是對於上面描述的第一種狀況,結果是同樣的。

   因此,在極端狀況下,半同步複製的Master-Slave會有一個事務不一致,可是對於用戶而言,因爲這個事務並無成功返回給用戶,因此不管事務提交與否都是能夠接受的,用戶有必要進行查詢或重試,判讀是否更新成功。或者咱們想一想,對於單機而言,若事務執行成功後,返回給用戶時,網絡斷了,用戶也是面臨同樣的問題,因此,這不是半同步複製的問題。對於提交返回成功的事務,版同步複製保證Master-Slave必定是一致的,從這個角度來看,半同步複製不會丟數據,能夠保證Master-Slave的強一致性。圖3是AFTER_SYNC模式,事務提交過程。



                                        圖3

並行複製網絡

半同步複製解決了Master-Slave的強一致問題,那麼性能問題呢?從圖1中能夠看到參與複製的主要有兩個線程:IO線程和SQL線程,分別用於拉取和回放binlog。對於Slave而言,全部拉取和解析binlog的動做都是串行的,相對於Master併發處理用戶請求,在高負載下, 若Master產生binlog的速度超過Slave消費binlog的速度,致使Slave出現延遲。如圖4,能夠看到,Users和Master之間的管道遠遠大於Master和Slave之間的管道。



                                 圖4

 那麼如何並行化,並行IO線程,仍是並行SQL線程?其實兩方面均可以並行,可是並行SQL線程的收益更大,由於SQL線程作的事情更多(解析,執行)。並行IO線程,能夠將從Master拉取和寫Relay log分爲兩個線程;並行SQL線程則能夠根據須要作到庫級並行,表級並行,事務級並行。庫級並行在mysql官方版本5.6已經實現。如圖5,並行複製框架實際包含了一個協調線程和若干個工做線程,協調線程負責分發和解決衝突,工做線程只負責執行。圖中,DB1,DB2和DB3的事務就能夠併發執行,提升了複製的性能。有時候庫級併發可能不夠,須要作表級併發,或更細粒度的事務級併發。



                                                      圖 5

  並行複製如何處理衝突?併發的世界是美好的,但不能亂併發,不然數據就亂了。Master上面經過鎖機制來保證併發的事務有序進行,那麼並行複製呢?Slave必需保證回放的順序與Master上事務執行順序一致,所以只要作到順序讀取binlog,將不衝突的事務併發執行便可。對於庫級併發而言,協調線程要保證執行同一個庫的事務放在一個工做線程串行執行;對於表級併發而言,協調線程要保證同一個表的事務串行執行;對於事務級而言,則是保證操做同一行的事務串行執行。

  是否粒度越細,性能越好?這個並非必定的。相對於串行復制而言,並行複製多了一個協調線程。協調線程一個重要做用是解決衝突,粒度越細的併發,可能會有更多的衝突,最終可能也是串行執行的,但消耗了大量的衝突檢測代價。

第三方複製工具併發

爲何會出現第三方複製工具?第三方複製工具的出現必定是內嵌的複製功能不能知足用戶需求,就像半同步複製和並行複製從無到有同樣。既然如今mysql複製已經作地這麼好了,爲何還有第三方複製工具,我能想到最重要的一點是異構複製。在異構數據源遷移場景下,內嵌複製是無能爲力的,第三方複製工具經過解析源端的數據庫日誌,而後在目的端回放,就能達到同步的目的,好比大名鼎鼎的GoldenGate就是一個例子。第三方複製工具一樣能很好地實現併發,在並行複製出現以前,這也是一個巨大的優點。另外一方面,就是能夠統一下游,避免全部下游都跑到DB上拉binlog,增大DB負載。
相關文章
相關標籤/搜索