第13章 可擴展性設計之 MySQL Replication 前言: MySQL Replication 是 MySQL 非常有特色的一個功能,他能夠將一個 MySQL Server 的 Instance 中的數據完整的複製到另外一個 MySQL Server 的 Instance 中。雖然複製過程 ...
第13章 可擴展性設計之 MySQL Replication
前言:
MySQL Replication 是 MySQL 非常有特色的一個功能,他能夠將一個 MySQL Server 的 Instance 中的數據完整的複製到另外一個 MySQL Server 的 Instance 中。雖然複製過程並不是實時而是非同步進行的,但是由於其高效的性能設計,延時非常之少。MySQL 的Replication 功能在實際應用場景中被非常廣泛的用於保證系統數據的安全性和系統可擴展設計中。本章將專門針對如何利用 MySQL 的 Replication 功能來提高系統的擴展性進行詳細的介紹。
13.1 Replication 對可擴展性設計的意義
在互聯網應用系統中,擴展最為方便的可能要數最基本的 Web 應用服務了。因為 Web應用服務大部分情況下都是無狀態的,也很少需要保存太多的數據,當然 Session 這類信息比較例外。所以,對於基本的 Web 應用伺服器很容易通過簡單的添加伺服器並複製應用程式來做到 Scale Out。
而資料庫由於其特殊的性質,就不是那麼容易做到方便的 Scale Out。當然,各個資料庫廠商也一直在努力希望能夠做到自己的資料庫軟體能夠像常規的應用伺服器一樣做到方便的 Scale Out,也確實做出了一些功能,能夠基本實現像 Web 應用伺服器一樣的Scalability,如很多資料庫所支持的邏輯複製功能。
MySQL 資料庫也為此做出了非常大的努力,MySQL Replication 功能主要就是基於這一目的所產生的。通過 MySQL 的 Replication 功能,我們可以非常方便的將一個資料庫中的數據複製到很多台 MySQL 主機上面,組成一個 MySQL 集群,然後通過這個 MySQL 集群來對外提供服務。這樣,每台 MySQL 主機所需要承擔的負載就會大大降低,整個 MySQL 集群的處理能力也很容易得到提升。
為什麼通過 MySQL 的 Replication 可以做到 Scale Out 呢?主要是因為通過 MySQL的 Replication,可以將一臺 MySQL 中的數據完整的同時複製到多台主機上面的 MySQL 資料庫中,並且正常情況下這種複製的延時並不是很長。當我們各台伺服器上面都有同樣的數據之後,應用訪問就不再只能到一臺資料庫主機上面讀取數據了,而是訪問整個 MySQL 集群中的任何一臺主機上面的資料庫都可以得到相同的數據。此外還有一個非常重要的因素就是 MySQL 的複製非常容易實施,也非常容易維護。這一點對於實施一個簡單的分散式資料庫集群是非常重要的,畢竟一個系統實施之後的工作主要就是維護了,一個維護複雜的系統肯定不是一個受歡迎的系統。
13.2 Replication 機制的實現原理
要想用好一個系統,理解其實現原理是非常重要的事情,只有理解了其實現原理,我們才能夠揚長避短,合理的利用,才能夠搭建出最適合我們自己應用環境的系統,才能夠在系統實施之後更好的維護他。
下麵我們分析一下 MySQL Replication的實現原理。
13.2.1 Replication 線程
Mysql的 Replication 是一個非同步的複製過程,從一個 Mysql instace(我們稱之為Master)複製到另一個 Mysql instance(我們稱之 Slave)。在 Master 與 Slave 之間的實現整個複製過程主要由三個線程來完成,其中兩個線程(Sql線程和IO線程)在 Slave 端, 另外一個線程(IO線程)在 Master 端。
要實現 MySQL 的 Replication ,首先必須打開 Master 端的Binary Log(mysql-bin.xxxxxx)功能,否則無法實現。因為整個複製過程實際上就是Slave從Master端獲取該日誌然後再在自己身上完全順序的執行日誌中所記錄的各種操作。打開 MySQL 的 Binary Log 可以通過在啟動 MySQL Server 的過程中使用“—log-bin” 參數選項,或者在 my.cnf 配置文件中的 mysqld 參數組([mysqld]標識後的參數部分)增加 “log-bin” 參數項。
MySQL 複製的基本過程如下:
1. Slave 上面的IO線程連接上 Master,並請求從指定日誌文件的指定位置(或者從最開始的日誌)之後的日誌內容;
2. Master 接收到來自 Slave 的 IO 線程的請求後,通過負責複製的 IO 線程根據請求信息讀取指定日誌指定位置之後的日誌信息,返回給 Slave 端的 IO 線程。返回信息中除了日誌所包含的信息之外,還包括本次返回的信息在 Master 端的 Binary Log 文件的名稱以及在 Binary Log 中的位置;
3. Slave 的 IO 線程接收到信息後,將接收到的日誌內容依次寫入到 Slave 端的 Relay Log文件(mysql-relay-bin.xxxxxx)的最末端,並將讀取到的Master端的bin-log的文件名和位置記錄到master-info文件中,以便在下一次讀取的時候能夠清楚的高速Master“我需要從某個bin-log的哪個位置開始往後的日誌內容,請發給我”
4. Slave 的 SQL 線程檢測到 Relay Log 中新增加了內容後,會馬上解析該 Log 文件中的內容成為在 Master 端真實執行時候的那些可執行的 Query 語句,併在自身執行這些 Query。這樣,實際上就是在 Master 端和 Slave 端執行了同樣的 Query,所以兩端的數據是完全一樣的。
實際上,在老版本中,MySQL 的複製實現在 Slave 端並不是由 SQL 線程和 IO 線程這兩個線程共同協作而完成的,而是由單獨的一個線程來完成所有的工作。但是 MySQL 的工程師們很快發現,這樣做存在很大的風險和性能問題,主要如下:
首先,如果通過一個單一的線程來獨立實現這個工作的話,就使複製 Master 端的, Binary Log日誌,以及解析這些日誌,然後再在自身執行的這個過程成為一個串列的過程, 性能自然會受到較大的限制,這種架構下的 Replication 的延遲自然就比較長了。
其次,Slave 端的這個複製線程從 Master 端獲取 Binary Log 過來之後,需要接著解析這些內容,還原成 Master 端所執行的原始 Query,然後在自身執行。在這個過程中, Master端很可能又已經產生了大量的變化並生成了大量的 Binary Log 信息。如果在這個階段 Master 端的存儲系統出現了無法修複的故障,那麼在這個階段所產生的所有變更都將永遠的丟失,無法再找回來。這種潛在風險在Slave 端壓力比較大的時候尤其突出,因為如果 Slave 壓力比較大,解析日誌以及應用這些日誌所花費的時間自然就會更長一些,可能丟失的數據也就會更多。
所以,在後期的改造中,新版本的 MySQL 為了儘量減小這個風險,並提高複製的性能, 將 Slave 端的複製改為兩個線程來完成,也就是前面所提到的 SQL 線程和 IO 線程。最早提出這個改進方案的是Yahoo!的一位工程師“Jeremy Zawodny”。通過這樣的改造,這樣既在很大程度上解決了性能問題,縮短了非同步的延時時間,同時也減少了潛在的數據丟失量。
當然,即使是換成了現在這樣兩個線程來協作處理之後,同樣也還是存在 Slave 數據延時以及數據丟失的可能性的,畢竟這個複製是非同步的。只要數據的更改不是在一個事務中, 這些問題都是存在的。
如果要完全避免這些問題,就只能用 MySQL 的 Cluster 來解決了。不過 MySQL的Cluster 知道筆者寫這部分內容的時候,仍然還是一個記憶體資料庫的解決方案,也就是需要將所有數據包括索引全部都 Load 到記憶體中,這樣就對記憶體的要求就非常大的大,對於一般的大眾化應用來說可實施性並不是太大。當然,在之前與 MySQL 的 CTO David 交流的時候得知,MySQL 現在正在不斷改進其 Cluster 的實現,其中非常大的一個改動就是允許數據不用全部 Load 到記憶體中,而僅僅只是索引全部 Load 到記憶體中,我想信在完成該項改造之後的 MySQL Cluster 將會更加受人歡迎,可實施性也會更大。
13.2.2 複製實現級別
MySQL 的複製可以是基於一條語句(Statement Level),也可以是基於一條記錄(Row level),可以在 MySQL 的配置參數中設定這個複製級別,不同複製級別的設置會影響到Master 端的 Binary Log 記錄成不同的形式。
1. Row Level:Binary Log 中會記錄成每一行數據被修改的形式,然後在 Slave 端再對相同的數據進行修改。
優點:在 Row Level 模式下,Binary Log 中可以不記錄執行的sql語句的上下文相關的信息,僅僅只需要記錄那一條記錄被修改了,修改成什麼樣了。所以 Row Level 的日誌內容會非常清楚的記錄下每一行數據修改的細節,非常容易理解。而且不會出現某些特定情況下的存儲過程,或function,以及trigger的調用和觸發無法被正確複製的問題。
缺點:Row Level下,所有的執行的語句當記錄到 Binary Log 中的時候,都將以每行記錄的修改來記錄,這樣可能會產生大量的日誌內容,比如有這樣一條update語句:UPDATE group_message SET group_id = 1 where group_id = 2,執行之後,日誌中記錄的不是這條update語句所對應的事件(MySQL以事件的形式來記錄 Binary Log 日誌),而是這條語句所更新的每一條記錄的變化情況,這樣就記錄成很多條記錄被更新的很多個事件。自然,
Binary Log 日誌的量就會很大。尤其是當執行ALTER TABLE 之類的語句的時候,產生的日誌量是驚人的。因為MySQL對於 ALTER TABLE 之類的 DDL 變更語句的處理方式是重建整個表的所有數據,也就是說表中的每一條記錄都需要變動,那麼該表的每一條記錄都會被記錄到日誌中。
2. Statement Level:每一條會修改數據的 Query 都會記錄到 Master的 Binary Log 中。Slave在複製的時候 SQL 線程會解析成和原來 Master 端執行過的相同的 Query 來再次執行。
優點:Statement Level下的優點首先就是解決了Row Level下的缺點,不需要記錄每一行數據的變化,減少 Binary Log 日誌量,節約了 IO 成本,提高了性能。因為他只需要記錄在Master上所執行的語句的細節,以及執行語句時候的上下文的信息。
缺點:由於他是記錄的執行語句,所以,為了讓這些語句在slave端也能正確執行,那麼他還必須記錄每條語句在執行的時候的一些相關信息,也就是上下文信息,以保證所有語句在slave端杯執行的時候能夠得到和在master端執行時候相同的結果。另外就是,由於Mysql現在發展比較快,很多的新功能不斷的加入,使mysql得複製遇到了不小的挑戰,自然複製的時候涉及到越複雜的內容,bug也就越容易出現。在statement level下,目前已經發現的就有不少情況會造成mysql的複製出現問題,主要是修改數據的時候使用了某些特定的函數或者功能的時候會出現,比如:sleep()函數在有些版本中就不能真確複製,在存儲過程中使用了last_insert_id()函數,可能會使slave和master上得到不一致的id等等。由於row level是基於每一行來記錄的變化,所以不會出現類似的問題。
從官方文檔中看到,之前的 MySQL 一直都只有基於 Statement 的複製模式,直到5.1.5版本的 MySQL 才開始支持Row Level的複製。從5.0開始,MySQL 的複製已經解決了大量老版本中出現的無法正確複製的問題。但是由於存儲過程的出現,給 MySQL 的複製又帶來了更大的新挑戰。另外,看到官方文檔說,從5.1.8版本開始,MySQL 提供了除Statement Level和Row Level之外的第三種複製模式:Mixed Level,實際上就是前兩種模式的結合。在Mixed模式下,MySQL會根據執行的每一條具體的 Query 語句來區分對待記錄的日誌形式,也就是在Statement和Row之間選擇一種。新版本中的Statment level 還是和以前一樣,僅僅記錄執行的語句。而新版本的Mysql中隊Row Level模式也被做了優化,並不是所有的修改都會以Row Level來記錄,像遇到表結構變更的時候就會以statement 模式來記錄,如果 Query 語句確實就是 UPDATE 或者 DELETE 等修改數據的語句,那麼還是會記錄所有行的變更。
13.3 Replication常用架構
MySQL Replicaion 本身是一個比較簡單的架構,就是一臺 MySQL 伺服器(Slave)從另一臺 MySQL 伺服器(Master)進行日誌的複製然後再解析日誌並應用到自身。一個複製環境僅僅只需要兩台運行有 MySQL Server 的主機即可,甚至更為簡單的時候我們可以在同一臺物理伺服器主機上面啟動兩個 mysqld instance,一個作為 Master 而另一個作為Slave 來完成複製環境的搭建。但是在實際應用環境中,我們可以根據實際的業務需求利用MySQL Replication 的功能自己定製搭建出其他多種更利於 Scale Out 的複製架構。如Dual Master 架構,級聯複製架構等。下麵我們針對比較典型的三種複製架構進行一些相應的分析介紹。
13.3.1 常規複製架構(Master - Slaves)
在實際應用場景中,MySQL 複製90% 以上都是一個Master 複製到一個或者多個Slave的架構模式,主要用於讀壓力比較大的應用的資料庫端廉價擴展解決方案。因為只要Master 和 Slave 的壓力不是太大(尤其是 Slave 端壓力)的話,非同步複製的延時一般都很少很少。尤其是自從Slave端的複製方式改成兩個線程處理之後,更是減小了 Slave 端的延時問題。而帶來的效益是,對於數據實時性要求不是特別 Critical 的應用,只需要通過廉價的pc server來擴展 Slave 的數量,將讀壓力分散到多台 Slave 的機器上面,即可通過分散單台資料庫伺服器的讀壓力來解決資料庫端的讀性能瓶頸,畢竟在大多數資料庫應用系統中的讀壓力還是要比寫壓力大很多。這在很大程度上解決了目前很多中小型網站的資料庫壓力瓶頸問題,甚至有些大型網站也在使用類似方案解決資料庫瓶頸。
這個架構可以通過下圖比較清晰的展示:
一個Master複製多個 Slave 的架構實施非常簡單,多個 Slave 和單個 Slave的實施並沒有實質性的區別。在 Master 端並不 Care 有多少個 Slave 連上了自己,只要有 Slave 的 IO 線程通過了連接認證,向他請求指定位置之後的 Binary Log 信息,他就會按照該IO線程的要求,讀取自己的 Binary Log 信息,返回給 Slave 的 IO 線程。
大家應該都比較清楚,從一個 Master 節點可以複製出多個 Slave 節點,可能有人會想,那一個 Slave 節點是否可以從多個 Master 節點上面進行複製呢?至少在目前來看, MySQL 是做不到的,以後是否會支持就不清楚了。
MySQL 不支持一個 Slave 節點從多個 Master 節點來進行複製的架構,主要是為了避免衝突的問題,防止多個數據源之間的數據出現衝突,而造成最後數據的不一致性。不過聽說已經有人開發了相關的 patch,讓 MySQL 支持一個 Slave 節點從多個 Master 結點作為數據源來進行複製,這也正是 MySQL 開源的性質所帶來的好處。
對於 Replication 的配置細節,在 MySQL 的官方文檔上面已經說的非常清楚了,甚至介紹了多種實現 Slave 的配置方式,在下一節中我們也會通過一個具體的示例來演示搭建一個 Replication 環境的詳細過程以及註意事項。
13.3.2 Dual Master 複製架構(Master - Master)
有些時候,簡單的從一個 MySQL 複製到另外一個 MySQL 的基本 Replication 架構, 可能還會需要在一些特定的場景下進行 Master 的切換。如在 Master 端需要進行一些特別的維護操作的時候,可能需要停 MySQL 的服務。這時候,為了儘可能減少應用系統寫服務的停機時間,最佳的做法就是將我們的 Slave 節點切換成 Master 來提供寫入的服務。
但是這樣一來,我們原來 Master 節點的數據就會和實際的數據不一致了。當原 Master 啟動可以正常提供服務的時候,由於數據的不一致,我們就不得不通過反轉原 Master - Slave 關係,重新搭建 Replication 環境,並以原 Master 作為 Slave 來對外提供讀的服務。重新搭建 Replication 環境會給我們帶來很多額外的工作量,如果沒有合適的備份,可能還會讓 Replication 的搭建過程非常麻煩。
為瞭解決這個問題,我們可以通過搭建 Dual Master 環境來避免很多的問題。何謂Dual Master 環境?實際上就是兩個 MySQL Server 互相將對方作為自己的 Master,自己作為對方的 Slave 來進行複製。這樣,任何一方所做的變更,都會通過複製應用到另外一方的資料庫中。
可能有些讀者朋友會有一個擔心,這樣搭建複製環境之後,難道不會造成兩台 MySQL 之 間的迴圈複製麽?實際上 MySQL 自己早就想到了這一點,所以在 MySQL 的 Binary Log 中 記錄了當前 MySQL 的 server-id,而且這個參數也是我們搭建 MySQL Replication 的時候必須明確指定,而且 Master 和 Slave 的 server-id 參數值比需要不一致才能使 MySQL Replication 搭建成功。一旦有了 server-id 的值之後,MySQL 就很容易判斷某個變更是從哪一個 MySQL Server 最初產生的,所以就很容易避免出現迴圈複製的情況。而且,如果我們不打開記錄 Slave 的 Binary Log 的選項(--log-slave-update)的時候,MySQL 根本就不會記錄複製過程中的變更到 Binary Log 中,就更不用擔心可能會出現迴圈複製的情形了。
下如將更清晰的展示 Dual Master 複製架構組成:
通過 Dual Master 複製架構,我們不僅能夠避免因為正常的常規維護操作需要的停機所帶來的重新搭建 Replication 環境的操作,因為我們任何一端都記錄了自己當前複製到對方的什麼位置了,當系統起來之後,就會自動開始從之前的位置重新開始複製,而不需要人為去進行任何干預,大大節省了維護成本。
不僅僅如此,Dual Master 複製架構和一些第三方的 HA 管理軟體結合,還可以在我們當前正在使用的 Master 出現異常無法提供服務之後,非常迅速的自動切換另外一端來提供相應的服務,減少異常情況下帶來的停機時間,並且完全不需要人工干預。
當然,我們搭建成一個 Dual Master 環境,並不是為了讓兩端都提供寫的服務。在正常情況下,我們都只會將其中一端開啟寫服務,另外一端僅僅只是提供讀服務,或者完全不提供任何服務,僅僅只是作為一個備用的機器存在。為什麼我們一般都只開啟其中的一端來提供寫服務呢?主要還是為了避免數據的衝突,防止造成數據的不一致性。因為即使在兩邊執行的修改有先後順序,但由於 Replication 是非同步的實現機制,同樣會導致即使晚做的修改也可能會被早做的修改所覆蓋,就像如下情形:
時間點 | MySQL A | MySQL B |
1 | 更新x表y記錄為10 | |
2 | 更新x表y記錄為20 | |
3 | 獲取到A日誌並應用,更新x表的y記錄為10(不符合期望) | |
4 | 獲取B日誌更新x表y記錄為20(符合期望) |
這中情形下,不僅在B庫上面的數據不是用戶所期望的結果,A和B兩邊的數據也出現了不一致。
當然,我們也可以通過特殊的約定,讓某些表的寫操作全部在一端,而另外一些表的寫操作全部在另外一端,保證兩端不會操作相同的表,這樣就能避免上面問題的發生了。
13.3.3 級聯複製架構(Master - Slaves - Slaves ...)
在有些應用場景中,可能讀寫壓力差別比較大,讀壓力特別的大,一個 Master 可能需要上10台甚至更多的 Slave 才能夠支撐註讀的壓力。這時候,Master 就會比較吃力了, 因為僅僅連上來的 Slave IO 線程就比較多了,這樣寫的壓力稍微大一點的時候,Master 端因為複製就會消耗較多的資源,很容易造成複製的延時。
遇到這種情況如何解決呢?這時候我們就可以利用 MySQL 可以在 Slave 端記錄複製所產生變更的 Binary Log 信息的功能,也就是打開 —log-slave-update 選項。然後,通過二級(或者是更多級別)複製來減少 Master 端因為複製所帶來的壓力。也就是說,我們首先通過少數幾台 MySQL 從 Master 來進行複製,這幾台機器我們姑且稱之為第一級Slave 集群,然後其他的 Slave 再從第一級 Slave 集群來進行複製。從第一級 Slave 進行複製的 Slave,我稱之為第二級 Slave 集群。如果有需要,我們可以繼續往下增加更多層次的複製。這樣,我們很容易就控制了每一臺 MySQL 上面所附屬 Slave 的數量。這種架構我稱之為 Master - Slaves - Slaves 架構這種多層級聯複製的架構,很容易就解決了 Master 端因為附屬 Slave 太多而成為瓶頸的風險。下圖展示了多層級聯複製的 Replication 架構。
當然,如果條件允許,我更傾向於建議大家通過拆分成多個 Replication 集群來解決上述瓶頸問題。畢竟 Slave 並沒有減少寫的量,所有 Slave 實際上仍然還是應用了所有的數據變更操作,沒有減少任何寫 IO。相反,Slave 越多,整個集群的寫 IO 總量也就會越多,我們沒有非常明顯的感覺,僅僅只是因為分散到了多台機器上面,所以不是很容易表現出來。
此外,增加複製的級聯層次,同一個變更傳到最底層的 Slave 所需要經過的 MySQL 也會更多,同樣可能造成延時較長的風險。
而如果我們通過分拆集群的方式來解決的話,可能就會要好很多了,當然,分拆集群也需要更複雜的技術和更複雜的應用系統架構。
13.3.4 Dual Master 與級聯複製結合架構(Master - Master - Slaves)
級聯複製在一定程度上面確實解決了 Master 因為所附屬的 Slave 過多而成為瓶頸的問題,但是他並不能解決人工維護和出現異常需要切換後可能存在重新搭建 Replication 的問題。這樣就很自然的引申出了 Dual Master 與級聯複製結合的 Replication 架構,我稱之為 Master - Master - Slaves 架構和 Master - Slaves - Slaves 架構相比,區別僅僅只是將第一級 Slave 集群換成了一臺單獨的 Master,作為備用 Master,然後再從這個備用的 Master 進行複製到一個Slave 集群。下麵的圖片更清晰的展示了這個架構的組成:
這種 Dual Master 與級聯複製結合的架構,最大的好處就是既可以避免主 Master 的寫入操作不會受到 Slave 集群的複製所帶來的影響,同時主 Master 需要切換的時候也基本上不會出現重搭 Replication 的情況。但是,這個架構也有一個弊端,那就是備用的Master 有可能成為瓶頸,因為如果後面的 Slave 集群比較大的話,備用 Master 可能會因為過多的 Slave IO 線程請求而成為瓶頸。當然,該備用 Master 不提供任何的讀服務的時候,瓶頸出現的可能性並不是特別高,如果出現瓶頸,也可以在備用 Master 後面再次進行級聯複製,架設多層 Slave 集群。當然,級聯複製的級別越多,Slave 集群可能出現的數據延時也會更為明顯,所以考慮使用多層級聯複製之前,也需要評估數據延時對應用系統的影響。
13.4 Replication 搭建實現
MySQL Replication環境的搭建實現比較簡單,總的來說其實就是四步,第一步是做好Master 端的準備工作。第二步是取得 Master 端數據的“快照”備份。第三步則是在 Slave端恢復 Master 的備份“快照”。第四步就是在 Slave 端設置 Master 相關配置,然後啟動複製。在這一節中,並不是列舉一個搭建 Replication 環境的詳細過程,因為這在 MySQL 官方操作手冊中已經有較為詳細的描述了,我主要是針對搭建環境中幾個主要的操作步驟中可以使用的各種實現方法的介紹,下麵我們針對這四步操作及需要註意的地方進行一個簡單的分析。
1. Master 端準備工作
在搭建 Replication 環境之前,首先要保證 Master 端 MySQL 記錄 Binary Log 的選項打開,因為 MySQL Replication 就是通過 Binary Log 來實現的。讓 Master 端 MySQL 記錄 Binary Log 可以在啟動 MySQL Server 的時候使用 —log-bin 選項或者在 MySQL 的配置文件 my.cnf 中配置 log-bin[=path for binary log]參數選項。
在開啟了記錄 Binary Log 功能之後,我們還需要準備一個用於複製的 MySQL 用戶。
可以通過給一個現有帳戶授予複製相關的許可權,也可以創建一個全新的專用於複製的帳戶。
當然,我還是建議用一個專用於複製的帳戶來進行複製。在之前“MySQL 安全管理”部分也 已經介紹過了,通過特定的帳戶處理特定一類的工作,不論是在安全策略方面更有利,對於維護來說也有更大的便利性。實現 MySQL Replication 僅僅只需要“REPLICATION SLAVE” 許可權即可。可以通過如下方式來創建這個用戶:
root@localhost : mysql 04:16:18> CREATE USER 'repl'@'192.168.0.2'
-> IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 04:16:34> GRANT REPLICATION SLAVE ON *.*
-> TO 'repl'@'192.168.0.2';
Query OK, 0 rows affected (0.00 sec)
這裡首先通過 CREATE USER 命令創建了一個僅僅具有最基本許可權的用戶 repl,然後再通過 GRANT 命令授予該用戶 REPLICATION SLAVE 的許可權。當然,我們也可以僅僅執行上面的第二條命令,即可創建出我們所需的用戶,這已經在“MySQL 安全管理”部分介紹過了。
2. 獲取 Master 端的備份“快照”
這裡所說的 Master 端的備份“快照”,並不是特指通過類似 LVM 之類的軟體所做的 snapshot,而是所有數據均是基於某一特定時刻的,數據完整性和一致性都可以得到保證的備份集。同時還需要取得該備份集時刻所對應的 Master 端 Binary Log 的準確 Log Position,因為在後面配置 Slave 的時候會用到。 一般來說,我們可以通過如下集中辦法獲得一個具有一致性和完整性的備份集以及所對應的 Log Position:
◆ 通過資料庫全庫冷備份
對於可以停機的資料庫,我們可以通過關閉 Master 端 MySQL,然後通過 copy 所有數據文件和日誌文件到需要搭建 Slave 的主機中合適的位置,這樣所得到的備份集是最完整的。在做完備份之後,然後再啟動 Master 端的MySQL。
當然,這樣我們還僅僅只是得到了一個滿足要求的備份集,我們還需要這個備份集所對應的日誌位置才能可以。對於這樣的備份集,我們有多種方法可以獲取到對應的日誌位置。如在 Master 剛剛啟動之後,還沒有應用程式連接上 Master 之前,通過執行SHOW Master STATUS 命令從 Master端獲取到我們可以使用的 Log Position。如果我們無法在 Master 啟動之後控制應用程式的連接,那麼可能在我們還沒有來得及執行SHOW Master STATUS 命令之前就已經有數據寫進來了,這時候我們可以通過mysqlbinlog 客戶端程式分析 Master 最新的一個 Binary Log來獲取其第一個有效的 Log Position。當然,如果你非常清楚你所使用的 MySQL 版本每一個新的 Binary Log 第一個有效的日誌位置,自然就不需要進行任何操作就可以。
◆ 通過 LVM 或者 ZFS 等具有 snapshot 功能的軟體進行“熱備份”
如果我們的 Master 是一個需要滿足 365 * 24 * 7 服務的資料庫,那麼我們就無法通過進行冷備份來獲取所需要的備份集。這時候,如果我們的 MySQL 運行在支持
Snapshot 功能的文件系統上面(如 ZFS),或者我們的文件系統雖然不支持 Snapshot, 但是我們的文件系統運行在 LVM 上面,那麼我們都可以通過相關的命令對 MySQL 的數據文件和日誌文件所在的目錄就做一個 Snapshot,這樣就可以得到了一個基本和全庫冷備差不多的備份集。
當然,為了保證我們的備份集數據能夠完整且一致,我們需要在進行Snapshot過 程中通過相關命令(FLUSH TABLES WITH READ LOCK)來鎖住所有表的寫操作,也包括支持事務的存儲引擎中commit動作,這樣才能真正保證該 Snapshot的所有數據都完整一致。在做完 Snapshot 之後,我們就可以 UNLOCK TABLES 了。可能有些人會擔心, 如果鎖住了所有的寫操作,那我們的應用不是就無法提供寫服務了麽?確實,這是無法避免的,不過,一般來說 Snapshot 操作所需要的時間大都比較短,所以不會影響太長時間。
那 Log Position 怎麼辦呢?是的,通過 Snapshot 所做的備份,同樣需要一個該備份所對應的 Log Position 才能滿足搭建 Replication 環境的要求。不過,這種方式下,我們可以比進行冷備份更容易獲取到對應的 Log Position。因為從我們鎖定了所有表的寫入操作開始到解鎖之前,資料庫不能進行任何寫入操作,這個時間段之內任何時候通過執行 SHOW MASTER STATUS 明令都可以得到準確的 Log Position。
由於這種方式在實施過程中並不需要完全停掉 Master 來進行,僅僅只需要停止寫入才做,所以我們也可以稱之為“熱備份”。
◆ 通過 mysqldump 客戶端程式
如果我們的資料庫不能停機進行冷備份,而且 MySQL 也沒有運行在可以進行Snapshot 的文件系統或者管理軟體之上,那麼我們就需要通過 mysqldump 工具來將Master 端需要複製的資料庫(或者表)的數據 dump 出來。為了讓我們的備份集具有一致性和完整性,我們必須讓 dump 數據的這個過程處於同一個事務中,或者鎖住所有需要複製的表的寫操作。要做到這一點,如果我們使用的是支持事務的存儲引擎(如Innodb),我們可以在執行 mysqldump 程式的時候通過添加 —single-transaction 選項來做到,但是如果我們的存儲引擎並不支持事務,或者是需要 dump 表僅僅只有部分支持事務的時候,我們就只能先通過 FLUSH TABLES WITH READ LOCK 命令來暫停所有寫入服務,然後再 dump 數據。當然,如果我們僅僅只需要 dump 一個表的數據,就不需要這麼麻煩了,因為 mysqldump 程式在 dump 數據的時候實際上就是每個表通過一條 SQL 來得到數據的,所以單個表的時候總是可以保證所取數據的一致性的。
上面的操作我們還只是獲得了合適的備份集,還沒有該備份集所對應的 Log Position,所以還不能完全滿足搭建 Slave 的要求。幸好 mysqldump 程式的開發者早就考慮到這個問題了,所以給 mysqldump 程式增加了另外一個參數選項來幫助我們獲取到對應的 Log Position,這個參數選項就是 —master-data 。當我們添加這個參數選項之後,mysqldump會在 dump 文件中產生一條 CHANGE MASTER TO 命令,命令中記錄了 dump時刻所對應的詳細的 Log Position 信息。如下:
測試 dump example 資料庫下的 group_message 表:
sky@sky:~$ mysqldump --master-data -usky -p example group_message >
group_message.sql
Enter password:
然後通過 grep 命令來查找一下看看:
sky@sky:~$ grep "CHANGE MASTER" group_message.sql
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000035', MASTER_LOG_POS=399;
連 CHANGE MASTER TO 的命令都已經給我們準備好了,還真夠體貼的,呵呵。
如果我們是要一次性 dump 多個支持事務的表的時候,可能很多人會選擇通過添加—single-transaction 選項來保證數據的一致性和完整性。這確實是一個不錯的選擇。
但是,如果我們需要 dump 的數據量比較大的時候,可能會產生一個很大的事務,而且會持續較長的時間。
◆ 通過現有某一個 Slave 端進行“熱備份”
如果現在已經有 Slave 從我們需要搭建 Replication 環境的 Master 上進行複製的話,那我們這個備份集就非常容易取得了。我們可以暫時性的停掉現有 Slave(如果有多台則僅僅只需要停止其中的一臺),同時執行一次 FLUSH TABLES 命令來刷新所有表和索引的數據。這時候在該 Slave 上面就不會再有任何的寫入操作了,我們既可以通過 copy 所有的數據文件和日誌文件來做一個全備份,同時也可以通過 Snapshot(如果支持)來進行備份。當然,如果支持 Snapshot功能,還是建議大家通過 Snapshot 來做,因為這樣可以使 Slave 停止複製的時間大大縮短,減少該 Slave 的數據延時。
通過現有 Slave 來獲取備份集的方式,不僅僅得到資料庫備份的方式很簡單,連所需要 Log Position,甚至是新 Slave 後期的配置等相關動作都可以省略掉,只需要新的 Slave 完全基於這個備份集來啟動,就可以正常從 Master 進行複製了。
整個過程中我們僅僅只是在短暫時間內停止了某台現有 Slave 的複製線程,對系統的正常服務影響很小,所以這種方式也基本可以稱之為“熱備份”。
3. 通過 Slave 端恢復備份“快照”
上面第二步我們已經獲取到了所需要的備份集了,這一步所需要做的就是將上一步所得到的備份集恢復到我們的 Slave 端的 MySQL 中。
針對上面四種方法所獲取的備份集的不同,在 Slave 端的恢復操作也有區別。下麵就針對四種備份集的恢復做一個簡單的說明:
◆ 恢復全庫冷備份集
由於這個備份集是一個完整的資料庫物理備份,我們僅僅只需要將這個備份集通過FTP 或者是 SCP 之類的網路傳輸軟體複製到 Slave 所在的主機,根據 Slave 上my.cnf 配置文件的設置,將文件存放在相應的目錄,覆蓋現有所有的數據和日誌等相關文件,然後再啟動 Slave 端的 MySQL,就完成了整個恢復過程。
◆ 恢復對 Master 進行 Snapshot 得到的備份集
對於通過對 Master 進行 Snapshot 所得到的備份集,實際上和全庫冷備的恢復方法基本一樣,唯一的差別隻是首先需要將該 Snapshot 通過相應的文件系統 mount 到某個目錄下,然後才能進行後續的文件拷貝操作。之後的相關操作和恢復全庫冷備份集基本一致,就不再累述。
◆ 恢復 mysqldump 得到的備份集
通過 mysqldump 客戶端程式所得到的備份集,和前面兩種備份集的恢復方式有較大的差別。因為前面兩種備份集的都屬於物理備份,而通過 mysqldump 客戶端程式所做的備份屬於邏輯備份。恢復 mysqldump 備份集的方式是通過 mysql 客戶端程式來執行備份文件中的所有 SQL 語句。
使用 mysql 客戶端程式在 Slave 端恢復之前,建議複製出通過 —master-data 所得到的 CHANGE MASTER TO 命令部分,然後在備份文件中註銷掉該部分,再進行恢復。
因為該命令並不是一個完整的 CHANGE MASTER TO 命令,如果在配置文件(my.cnf)中沒有配置MASTER_HOST,MASTER_USER,MASTER_PASSWORD 這三個參數的時候,該語句是無法有效完成的。
通過 mysql 客戶端程式來恢復備份的方式如下:
sky@sky:~$ mysql -u sky -p -Dexample < group_message.sql
這樣即可將之前通過 mysqldump 客戶端程式所做的邏輯備份集恢復到資料庫中了。
◆ 恢復通過現有 Slave 所得到的熱備份
通過現有 Slave 所得到的備份集和上面第一種或者第二種備份集也差不多。如果是通過直接拷貝數據和日誌文件所得到的備份集,那麼就和全庫冷備一樣的備份方式,如果是通過 Snapshot 得到的備份集,就和第二種備份恢復方式完全一致。
4. 配置並啟動 Slave
在完成了前面三個步驟之後, Replication 環境的搭建就只需要最後的一個步驟了,那就是通過 CHANGE MASTER TO 命令來配置 然後再啟動 Slave 了。
CHANGE MASTER TO 命令總共需要設置5項內容,分別為:
MASTER_HOST:Master 的主機名(或者 IP 地址);
MASTER_USER:Slave 連接 Master 的用戶名,實際上就是之前所創建的 repl 用戶;
MASTER_PASSWORD:Slave 連接 Master 的用戶的密碼;
MASTER_LOG_FILE:開始複製的日誌文件名稱;
MASTER_LOG_POS:開始複製的日誌文件的位置,也就是在之前介紹備份集過程中一致提到的 Log Position。
下麵是一個完整的 CHANGE MASTER TO 命令示例:
CHANGE MASTER TO
root@localhost : mysql 08:32:38> CHANGE MASTER TO
-> MASTER_HOST='192.168.0.1',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='password',
-> MASTER_LOG_FILE='mysql-bin.000035',
-> MASTER_LOG_POS=399;
執行完 CHANGE MASTER TO 命令之後,就可以通過如下命令啟動 SLAVE 了:
root@localhost : mysql 08:33:49> START SLAVE;
至此,我們的 Replication 環境就搭建完成了。讀者朋友可以自己進行相應的測試來嘗試搭建,如果需要瞭解 MySQL Replication搭建過程中更為詳細的步驟,可以通過查閱MySQL 官方手冊。
13.5 小結
在實際應用場景中,MySQL Replication 是使用最為廣泛的一種提高系統擴展性的設計手段。眾多的 MySQL 使用者通過 Replication 功能提升系統的擴展性之後,通過簡單的增加價格低廉的硬體設備成倍甚至成數量級的提高了原有系統的性能,是廣大 MySQL 中低端使用者最為喜愛的功能之一,也是大量 MySQL 使用者選擇 MySQL 最為重要的理由之一。
摘自:《MySQL性能調優與架構設計》簡朝陽
轉載請註明出處:
作者:JesseLZJ
出處:http://jesselzj.cnblogs.com