糟了,資料庫崩了,又好像沒蹦
來源:waynblog
前言
2023 年某一天週末,新手程式設計師小明因為領導安排的一個活來到公司加班,小明三下五除二,按照領導要求寫了一個跑批的資料落庫任務在測試環境執行 ,突然間公司停電了,小明大驚,“糟了,MySQL 還在跑任務,會不會因為突然斷電,導致資料庫崩了”。
這時候,傍邊的同事雲淡風清的說了一句,“沒事,小明,MySQL 有一套預寫日誌機制就是應對這種情況的。你的落庫任務啟用了事務沒,啟用了的話,就等來電重新跑一下任務就行了。”
聽了同事的話,小明懸著的心放了下來。“哦哦,我啟用了事務,那我還是等週一來重新跑一遍”。
回家的公交車上,小明默默的開啟百度,搜尋 MySQL 預寫日誌 ,寫下了這篇文章 😂。
什麼是預寫日誌機制?
一般情況下,大部分資料庫都是將表和索引儲存在磁碟檔案中。當新增資料時,資料庫系統會先寫入記憶體,然後將其寫入磁碟上的資料檔案。
那為什麼不直接寫入磁碟嘞?主要是每次新增都直接寫入磁碟效能很低,放在記憶體中,可以批次寫入磁碟以提升效能。
但有一個問題,如果資料在寫入磁碟檔案中途斷電怎麼辦?當來電恢復後,我們重啟資料庫,發現資料不一致,又該如何處理。
所以我們需要一些其他機制來避免斷電引發的資料不一致,其實 MySQL 已經考慮到了這一點,內部已經實現一套 WAL(預寫日誌)機制來避免這一點。
MySQL 設計有健壯的恢復機制,特別是使用 InnoDB 儲存引擎的情況下,它能夠在斷電後重啟而不會崩潰。InnoDB 儲存引擎使用預寫日誌(WAL)機制來確保資料的一致性和原子性。
預寫日誌機制是一種資料庫事務日誌技術,它要求在任何資料庫修改被寫入到永久儲存(也就是磁碟)之前,先將這些修改記錄到日誌中。
這樣當 MySQL 遇到意外的斷電情況時,它會在重啟後利用 Redo log 來恢復已提交但未寫入資料檔案的事務繼續寫入資料檔案,從而保證一致性,再利用 undo log 來撤銷未提交事務的需改,從而保證原子性。
MySQL 中的預寫日誌機制
在 MySQL 中,InnoDB 儲存引擎實現了 WAL 機制。包含 Redo log buffer、Redo log、Undo Log 等,來記錄事務已提交但未寫入資料檔案的資料變更以及事務回滾後的資料還原。
為了給大家講清楚 MySQL 的預寫日誌機制,會涉及到 MySQL 架構中的以下內容,
Buffer Pool(緩衝池)
Buffer Pool (緩衝池)是 InnoDB 儲存引擎中非常重要的記憶體結構,顧名思義,緩衝池就是起到一個快取的作用,因為我們都知道 MySQL 的資料最終是儲存在磁碟中的,如果沒有這個 Buffer Pool 那麼我們每次的資料庫請求都會磁碟中查詢,這樣必然會存在 IO 操作,這肯定是無法接受的。
但是有了 Buffer Pool 就是我們第一次在查詢的時候會將查詢的結果存到 Buffer Pool 中,這樣後面再有請求的時候就會先從緩衝池中去查詢,如果沒有再去磁碟中查詢,然後在放到 Buffer Pool 中。
Redo log buffer(日誌緩衝區)
Redo log buffer 是用作資料變更記錄寫入 Redo log 檔案前的一塊記憶體區域。日誌緩衝區大小由 innodb_log_buffer_size 變數定義,預設大小為 16MB。
日誌緩衝區的內容會定期重新整理到 Redo log 檔案中,大型日誌緩衝區允許大型事務執行,而無需在事務提交之前將 Redo log 資料寫入磁碟。因此如果事務涉及的更新、插入或刪除運算元據量較大時,可以增加日誌緩衝區的大小可以節省磁碟 I/O。
MySQL 提交事務的時候,會將 Redo log buffer 中的資料寫入到 Redo log 檔案中,刷磁碟可以透過 innodb_flush_log_at_trx_commit 引數來設定
值為 0 表示不刷入磁碟 值為 1 表示立即刷入磁碟 值為 2 表示先刷到 os cache
為了提高效能,MySQL 首先將修改操作寫入到日誌緩衝區,之後以 innodb_flush_log_at_trx_commit 引數設定落盤時機,將日誌緩衝區刷入到磁碟的 Redo log 檔案中去。
Redo Log
MySQL Redo Log 是 InnoDB 儲存引擎中的一個重要元件,它是一種磁碟基礎的資料結構,用於在崩潰重啟期間修復由已提交事務但未寫入資料檔案的資料。
在正常操作中,Redo log 記錄了由 SQL 語句執行導致的表資料變更記錄。將 Redo log buffer 中的資料持久化到磁碟中,就是將 Redo log buffer 中的資料寫入到 Redo log 磁碟檔案中。
資料在由 Redo log buffer 寫入 Redo log 時的觸發時機如下,
MySQL 正常關閉時觸發 當 Redo log buffer 中記錄的寫入量大於 Redo log buffer 記憶體空間的一半時,會觸發落盤 InnoDB 的後臺執行緒每隔 1 秒,將 Redo log buffer 持久化到磁碟 每次事務提交時都將快取在 redo log buffer 裡的 redo log 直接持久化到磁碟(這個策略就是由上文提高 innodb_flush_log_at_trx_commit 引數控制)
Redo log 是 WAL 機制的核心,它記錄了事務所做的所有修改。如果資料庫發生故障,可以使用 Redo 日誌來重做事務,從而確保資料的一致性。
Undo Log
Undo Log 記錄瞭如何撤銷一個事務的修改。如果需要回滾事務或在執行事務時還未提交,資料庫就發生了崩潰,這時我們就需要將未提交事務前的資料回滾回去,難道這個操作有我們自己來做嗎?顯然 MySQL 也考慮到了這一點。
MySQL 會使用 Undo log 來撤銷未提交的修改。在運算元據前,MySQL 首先將資料備份到 Undo log,然後進行資料修改。
如果出現錯誤或者使用者執行了 Rollback 語句,系統可以利用 Undo log 中的備份將資料恢復到事務操作前的狀態。
透過 Undo log 撤銷修改,從而確保資料的原子性。
結合 Buffer Pool、Redo log buffer、Redo log、Undo log 後,我們在MySQL 中更新一條資料的流程如下,
準備更新一條 SQL 語句 MySQL(innodb)會先去緩衝池(Buffer Pool)中去查詢這條資料,沒找到就會去磁碟中查詢,如果查詢到就會將這條資料載入到緩衝池(Buffer Pool)中 在載入到 Buffer Pool 的同時,會將這條資料的原始記錄儲存到 undo 日誌檔案中 innodb 會在 Buffer Pool 中執行更新操作 更新後的資料會記錄在 Redo log buffer 中 MySQL 提交事務的時候,會將 Redo log buffer 中的資料寫入到 Redo log 檔案中,刷磁碟可以透過 innodb_flush_log_at_trx_commit 引數來設定 MySQL 重啟的時候會將 Redo log 恢復到緩衝池中
額外知識:檢查點(Checkpoint)
檢查點是什麼?為什麼有了 Redo log、Undo log 還要引入檢查點。
明明藉助 Redo log、Undo log 我們就可以實現 MySQL 的故障恢復了。
雖然資料在寫入 Redo log 檔案後,就代表資料變更已經生效了,但是還未寫入到資料檔案,也就是還沒有完成事務的永續性。
那麼檢查點就是幫助 MySQL 實現事務的永續性。
如果說 Redo log 可以無限地增大,能夠儲存所有資料庫變更的資料,那麼在發生當機時完全可以透過 Redo log 來恢復資料庫系統的資料到當機發生前的情況。
然而現實是我們的物理磁碟檔案大小是有效的。即使達成無限了,如果資料庫執行了很久後發生當機,那麼使用 Redo log 進行恢復的時間也會非常的久。
所以在 Redo log 檔案容量是有限的情況下,還需要定期將 Redo log 寫入資料檔案完成資料的持久化,在這樣的情況下,就引入了 Checkpoint(檢查點)技術。
Checkpoint(檢查點)技術不僅僅是會同步 Redo log 寫入資料檔案,也會同步髒頁資料寫入資料檔案。
檢查點的觸發時機有兩種如下,
Sharp Checkpoint(完全檢查點)
將記憶體中所有髒頁全部寫到磁碟就是完全檢查點,比如資料庫例項關閉時。
Fuzzy Checkpoint(模糊檢查點)
將部分髒頁重新整理到磁碟,就是模糊檢查點,一般就是髒頁達到一定數量時觸發。資料庫例項執行過程產生的檢查基本上就是這種型別的檢查點。
因此其實 Checkpoint 就是指一個觸發點(時間點),當發生 Checkpoint 時,會將髒頁寫回磁碟,以確保資料的永續性和一致性。並且 Redo log、Undo log 檔案也可以重新覆寫,這樣可以保證重啟時不會因為 Redo log、Undo log 檔案太大而導致重啟時間過長。
斷電故障恢復案例
OK,假如我們正在使用 MySQL 新增資料。在提交事務的過程中,突然發生了斷電,那麼這個資料會丟嗎?
我們結合上文MySQL 中更新一條資料的流程,來給大家分析下具體場景,
資料在寫入 Buffer Pool、Redo log buffer 中時,發生斷電
先說結論,會丟。因為資料沒有寫入 Redo log 前,MySQL 是沒辦法保證資料一致性的。但是這沒關係的,因為 MySQL 會認為本次事務是失敗的,在重啟後可以根據 Undo log 檔案將資料恢復到更新前的樣子,並不會有任何的影響。
資料在寫入 Redo log 檔案後,發生斷電
先說結論,不會丟。因為 Redo log buffer 中的資料已經被寫入到 Redo log 了,就算資料庫當機了,在下次重啟的時候 MySQL 也會將 Redo log 檔案內容恢復到 Buffer Pool 中進行重放。
參考資料
%E6%96%87%E4%BB%B6%E5%86%99%E6%BB%A1%E4%BA%86%E6%80%8E%E4%B9%88%E5%8A%9E https://pdai.tech/md/db/sql-mysql/sql-mysql-execute.html
最後說兩句
預寫日誌機制是資料庫管理系統中保證資料安全性的關鍵技術。在 MySQL 中,透過 InnoDB 儲存引擎實現的 WAL 機制,即使在發生斷電等意外情況下,也能夠有效地保護資料不受損壞。這使得 MySQL 成為了一個可靠和健壯的資料庫解決方案,適用於各種需要高資料一致性和可靠性的應用場景。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027826/viewspace-2998592/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 又來勒索,有完沒完-資料庫安全指南資料庫
- Windows 10 1903 又崩了,開始選單罷工Windows
- 雲開發資料庫又增新技能!資料庫
- jive(jdon版)好像沒法修改密碼密碼
- 自建資料庫太麻煩?華為雲資料庫GaussDB既省心又省力資料庫
- 糟了,生產環境資料竟然不一致,人麻了!
- 部落格園又崩了,這個鍋要不要阿里雲背?阿里
- 分散式資料庫怎樣才能叫好又賣座分散式資料庫
- com.jdon.model.query.cache.BlockCacheKeyFactory 好像沒有BloC
- 沒有審計系統就沒有資料庫安全資料庫
- 看似好像沒用的小知識點 vol.1
- 鄭州市健康碼崩了?大資料局回應大資料
- 資料探勘概述(又) (轉)
- 資料庫沒有完美的儲存引擎資料庫儲存引擎
- SqlServer資料庫沒有有效所有者SQLServer資料庫
- 鍵值資料庫與關聯式資料庫有沒有融合的可能?資料庫
- 虹科分享 | B站崩了怎麼辦?Redis企業版資料庫多雲戰略分析Redis資料庫
- 幽默:沒有資料庫的架構來了資料庫架構
- petstore 的資料庫指令碼怎麼沒找到???資料庫指令碼
- 【ASK_ORACLE】你知道怎麼又快同時又幹淨地關閉Oracle資料庫嗎?Oracle資料庫
- onethink構思不錯,好像沒有好的例項教程
- MySQL查詢資料庫中沒有主鍵的表MySql資料庫
- 資料庫容災-沒有最好,只有最適合資料庫
- 騰訊雲也崩了。。
- 資料庫大戰,AWS又將目標瞄準了微軟SQL Server資料庫微軟SQLServer
- EM 12c for cloud : 自助RAC資料庫成功後,資料庫沒有temp資料檔案問題-bug 17429475Cloud資料庫
- 【國產資料庫名錄一覽】竟有這麼多國產資料庫產品?很多沒聽過資料庫
- 有沒有完全自主的國產化資料庫技術資料庫
- 資料庫中沒有外來鍵的9個理由資料庫
- 翻譯:JBoss Seam 2.0蹦達出來了
- 蘋果手錶2開啟新技能 但好像並沒有什麼用!蘋果
- 資料湖是誰?那資料倉儲又算什麼?
- 通過awr 查詢資料庫最近有沒有重啟!資料庫
- 【HTML5初探之本地儲存】如果沒有資料庫。。。HTML資料庫
- oracle關閉資料庫時沒反應的處理案例Oracle資料庫
- 請教資料庫高手(我們這沒有SQL版阿)資料庫SQL
- 資料庫連線沒有釋放造成的奇怪問題資料庫
- 有沒有用過goquery的,我想用代理去爬蟲,goquery支援嗎?找了一下好像沒找到Go爬蟲