1. 程式人生 > 實用技巧 >MySQL複製

MySQL複製

Asweknow,當今社會,資訊化發展十分迅猛,資訊對於每個人來說都是至關重要的,那麼對於一個對資料十分敏感的IT人來說,資料的安全性是至關重要的,今天我們就從資料的複製來淺談怎樣保證資料的安全性。

目前,對於任何的行業,資訊量都十分大,那麼我們的伺服器硬體裝置可能就會滿足不了當前的發展,這就成為了制約系統性能的一個瓶頸,因此如果要擴充套件系統性能兩種方式:向上擴充套件(scaleup)和向外擴充套件(scaleout)

一般來說,向上擴充套件就是擴充套件硬體(比如增加大型機等),這種方式有一個最大的缺陷就是計算能力的增加跟經濟消耗是不成正比的,換句話說,系統性能增加的程度遠遠低於經濟消耗水平。因此目前很多公司都比較傾向於購買商業硬體來替代這些產品

對於資料庫伺服器來講,在有限的條件下,既想讓我們的伺服器效能很好,又不想在資金方面投入太多的話,這就是複製出現的原因,

MySQL的複製架構:

就是對於任何影響資料的請求都記錄到本地的二進位制日誌檔案中,從伺服器中的I/Othread可以不停的向主伺服器傳送請求監控二進位制日誌檔案中產生的每個二進位制事件,一旦有事務產生,向主伺服器發起複製請求,一旦發現主伺服器上的事件與從伺服器上的不一致,那麼主伺服器就會啟動dumpthread將新的事件讀取出來併發送給I/OthreadI/Othread再將二進位制日誌檔案存放到中繼日誌中。而後在從伺服器中再啟動一個執行緒,即sqlthread,把中繼日誌中的二進位制日誌檔案產生的事件讀取過來,在本地伺服器上執行一遍,因此每當主伺服器上產生一個新的資料時,從伺服器上面就會更新,並且拿來應用,這就是所謂的複製。

//dumpthread:位於主伺服器上的執行緒,用於專門接收來自從伺服器I/O執行緒傳送的請求

//I/Othread:位於從伺服器,主要功能:向主伺服器發起複製請求,一旦發現主伺服器上的事件與從伺服器上的不一致,那麼主伺服器就會啟動dumpthread將新的事件讀取出來併發送給I/OthreadI/Othread再將二進位制日誌檔案存放到中繼日誌中。

//sqlthread:負責從中繼日誌中依次把事件讀取過來,並在本地資料庫上執行一次。(眾所周知,二進位制日誌中的事件其實就是sql語句,因此在從伺服器上執行一次,等於在本地生成一個和主伺服器同樣的結果)

但在這種複製並不是單純的簡單的把主伺服器上的資料檔案複製,而是將主伺服器上任何可以改變資料變化的語句複製到中繼日誌檔案中,而複製的方式是通過二進位制日誌檔案中的事件來完成的,而後由一個獨立的執行緒將其讀取過來,在本地伺服器上再應用一次,這就是

MySQLReplication。這樣就保證了主伺服器和從伺服器的資料一致性。

那麼這樣的複製過程又簡單的分為幾種情況:

非同步複製:一旦事務產生,那麼就會記錄在主伺服器的二進位制日誌檔案中,他就會立即向客戶端返回響應結果,主伺服器是不關心從伺服器是否已經把資料複製過去了,而是要靠從伺服器本身通過各種機制把資料同步過去;這樣雖然速度提升上去了,但是也會產生一些問題,比如說,當主從伺服器都執行很長時間後,可能會發現主從伺服器之間的資料可能會不一致,那是因為主伺服器從來不等待從伺服器,或許因為網路延遲等各種原因,時間久了後,從伺服器可能就從主伺服器上找不到一些事件,就會產生主從伺服器之間資料不一致的情況。這就是從伺服器的滯後性。

產生這種滯後性的重要原因主要是:在主伺服器上,眾所周知,同一時刻可能會執行多個事務,在主伺服器上可以並行,然後在從伺服器上只能執行一個程序來依次獲取主伺服器上的二進位制日誌檔案,因此對於繁忙的主伺服器來說,產生滯後性的可能性是非常大的。

同步複製:客戶端提交事務,首先在本地資料區域中儲存下來,而後事件寫入二進位制日誌檔案中,同時二進位制日誌檔案要寫入到從伺服器的中繼日誌檔案中去,且有從伺服器的某一執行緒在本地伺服器上應用一次,然後告訴主伺服器同步完成,再響應給客戶端。基於同步複製是非常漫長的,因此這種方法是不可用的,所以大部分都是非同步的

我們在做主從架構的時候需要注意幾點,如果主伺服器和從伺服器都是新的,資料都是從零開始這個不需要太多的考慮;如果主伺服器已經執行很久,從伺服器是新新增上去的,那麼就需要取得主伺服器上的一個完全備份在從伺服器上恢復,再告訴怎麼去主伺服器上覆制。

關於資料安全:

前面我們知道,在主伺服器上,一個事務被提交了以後,為了保證這個事務以後能夠用二進位制恢復回來,我們一般將這個事件寫入到二進位制日誌中去,但是我們易知二進位制日誌檔案其實就是磁碟上的物理檔案,那麼如果直接的把事件寫入到二進位制日誌中的話,對於一臺繁忙的伺服器來說,就會額外的增加了許多I/O操作,而且速度還很慢,所以為了加速這樣的操作,我們運用了buffer(緩衝,即核心維護的一段記憶體空間),任何寫入操作都在buffer中完成,這樣就大大加快了速度,會在很短的時間內響應給客戶端寫入成功,只不過會在稍後才把資料同步到事務日誌或二進位制日誌檔案(如果事務涉及到了寫語句)中去,通過刷寫的頻率,一旦事務被提交,我們就根據刷寫頻率把事務提交到事務日誌中去,同時根據刷寫的規則,可以立即刷寫到磁碟上,這就保證了事務的安全可靠性,即使發生意外,這也可以保證我們事務的完整性;如果一個事務提交以後,此事務的相關語句要被提交到二進位制檔案中去,為了加速二進位制的操作,我們都是在核心的緩衝去中進行的,那麼如果系統斷電或發生別的意外情況,我們的二進位制日誌檔案就會丟失,等再次開機後就會造成事務的不完整性,這樣就導致了主伺服器和從不服務的資料不一致性。

為了保證事務不會在二進位制檔案中丟失,那麼只要事務commit,就通過刷寫操作,把buffer中的二進位制資料檔案立即同步到磁碟中去。這個引數叫做sync_binlog,通過設定此引數來判定當事務commitbuffer當中後,是否立即同步到磁碟中去

這就是所謂的資料安全。為了儘可能降低資料丟失的可能性,生成環境中,我們一般都要啟用這項,當然他也會產生大量的磁碟I/O,加大系統資源開銷,損失一部分效能。

說明:

//刷寫二進位制事務的引數:sync_binlog,此引數相當重要

//刷寫事務的引數,對於Innodb引擎來說,此引數相當重要

innodb_flush_log_at_trx_commit={0|1|2}

設定InnoDB同步日誌緩衝區(logbuffer)資料至日誌檔案中的方式,以及刷寫日誌檔案至磁碟的方式。其可接受的值中,“0”表示將日誌緩衝區每秒一次地寫入日誌檔案,並同時將日誌檔案刷寫至磁碟中,但事務提交時不會採取任何動作;“1”是預設值,表示在有事務提交時將日誌緩衝區寫入日誌檔案,並同時將日誌檔案刷寫至磁碟;“2”表示每事務提交或每秒一次將日誌緩衝區寫入日誌檔案,但不會同時執行日誌檔案的刷寫操作。當然,由於作業系統程序排程的原因,每秒一次的日誌寫入或刷寫操作並不能得到100%的保證。

完全相容ACID的場景需要將此變數值設定為1,由於要執行每事務的日誌刷寫操作,其會阻止I/O呼叫,直到寫操作完成,故其會顯著降低InnoDB每秒鐘可以提交的事務數。設定為“2”可獲得比“1”更好的效能,而且僅在作業系統崩潰時才會丟失最後一秒鐘的資料,因此資料安全性也有著不錯的表現。設定為“0”則有可能會導致事務最後一秒鐘的資料丟失,於是整個事務的資料安全性將無法保證,但其通常有著最好的效能。為了在最大程式上保證複製的InnoDB事務永續性和一致性,應該設定變數innodb_flush_log_at_trx_commit=1以及設定變數sync_binlog=1。

然而需要注意的是,有些磁碟自身也有快取,這可能會給事務操作帶來額外的潛在風險。可以使用hdparm工具或供應商的自有工具等禁用磁碟自身的快取。當然,高效能事務的最佳配置是把此變數的值設定為1,並且將日誌檔案放在有備用電池的寫入快取的RAID上。作用範圍為全域性,可用於選項檔案,屬動態變數。

對於從伺服器來說,I/Othread從dumpthread獲得事件後,I/Othread要把事件寫入到中繼日誌中去的,要知道此操作也屬於磁碟的I/O操作,因為為了加速這個過程,在從伺服器中也引入了buffer,這種機制帶來的直接後果就是從伺服器要落後於主伺服器,這樣也就存在了從伺服器資料丟失的可能性。但是隻要我們的主伺服器中存在資料,從伺服器就可以從主伺服器上進行恢復。

半同步複製概念的引入:

對於主從資料庫伺服器而言,從伺服器都有可能存在資料的延後性,為了解決這種情況,我們這裡引入了半同步複製的概念:當客戶端提交事務後,伺服器端先將事務寫到二進位制日誌檔案中,並通知從伺服器端,把二進位制檔案儲存到中繼日誌中,從伺服器解析後,把結果反饋給主伺服器,只等待眾多從伺服器中某一臺響應即可,如果沒有響應的話,主伺服器根據響應時間,放棄半同步模式,進入非同步模式,直接響應客戶端。因此,如果我們要配置半同步的話最好在同一個機房內,頻寬足夠大,預設半同步等待時間為:10s,且從伺服器是不允許寫的。

資料庫讀寫分離概念的引入:

通過前面我們知道,從伺服器是隻能讀不能寫的,而主伺服器是具有讀寫功能的,如果我們的系統是一個具有一定規模的web系統的話,當客戶端請求對資料庫進行讀寫操作時,我們的主資料庫伺服器可以兼具對請求進行相應,這可能就會是主伺服器很繁忙,而從伺服器比較空閒,為了解決這樣的問題,那麼我們可以這樣設計,即當客戶端有讀操作時,從伺服器直接來響應,當客戶端有寫操作時,主伺服器直接來響應。這樣就能平衡資源的利用,緩解主伺服器的壓力。

然而,當客戶端發來請求時,我們的資料庫伺服器端是無法對讀寫進行分配過濾的,他還是隻能把所有的請求都分配都同一臺主機上,為了解決這個問題,我們引入了資料庫代理的概念,資料庫代理的主要功能就是實現把客戶端的讀寫請求分開發送給主從伺服器。能夠提供這種功能的有MySQLProxy。這只是一種框架,指令碼需要自己來寫的。

讀寫分離的框架結構為:

比較有名的幾種代理:

MySQLProxy

提供的功能:連線路由、Query分析、查詢過濾和修改、負載均衡、簡單HA的功能

Amoeba(Java)也是讀寫分離器,執行資料庫切分,在內部實現資料路由

利用Java虛擬機器建立起來的功能,

功能:查詢路由、查詢分析、查詢過濾、讀寫分離、負載均衡、HA功能

Cobar(Java)基於Amoeba,淘寶的產品

關於雙主模型:

當系統的業務量很大的情況下,客戶端對主伺服器的寫操作的併發量很大,那麼主伺服器可能就會超負荷工作,這就會大大加大發生宕機的概率,為了減小這種概率,這裡採用了雙主模型,即Master/Master模型。