-
1 # 愛可生雲資料庫
-
2 # 列克美食
資料主從同步的由來
網際網路的很多業務,特別是在高併發的場景下,基本都是讀遠遠大於寫,如果資料庫讀和寫的壓力都同在一臺主機上,這顯然不太合理。
於是,把一臺資料庫主機分為單獨的一臺寫主庫(主要負責寫操作),而把讀的資料庫壓力分配給讀的從庫,而且讀從庫可以變為多臺,這就是讀寫分離的典型場景如下:
為了進一步的降低資料庫端的壓力(高併發的瓶頸),這個時候也會在業務層部署分散式快取叢集(redis、memcached)等,把讀的壓力轉移給應用伺服器端,其實與資料主從的設計是遵循同一個原則,降低後端資料庫的壓力。
問題:
讀寫分離提高了資源的利用效率的同時也引出了一個問題,就是由於延時(網路傳輸,操作)而引起的資料庫主從不一致的問題,以下會詳細談相關的資料一致性解決方案。
資料同步一致性解決方案
1.半同步複製
辦法就是等主從同步完成之後,等主庫上的寫請求再返回,這就是常說的“半同步複製"。
實現方案
mysql的半同步複製方案,下面我以mysql為例介紹。
MySQL半同步複製
MySQL的Replication預設是一個非同步複製的過程,從MySQL5.5開始,MySQL以外掛的形式支援半同步複製,我先談下非同步複製,這樣可以更好的理解半同步複製。
1)非同步複製
MySQL預設的複製是非同步的,主庫在執行完客戶端提交的事務後會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主如果crash掉了,此時主上已經提交的事務可能並沒有傳到從庫上。
2)半同步複製
對於非同步複製和全同步複製之間,主庫在執行完客戶端提交的事務後不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。相對於非同步複製,半同步複製提高了資料的安全性,同時它也造成了一定程度的延遲,這個延遲最少是一個TCP/IP往返的時間。所以,半同步複製最好在低延時的網路中使用。
半同步複製原理:
事務在主庫寫完binlog後需要從庫返回一個已接受,才放回給客戶端
mysql5.5版本以後,以外掛的形式存在,需要單獨安裝
確保事務提交後binlog至少傳輸到一個從庫
不保證從庫應用完成這個事務的binlog
效能有一定的降低
網路異常或從庫宕機,卡主庫,直到超時或從庫恢復
該方案優點:
利用資料庫原生功能,比較簡單
該方案缺點:
主庫的寫請求時延會增長,吞吐量會降低
2.資料庫中介軟體
流程:
1)所有的讀寫都走資料庫中介軟體,通常情況下,寫請求路由到主庫,讀請求路由到從庫
2)記錄所有路由到寫庫的key,在主從同步時間視窗內(假設是500ms),如果有讀請求訪問中介軟體,此時有可能從庫還是舊資料,就把這個key上的讀請求路由到主庫。
3)在主從同步時間過完後,對應key的讀請求繼續路由到從庫。
相關的中介軟體有:
1)canal:是阿里巴巴旗下的一款開源專案,純Java開發,基於資料庫增量日誌解析,提供增量資料訂閱&消費,目前主要支援了MySQL。
2)otter:也是阿里開源的一個分散式資料庫同步系統,尤其是在跨機房資料庫同步方面,有很強大的功能。它是基於資料庫增量日誌解析,實時將資料同步到本機房或跨機房的mysql/oracle資料庫。
兩者的區別在於:
otter目前嵌入式依賴canal,部署為同一個jvm,目前設計為不產生Relay Log。
otter目前允許自定義同步邏輯,解決各類需求。
該方案優點
能保證絕對一致
該方案缺點:
資料庫中介軟體的成本較高
3.快取記錄寫key法
寫流程:
1)如果key要發生寫操作,記錄在cache裡,並設定“經驗主從同步時間”的cache超時時間,例如500ms
2)然後修改主資料庫
讀流程:
1)先到快取裡檢視,對應key有沒有相關資料
2)有相關資料,說明快取命中,這個key剛發生過寫操作,此時需要將請求路由到主庫讀最新的資料。
3)如果快取沒有命中,說明這個key上近期沒有發生過寫操作,此時將請求路由到從庫,繼續讀寫分離。
該方案優點:
相對資料庫中介軟體,成本較低
該方案缺點:
為了保證“一致性”,引入了一個cache元件,並且讀寫資料庫時都多了快取操作。
回覆列表
在談這個特性之前,我們先來看看mysql的複製架構衍生史。 MySQL的複製分為三種: 第一種,即普通的replication。 搭建簡單,使用非常廣泛,從mysql誕生之初,就產生了這種架構,效能非常好,可謂非常成熟。 但是這種架構資料是非同步的,所以有丟失資料庫的風險。 第二種,即mysql cluster。 搭建也簡單,本身也比較穩定,是mysql裡面對資料保護最最靠譜的架構,也是唯一一個數據完全同步的架構,絕對的零丟失。不過效能就差遠些了。 第三種,即semi-sync replication,半同步,效能,功能都介於以上兩者之間。從mysql5.5開始誕生,目的是為了折中上述兩種架構的效能以及優缺點。“我們今天談論第三種架構
我們知道,普通的replication,也即mysql的非同步複製,依靠mysql二進位制日誌也即binary log進行資料複製。比如兩臺機器,一臺主機也即master,另外一臺是從機,也即slave。
1. 正常的複製為:事務一(t1)寫入binlog buffer;dumper 執行緒通知slave有新的事務t1;binlog buffer 進行checkpoint;slave的io執行緒接收到t1並寫入到自己的的relay log;slave的sql執行緒寫入到本地資料庫。 這時,master和slave都能看到這條新的事務,即使master掛了,slave可以提升為新的master。 2. 異常的複製為:事務一(t1)寫入binlog buffer;dumper 執行緒通知slave有新的事務t1;binlog buffer 進行checkpoint;slave因為網路不穩定,一直沒有收到t1;master 掛掉,slave提升為新的master,t1丟失。
3. 很大的問題是:主機和從機事務更新的不同步,就算是沒有網路或者其他系統的異常,當業務併發上來時,slave因為要順序執行master批次事務,導致很大的延遲。
為了彌補以上幾種場景的不足,mysql從5.5開始推出了半同步。
即在master的dumper執行緒通知slave後,增加了一個ack,即是否成功收到t1的標誌碼。也就是dumper執行緒除了傳送t1到slave,還承擔了接收slave的ack工作。如果出現異常,沒有收到ack,那麼將自動降級為普通的複製,直到異常修復。
我們可以看到半同步帶來的新問題: 1. 如果異常發生,會降級為普通的複製。 那麼從機出現數據不一致的機率會減少,並不是完全消失。 2. 主機dumper執行緒承擔的工作變多了,這樣顯然會降低整個資料庫的效能。 3. 在MySQL 5.5和5.6使用after_commit的模式下, 即如果slave 沒有收到事務,也就是還沒有寫入到relay log 之前,網路出現異常或者不穩定,此時剛好master掛了,系統切換到從機,兩邊的資料就會出現不一致。 在此情況下,slave會少一個事務的資料。
隨著MySQL 5.7版本的釋出,半同步複製技術升級為全新的Loss-less Semi-Synchronous Replication架構,其成熟度、資料一致性與執行效率得到顯著的提升。
MySQL 5.7對資料複製效率進行了改進1 主從一致性加強支援在事務commit前等待ACK
新版本的semi sync 增加了rpl_semi_sync_master_wait_point引數 來控制半同步模式下 主庫在返回給會話事務成功之前提交事務的方式。
該引數有兩個值:
AFTER_COMMIT(5.6預設值)
master將每個事務寫入binlog ,傳遞到slave 重新整理到磁碟(relay log),同時主庫提交事務。master等待slave 反饋收到relay log,只有收到ACK後master才將commit OK結果反饋給客戶端。
AFTER_SYNC(5.7預設值,但5.6中無此模式)
master 將每個事務寫入binlog , 傳遞到slave 重新整理到磁碟(relay log)。master等待slave 反饋接收到relay log的ack之後,再提交事務並且返回commit OK結果給客戶端。 即使主庫crash,所有在主庫上已經提交的事務都能保證已經同步到slave的relay log中。
因此5.7引入了after_sync模式,帶來的主要收益是解決after_commit導致的master crash主從間資料不一致問題,因此在引入after_sync模式後,所有提交的資料已經都被複制,故障切換時資料一致性將得到提升。
2 效能提升支援傳送binlog和接受ack的非同步化
舊版本的semi sync 受限於dump thread ,原因是dump thread 承擔了兩份不同且又十分頻繁的任務:傳送binlog 給slave ,還需要等待slave反饋資訊,而且這兩個任務是序列的,dump thread 必須等待 slave 返回之後才會傳送下一個 events 事務。dump thread 已然成為整個半同步提高效能的瓶頸。在高併發業務場景下,這樣的機制會影響資料庫整體的TPS .
圖:Without ACK receiving thread
為了解決上述問題,在5.7版本的semi sync 框架中,獨立出一個 ack collector thread ,專門用於接收slave 的反饋資訊。這樣master 上有兩個執行緒獨立工作,可以同時傳送binlog 到slave ,和接收slave的反饋。
圖:With ACK receiving thread3 效能提升控制主庫接收slave 寫事務成功反饋數量
MySQL 5.7新增了rpl_semi_sync_master_wait_slave_count引數,可以用來控制主庫接受多少個slave寫事務成功反饋,給高可用架構切換提供了靈活性。
如圖所示,當count值為2時,master需等待兩個slave的ack
4 效能提升
Binlog 互斥鎖改進
舊版本半同步複製在主提交binlog的寫會話和dump thread讀binlog的操作都會對binlog新增互斥鎖,導致binlog檔案的讀寫是序列化的,存在併發度的問題。
MySQL 5.7對binlog lock進行了以下兩方面最佳化
1.移除了dump thread對binlog的互斥鎖
2.加入了安全邊際保證binlog的讀安全
5 效能提升組提交
5.7引入了新的變數slave-parallel-type,其可以配置的值有:
DATABASE (5.7之前預設值),基於庫的並行複製方式;LOGICAL_CLOCK (5.7新增值),基於組提交的並行複製方式;
MySQL 5.6版本也支援所謂的並行複製,但是其並行只是基於DATABASE的,也就是基於庫的。如果使用者的MySQL資料庫例項中存在多個DATABASE ,對於從機複製的速度的確可以有比較大的幫助,如果使用者例項僅有一個庫,那麼就無法實現並行回放,甚至效能會比原來的單執行緒更差。
MySQL5.7中增加了一種新的並行模式:為同時進入COMMIT階段的事務分配相同的序列號,這些擁有相同序列號的事務在備庫是可以併發執行的。
MySQL 5.7真正實現的並行複製,這其中最為主要的原因就是slave伺服器的回放與主機是一致的即master伺服器上是怎麼並行執行的slave上就怎樣進行並行回放。不再有庫的並行複製限制,對於二進位制日誌格式也無特殊的要求(基於庫的並行複製也沒有要求)。
因此下面的序列中可以併發的序列為(其中前面一個數字為last_committed ,後面一個數字為sequence_number ):
trx1 1…..2trx2 1………….3trx3 1…………………….4trx4 2……………………….5trx5 3…………………………..6trx6 3………………………………7trx7 6………………………………..8
備庫並行規則:當分發一個事務時,其last_committed 序列號比當前正在執行的事務的最小sequence_number要小時,則允許執行。
因此,
a)trx1執行,last_commit<2的可併發,trx2, trx3可繼續分發執行
b)trx1執行完成後,last_commit < 3的可以執行, trx4可分發
c)trx2執行完成後,last_commit < 4的可以執行, trx5, trx6可分發
d)trx3、trx4、trx5完成後,last_commit < 7的可以執行,trx7可分發
綜上所述
我們認為MySQL 5.7版對Loss-Less半同步複製技術的最佳化,使得其成熟度和執行效率都得到了質的提高。我們建議在使用MySQL 5.7作為生產環境的部署時,可以使用半同步技術作為高可用與讀寫分離方案的資料複製方案。