天天看點

MySQL資料庫丢失資料場景分析

下載下傳網站:www.SyncNavigator.CN 

 客服QQ1793040

----------------------------------------------------------

關于HKROnline SyncNavigator 注冊機價格的問題

MySQL資料庫丢失資料場景分析
HKROnline SyncNavigator 8.4.1 非破解版 注冊機 授權激活教程
MySQL資料庫丢失資料場景分析

最近一直在研究資料庫同步的問題,在網上查了很多資料,也請教了很多人,找到了一種通過快照複制的方法。研究了一番後發現之前就是用的這個方法,效果不是很好,果斷放棄。經過了一番尋覓和他人指點,最後從一位熱心網友那裡得知一款很好用的軟體—— SyncNavigator。

好東西就要拿出來跟大家分享,是以今天向大家介紹一下這款軟體,及其一些使用方法。下面先看看它有什麼強大的功能吧!

SyncNavigator的基本功能:

自動同步資料/定時同步資料

無論是實時同步/24小時不間斷同步,還是根據計劃任務(每小時/每日/每周/等)定時自動同步都能完全勝任。

完整支援 Microsoft SQL Server

完整支援 Microsoft SQL Server 2000 2005 2008 資料庫類型。并能在不同資料庫版本之間互相同步資料。

支援 MySQL 4.1 以上版本

支援 MySQL 4.1 5.0 5.1 5.4 5.5。并能在不同資料庫版本之間互相同步資料。

無人值守和故障自動恢複

當資料庫故障或網絡故障以後,無需人工幹預(或操作)自動恢複同步并確定資料完全準确,可靠。

同構資料庫同步/異構資料庫同步

SQL Server to SQL Server, MySQL to MySQL, SQL Server to MySQL 等都能輕松實作。

斷點續傳和增量同步

當同步完成(或中斷)後,再次同步時能繼續上一次的位置增量同步,避免每次都需要從頭開始的問題。

引擎層資料丢失場景

1.1.InnoDB丢失資料場景分析

InnoDB作為MySQL支援事務的存儲引擎,同Oracle類似,事務送出時需要寫redo、undo log。 InnoDB采用預寫日志(Write Ahead Log)政策,資料頁的變更會首先在記憶體中完成,同時将事務操作順序記錄到redo log中。完成上述的操作後表示該事務已經完成,可以傳回給應用已送出的資訊。 但此時實際被更改的資料頁還儲存在記憶體中(稱為髒頁),并沒有flush到磁盤上即沒有落地。刷盤操作一般會在達到一定條件後,觸發checkpoint機制,此時會将記憶體中的髒頁合并寫入到磁盤裡,完成資料同步。

刷盤政策

由innodb_flush_log_at_trx_commit參數控制的政策。如下圖:

MySQL資料庫丢失資料場景分析

參數innodb_flush_log_at_trx_commit:

=0 :每秒 write os cache & flush disk

=1 :每次commit都 write os cache & flush disk

=2 :每次commit都 write os cache,然後根據innodb_flush_log_at_timeout參數(預設為1s) flush disk

innodb_flush_log_at_trx_commit=1最為安全,因為每次commit都保證redo log寫入了disk。但是這種方式性能對DML性能來說比較低,在我們的測試中發現,如果設定為2,DML性能要比設定為1高10倍左右(是以在短信平台出現寫入問題時,已将該參數設定為2)。

innodb_flush_log_at_trx_commit為0或2的差別主要展現在在mysql service crash或system crash時丢失事務的類型:

1)當mysql service crash時,設定為0就會丢失1秒内的所有已送出及未送出的事務,且無法復原(因為redo log還記錄在log buffer中,沒有落盤到redo log)。而設定為2時,每次送出都會寫入到os cache中,即使service crash掉,也隻會丢失1秒内所有未送出的事務,而已送出的事務已經寫入redo log中,可以復原。

2)當system crash時,與上述類似。

是以,業内的共識是在一些DML操作頻繁的場景下,參數innodb_flush_log_at_trx_commit設定為2。

雖然這樣就存在丢資料的風險:當出現mysql service crash時,重新開機後InnoDB會進行crash recovery,則會丢失innodb_flush_log_at_timeout秒内的已送出的資料。未送出的資料則可由應用中的事務補償機制處理。但是IO性能可以提高至少10倍。

PS:當開啟了内部XA事務(預設開啟),且開啟binlog,情況稍有不一樣。見下文。

1.2.MyISAM丢失資料場景分析

MyISAM存儲引擎在我們的生産環境中基本沒有使用。而且我們線上的5.6版本已将系統的資料字典表中繼資料表等系統表的預設存儲引擎修改為InnoDB。

由于MyISAM不支援事務,且沒有data cache,所有DML操作隻寫到OS cache中,flush disk操作均由OS來完成,是以如果伺服器當機,這部分資料肯定會丢失。

2.主從複制導緻資料不一緻的場景

MySQL主從複制原理:MySQL主庫在事務送出時寫binlog,并通過sync_binlog參數來控制binlog重新整理到磁盤“落地”。從庫中有兩個線程: IO線程負責從主庫讀取binlog,并記錄到本地的relay log中;SQL線程再将relay log中的記錄應用到從庫。如下圖所示:

2.1.binlog重新整理機制

master寫binlog與innodb引擎寫redo類似,由參數sync_binlog控制:

= 0 :表示MySQL不控制binlog的重新整理,由檔案系統控制binlog cache的刷盤操作

= N :表示每sync_binlog在N次事務送出後,MySQL調用檔案系統的flush操作将binlog cache中的内容刷盤

sync_binlog=1時最安全,即表示每次事務送出,MySQL都會把binlog cache中的内容flush disk。這樣在掉電等情況下,系統隻有可能丢失1個事務的資料。但是sync_binlog為1時,系統的IO消耗非常大。

但是N的值也不易過大,否則在系統掉電時會丢失較多的事務。目前我們生産系統設定為100.

2.2.内部XA事務原理

MySQL的存儲引擎與MySQL服務層之間,或者存儲引擎與存儲引擎之間的分布式事務,稱之為MySQL内部XA事務。最為常見的内部XA事務存在與binlog與InnoDB存儲引擎之間。在事務送出時,先寫二進制日志,再寫InnoDB存儲引擎的redo log。對于這個操作要求必須是原子的,即需要保證兩者同時寫入。内部XA事務機制就是保證兩者的同時寫入。

XA事務的大緻流程:

1)事務送出後,InnoDB存儲引擎會先做一個PREPARE操作,将事務的XID寫入到redo log中

2)寫binlog

3)将該事務的commit資訊寫到redo log中

如果在步驟1和步驟2失敗的情況下,整個事務會復原,如果在步驟3失敗的情況下,MySQL資料庫在重新開機後會先檢查PREPARE的XID事務是否已經送出,若沒有,則在存儲引擎層再進行一次送出操作。這樣就保證了redo與binlog的一緻性,防止丢失事務。

2.3.主庫寫redo log、binlog不實時造成的資料不一緻

上面我們介紹了MySQL的内部XA事務流程,但是這個流程并不是天衣無縫的,redo的ib_logfile與binlog日志如果被設定非實時flush,就有可能出現以下資料不一緻的情況:

1)Redo log的trx_prepare未寫入,但binlog已寫入,則crash recovery後從庫資料比主庫多。

2)Redo log的trx_prepare與commit都寫入了,但binlog未寫入,則crash recovery後從庫資料量比主庫少。

從目前來看,隻能犧牲性能去換取資料的安全性,必須要設定redo log和binlog為實時刷盤,如果對性能要求很高,則考慮使用SSD來替代機械盤。

2.4.從庫寫redo log、binlog不實時造成的資料不一緻

主庫正常,但是從庫出現異常情況當機,如果資料丢失,從庫的SQL線程還會重新應用嗎?這個我們需要先了解SQL線程的機制。

從庫讀取主庫的binlog日志後,需要落地3個檔案:

relay log:即IO Thread讀取過來的主庫binlog,内容格式與主庫的binlog一緻

relay log info:記錄SQL Thread應用的relay log的位置、檔案号等資訊

master info:記錄IO Thread讀取主庫的binlog的位置、檔案号、延遲等資訊

是以如果當這3個檔案如果不及時落地,則system crash後會導緻資料的不一緻。

在MySQL 5.6.2之前,從庫記錄的主庫資訊以及從庫應用binlog的資訊存放在檔案中,即master.info與relay-log.info。在5.6.2版本之後,允許記錄到table中,參數設定如下:

master-info-repository  = TABLE  relay-log-info-repository = TABLE  對應的表分别為mysql.slave_master_info與mysql.slave_relay_log_info,且這兩個表均為innodb引擎表。

master info與relay info還有3個參數控制重新整理:

1)sync_relay_log:預設為10000,即每10000次sync_relay_log事件會重新整理到磁盤。為0則表示不重新整理,交由OS的cache控制。

2)sync_master_info:若master-info-repository為FILE,當設定為0時,則每次sync_master_info事件都會重新整理到磁盤,預設為10000次重新整理到磁盤;若master-info-repository為TABLE,當設定為0時,則表不做任何更新,設定為1,則每次事件會更新表。預設為10000。

3)sync_relay_log_info:若relay_log_info_repository為FILE,當設定為0時,交由OS重新整理磁盤,預設為10000次重新整理到磁盤;若relay_log_info_repository為TABLE,則無論為任何值,每次evnet都會更新表。

如果參數設定如下:

sync_relay_log = 1

sync_master_info = 1  sync_relay_log_info = 1  master-info-repository  = TABLE  relay-log-info-repository = TABLE

将導緻調用fsync()/fdatasync()随着master的事務的增加而增加,且若slave的binlog和redo也實時重新整理的話,會帶來很嚴重的IO性能瓶頸。

2.5.主庫當機後無法及時恢複造成的資料不一緻

當主庫出現故障後,binlog未及時拉到從庫中,或者各個從庫收到的binlog不一緻(多數是由于網絡原因)。且主庫無法在第一時間恢複:

1)如果主庫不切換,則應用隻能讀寫主庫。如果有讀寫分離的場景則會影響應用(讀寫分離場景中從庫會從)。

2)如果将某一從庫提升為新的主庫(如MHA),那麼原主庫未來得及傳到從庫的binlog資料則會丢失,并且還涉及到下面2個問題:

a)各個從庫之間接收到的binlog不一緻,如果強制拉起一個從庫做新主庫,則從庫之間資料會不一緻。

b)原主庫恢複正常後,由于新的主庫日志丢棄了部分原主庫的binlog日志,那麼會多出來故障時期的這部分binlog。

對于上面出現的問題,業内已經有較成熟的方法來解決:

2.5.1確定binlog全部傳到從庫

方案一:使用semisync replication(半同步複制)插件。半同步複制的特點是從庫中有一台送出後,主庫才能送出事務。優點是保證了主、從庫的資料一緻性;缺點是對性能影響很大,依賴網絡,适合tps壓力小的場景。

方案二:雙寫binlog,通過DBDR OS層的檔案系統複制到備機,或者使用共享盤儲存binlog日志。優點和方案一類似,但此方案缺點較明顯:

1)DBDR需要部署自己的服務

2)DBDR腦裂嚴重。在發生災難場景時,往往不能正确切換。

3)需要建立heartbeat機制。保證被監控機的存活。

方案三:架構層面調整,引入消息隊列做異步消息處理。比如保證資料庫寫成功後,再異步隊列的方式寫一份,部分業務可以借助設計和資料流解決。

2.5.2保證資料最小化丢失

上面的方案設計及架構比較複雜,如果能容忍資料的丢失,可以考慮使用MHA。

當master當機後,MHA可以指定一台或者選延遲最低或者binlog pos最新的一台從庫,并将其提升為主庫。

MHA在切換master後,原master可以修複後以新master的slave角色重新加入叢集。進而達到高可用。

3.總結

通過上面的總結分析,MySQL丢資料的場景衆多,主要還是涉及到引擎層資料丢失場景、主從的資料不一緻場景等。