mysql中怎么防止数据丢失
前言
放假期間,突然接到老板電話,說系統出現了數據丟失問題,猶如晴天霹靂,內心慌得一批已經準備卷鋪蓋回家。
今天主要給大家分享mysql數據庫出現數據丟失的幾個場景以及解決數據丟失問題的相應手段,讓大家以后心里有譜,放假不慌。
一、事務級數據丟失
說明:
1、批量操作數據時,由于沒有添加事務控制,出現事務回滾時,出現部分數據操作成功,部分數據操作失敗的問題。
2、事務提交成功到數據還沒有刷寫到磁盤,出現數據庫宕機導致的數據丟失
范圍: 事務級
嚴重級別: 低
處理手段:
- 添加事務控制
- 開啟redo log、undo log
- 采用強一致日志刷寫策略
1、開啟事務控制
示例:批量保存用戶信息
@Override@Transactional(rollbackFor = {Exception.class})public boolean saveBatch(Collection<User> entityList, int batchSize) {try {int size = entityList.size();int idxLimit = Math.min(batchSize, size);int i = 1;//保存單批提交的數據集合List<User> oneBatchList = new ArrayList<>();for(Iterator<User> var7 = entityList.iterator(); var7.hasNext(); ++i) {User element = var7.next();oneBatchList.add(element);if (i == idxLimit) {userMapper.insertBatchSomeColumn(oneBatchList);//每次提交后需要清空集合數據oneBatchList.clear();idxLimit = Math.min(idxLimit + batchSize, size);}}}catch (Exception e){log.error("saveBatch fail",e);return false;}return true;}2、開啟redo log、undo log
mysql中只有InnoDB引擎支持事務,而事務機制的實現離不開redo log和undo log。
默認情況下都是開啟的,不需要主動調整。但如果出現事務級別的數據丟失,就需要檢查相關配置。
- redo log:重做日志
- undo log:回滾日志
Redo Log(重做日志)是MySQL中非常重要的日志模塊。
官方解釋:重做日志是一種基于磁盤的數據結構,用于在崩潰恢復期間糾正不完整事務寫入的數據。
在正常操作期間,重做日志對由SQL語句或低級API調用產生的更改表數據的請求進行編碼。在初始化期間和接受連接之前,會自動重播在意外關閉之前未完成更新數據文件的修改).
MySQL里經常說到的WAL技術(WAL的全稱是Write-Ahead Logging),它的關鍵點就是日志先行(也稱為寫前日志,實際寫數據之前,先把修改的數據記錄到日志文之間中。即先寫日志,再寫磁盤),其實很多數據庫軟件設計的理念都是日志先行。(但是Redis的AOF(Append Only File)日志正好相反,它是寫后日志,“寫后”的意思是Redis的先執行命令,把數據寫入內存,然后才記錄日志),MySQL中日志先行的這個“日志”就是Redo Log。
Redo Log是InnoDB引擎特有的日志,而MySQL Server層也有自己的日志,稱為binlog(不在我們本文的討論范圍,下一章我們就會見到它了,拭目以待吧)。正是因為有了Redo Log,才保證了InnoDB存儲引擎的Crash-safe能力。
Redo Log是物理日志,記錄的是“在某個數據頁上做了什么修改(做了什么改動)”。一句話概括一下,Redo Log是為了保證已提交事務的ACID特性,同時能夠提高數據庫性能的技術。
3、Redo log刷寫策略
我們都知道,數據只有刷寫到磁盤中才是最安全的,redo log從內存到刷寫到磁盤經歷了三層結構。
Redo Log的三層結構:
簡單來說一下Redo Log的三層結構:
- 粉色部分:是InnoDB一項很重要的內存結構(In-Memory Structure),即我們的Log Buffer(日志緩沖區),這一層,是MySQL應用程序用戶態控制。
- 黃色部分:操作系統文件系統的緩沖區(FS Page Cache),這一層,是操作系統OS內核態控制。
- 綠色部分:就是落盤的物理日志文件。
Redo Log刷寫時機:
Redo log目前有三種刷寫策略,即對應可設置的值可以是0、1或2。
- 策略一:最佳性能(innodb_flush_log_at_trx_commit=0)
處理過程:每隔一秒,才將Log Buffer中的數據批量write入FS Page Cache,同時MySQL主動fsync。
缺點:這種策略,如果數據庫奔潰,有一秒的數據丟失。 - 策略二:強一致(innodb_flush_log_at_trx_commit=1)
處理過程:每次事務提交,都將Log Buffer中的數據write入FS Page Cache,同時MySQL主動fsync。這種策略,是InnoDB的默認配置,為的是保證事務ACID特性。
缺點:這種策略,性能較其余兩種策略較差。 - 策略三:折衷(innodb_flush_log_at_trx_commit=2)
處理過程:每次事務提交,都將Log Buffer中的數據write入FS Page Cache;每隔一秒,MySQL主動將FS Page Cache中的數據批量fsync。
缺點:這種策略,如果操作系統奔潰,最多有一秒的數據丟失。(因為OS也會fsync,MySQL主動fsync的周期是一秒,所以最多丟一秒數據。磁盤IO次數不確定,因為操作系統的fsync頻率并不是MySQL能控制的)
綜上,為了防止事務級數據丟失,必須設置redo log的刷寫級別為強一致(innodb_flush_log_at_trx_commit=1)
二、page級數據丟失
說明: 由于mysql數據頁page損壞出現的數據丟失
范圍: page級
嚴重級別: 中
處理手段:
- 開啟Doublewrite Buffer,默認開啟
Linux文件系統頁(OS Page)的大小是4KB,MySQL的頁(Page)大小默認是16KB,
所以MySQL將Buffer Pool中一頁數據刷入磁盤,要寫4個文件系統里的頁(也可以說成一個MySQL數據頁映射4個系統頁)。
如上圖所示,MySQL里Page 1的頁,物理上對應磁盤的Page 1、Page 2、Page 3、Page 4四個頁。
這個操作并非原子,如果執行到一半斷電,會不會出現問題呢?
答案:會,這就是所謂的“頁數據損壞”。
MySQL內Page 1的頁準備刷入磁盤,才刷了3個文件系統里的頁,掉電了,則會出現:重啟后,MySQL內Page 1的頁,物理上對應磁盤上的Page 1、Page 2、Page 3三個頁,數據完整性被破壞。(Redo Log無法修復這類“頁數據損壞”的異常,因為Redo Log修復的前提是“頁數據正確”并且Redo日志正常)
針對上面出現的情況,如何解決這類“頁數據損壞”的問題呢?
很容易想到的方法是,能有一個“副本”,對原來的頁進行還原,這個存儲“副本”的地方,就是Doublewrite Buffer。Doublewrite Buffer,它與傳統的“Buffer”又不同,它分為內存和磁盤的兩層架構。(傳統的“Buffer”,大部分是內存存儲;而DWB里的數據,是需要落地的)
Doublewrite Buffer工作流程:
如上圖所示,當有頁數據要刷盤時:
- 第1步:頁數據先memcopy到DWB的內存里;
- 第2步:DWB的內存里的數據頁,會先刷到DWB的磁盤上;
- 第3步:DWB的內存里的數據頁,再刷到數據磁盤存儲.ibd文件上;
備注:DWB內存結構由128個頁(Page)構成,所以容量只有:16KB × 128 = 2MB。
DWB為什么能解決“頁數據損壞”問題呢?
假設步驟2掉電,磁盤里依然是Page 1、Page 2、Page 3、Page 4的完整數據。只要有頁數據完整,就能通過Redo Log還原數據;假如步驟3掉電,DWB磁盤結構里存儲著完整的數據。所以,一定不會出現“頁數據損壞”問題。同時寫了DWB磁盤和Data File,總有一個地方的數據是OK的。
是否開啟DoubleWrite
SHOW VARIABLES LIKE 'innodb_doublewrite';三、磁盤級數據丟失
說明: 磁盤損壞導致的數據丟失
范圍: 磁盤級
嚴重級別: 嚴重
處理手段:
- 磁盤矩陣
- 數據庫集群
- 冷熱備份
不要以為數據正確完整的寫到磁盤上就萬事大吉,在程序整體架構的考慮中,除了軟件層面的問題,必須還要考慮硬件層面的風險。
比如,由于Mysql存儲數據的磁盤由于故障損壞了,造成了整個系統的數據丟失,這樣的情況將使災難性的。那么我們該如何應對磁盤級的數據丟失風險呢?其核心就是就好數據備份。
磁盤矩陣
核心是利用多塊磁盤的冗余存儲,保障即是一塊磁盤損壞也不會出現數據丟失。
RAID1 是磁盤陣列中單位成本最高的一種方式。因為它的原理是在往磁盤寫數據的時候,將同一份數據無差別的寫兩份到磁盤,分別寫到工作磁盤和鏡像磁盤,那么它的實際空間使用率只有50%了,兩塊磁盤當做一塊用,這是一種比較昂貴的方案。
優點:是簡單,一般做硬件運維的同事都能操作。
缺點:成本較高,備份數據的精讀較粗,一般是整個服務器級別,往往是財大氣粗的政府機關和銀行在使用。另外不能做到遠程宰備,如果整機房都出了問題,往往還是會出現數據丟失。
數據庫集群備份Replication
通過搭建mysql數據庫集群,讓集群中每臺服務器保存完整的數據庫信息,這樣即使一臺服務器上的數據出現了丟失,也能從備份的數據庫中找回。
而且mysql的主備數據庫可以實現無感知的切換,宅難恢復的速度更快。
而且通過主備數據庫,也可以方便實現數據庫的讀寫分離,緩解單臺數據庫上的讀寫壓力。
是目前最主流的數據庫災備方式。
優點:程序級別的數據備份,更節省成本,能較方便的實現遠程備份,宅難恢復更快。
缺點:如果是程序勿操作導致的數據丟失,從庫也會執行相同操作,造成數據無法找回。
冷熱備份
MySQL備份功能在實際應用中的重要程度不需要多說,在誤刪重要數據后或者數據庫被攻擊后,備份數據的作用就突顯出來了。
MySQL備份方式從不同的角度分析有不同的分類。 從運行狀態分析,有冷備份和熱備份之分。冷備份一般是在數據庫關閉或者暫時不對外提供服務時,選擇某一時間節點對完整數據庫進行快照備份。熱備份一般是在數據庫運行的狀態下,直接對數據進行備份,不影響MySQL對外提供服務。這里主要講下這兩種方式的實現。
直接通過MySQL自帶的mysqldump工具進行備份
-- 數據備份 mysqldump -uroot -proot test > /data/backup/test.sql -- 數據恢復 mysql -f -uroot -proot test < /data/backup/test.sql一般將備份的數據文件存放在其他服務器上。
總結
本文主要對mysql數據庫數據丟失的幾種常見場景進行了介紹。作為程序開發者可能只需要注意程序開發中過程中事務的使用規范,但是如果作為項目負責人、架構師等視角來看,必須把數據庫運維的問題也考慮在內,做到軟硬件風險全盤考慮,防止出現重大事故。
- 事務級數據丟失:添加事務控制,開啟Redo log并采用強一致(innodb_flush_log_at_trx_commit=1)刷寫機制。
- 數據頁損壞級別的數據丟失:數據雙寫機制double wirte
- 如何防止磁盤級別的數據丟失:磁盤矩陣,數據庫集群,數據庫冷熱備份。
MySQL各種“Buffer”之Doublewrite Buffer
MySQL各種“Buffer”之Log Buffer
MySQL的冷熱備份
總結
以上是生活随笔為你收集整理的mysql中怎么防止数据丢失的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度云离线下载含有违规内容检测方法分析
- 下一篇: 如何提升原创文章排名与百度冰桶算法