MySQL複製

 

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

目前,對於任何的行業,信息量都十分大,那麼我們的服務器硬件設備可能就會滿足不了當前的發展,這就成爲了制約系統性能的一個瓶頸,因此如果要擴展系統性能兩種方式:向上擴展(scale up)和向外擴展(scale out)

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

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

MySQL的複製架構:

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

//dump thread:位於主服務器上的線程,用於專門接收來自從服務器I/O線程發送的請求

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

//sql thread:負責從中繼日誌中依次把事件讀取過來,並在本地數據庫上執行一次。(衆所周知,二進制日誌中的事件其實就是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同步日誌緩衝區(log buffer)數據至日誌文件中的方式,以及刷寫日誌文件至磁盤的方式。其可接受的值中,“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/O thread 從dump thread獲得事件後,I/O thread 要把事件寫入到中繼日誌中去的,要知道此操作也屬於磁盤的I/O操作,因爲爲了加速這個過程,在從服務器中也引入了buffer,這種機制帶來的直接後果就是從服務器要落後於主服務器,這樣也就存在了從服務器數據丟失的可能性。但是隻要我們的主服務器中存在數據,從服務器就可以從主服務器上進行恢復。

半同步複製概念的引入:

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

數據庫讀寫分離概念的引入:

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

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

讀寫分離的框架結構爲:

比較有名的幾種代理:

MySQL Proxy

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

Amoeba(Java)也是讀寫分離器,運行數據庫切分,在內部實現數據路由

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

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

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

關於雙主模型:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章