提出問題
- 服務器數據庫異常重啟了會造成什么樣的影響?
- 不小心刪除了數據庫怎么辦,或者不小心刪除了數據庫表中數據怎么辦?
- 一條更新語句在數據庫系統內部執行時與數據庫日志系統有什么聯系?
- 數據庫備份,是每天一備比較好,還是每周一備比較好?
接下來在講解日志系統的同時,回答上面的幾個問題。
日志系統詳解:
redo日志(重做日志)
redo是引擎層的日志,而且是InnoDB特有的。InnoDB的redo log是有固定大小的,比如可以配置為 一組4個文件(logfile-1,logfile-2,logfile-3,logfile-4),每個文件的大小是1GB,那么它總共可以記錄4GB的操作。一個環狀循環結構,從頭開始寫,寫到末尾又回到開始循環寫。
- redo中的環狀結構
write pos是當前記錄的位置,一邊寫一邊后移,環狀結構,寫到3號文件末尾就會回到0號文件開頭。checkpoint是當前擦除的位置,也是往后推移并且循環的。注意擦除記錄前要把記錄更新到數據文件(這里可以聯想 粉板 老板正式記賬本的例子)
- redo日志作用(回答提出問題1)
- 在MySQL中,如果每一次的更新操作都寫進磁盤,然后磁盤也找到對應的那條記錄,然后再更新,整個過程io成本,查找成本都很高,為了解決這個問題,提升效率,就會用到redo日志,MySQL經常說的的WAL技術,WAL的全稱是write-Ahead-Logging,它的關鍵點就是先寫日志,再寫磁盤。具體說,當有一條記錄需要更新的時候,InoDB引擎會先記錄到redo log,并更新內存,這時候更新就算完成了。同時InnoDb引擎會在適當的時候,將這個操作記錄更新到磁盤里面,而這個更新往往是在系統比較空閑的時候做。
- 正是因為有了redo log ,InnoDB就可以保證即使數據庫發生異常重啟,之前提交的記錄多不會消失,這個能力叫crash-safe。只要數據庫的物理記錄還在redo log中,就是服務器數據庫出現問題重啟,數據庫恢復后,數據記錄仍然可以恢復。
binlog日志(歸檔日志)
Mysql基礎架構整體分為兩部分:Server層和引擎層,引擎層主要負責存儲相關的事宜。上面說到在引擎層有自己的日志,而且只在InnoDB引擎中才有。Server層也有自己的日志,稱為binlog(歸檔日志)。它是采用追寫入日志的方式。追加寫是指binlog文件寫到一定大小后會切換到下一個,并不會覆蓋以前的日志。
- binlog日志作用(回答提出問題2)
只依靠redo日志的crash-safe特性在應對數據庫誤刪,表數據誤刪等操作時候,有些時候redo日志是無力的,但是binlog日志解決這些問題,因為binlog會記錄所有的邏輯操作,并且采用“追加寫”的形式。
舉個例子如果公司老大發現某天下午有一個誤刪表數據操作,要求找回數據,應該怎么做?(注:這里要考慮是在剛備份之后誤刪除,還是備份之前誤刪除,下面的例子是在備份之前刪除的,找之前刪除的數據)
- 首先,找到最近的一次全量備份,這要看你們公司的數據庫是多久備份一次(有的公司是一天,有的公司是一周,而且會定期刪除,很多公司只保留最近一個月的數據庫備份),拿到備份數據后,把這個備份數據恢復到臨時表
- 然后從備份的時間點開始,將備份的binlog依次取出來,重放到誤刪表之前的那個時刻
- 這時候臨時庫跟誤刪之前的線上庫一樣了,然后把表數據從臨時數據取出來,按需恢復到線上庫去。
redo日志與binlog日志對比
redo日志與binlog日志有哪些不同? 其實上面好多都提到過,再次總結一遍,加深印象。
- redo log是InnoDB引擎特有的;binlog是MySQL的Server層實現的,所有的引擎都可以使用。
- redo log是物理日志,記錄的是某個數據頁上做了什么修改;binlog是邏輯日志,記錄的是這個語句的原始邏輯,比如“給ID=2這一行的c字段加一”
- redo log是環狀結構,循環寫,空間固定會用完,用完后需要擦除;binlog是可以追加寫入的?!白芳訉憽笔侵籦elog文件寫到一定大小后會切換到下一個,并不會覆蓋以前的日志。
更新語句執行流程(與日志關系)
數據庫語句:
mysql> update Student set c=c+1 where ID=2;
通過分析這一條更新語句,畫出流程圖,
問題3也就得到解決。
紅色是執行器完成的部分,黑色時候引擎完成的部分。注意流程圖的最后三步,這是更新語句和日志關系密切的地方,將redo日志拆成了兩個步驟:prepare和commit,它倆的中間是執行器寫入binlog。(注:如果不這么做,假如一個日志提交成功的時候,另一個日志提交之前發生了數據庫發生了崩潰,但是crash-safe恢復或者誤刪庫恢復的時候可能造成二者數據不統一出現問題。)
開發過程中如何為mysql設置這兩種保存日志的配置
-
redo log
innodb_flush_log_at_trx_commit 這個參數設置成 1 的時候,表示每次事務的 redo log 都直接持久化到磁盤。這個參數我建議你設置成 1,這樣可以保證 MySQL 異常重啟之后數據不丟失。
-
binlog
sync_binlog 這個參數設置成 1 的時候,表示每次事務的 binlog 都持久化到磁盤。這個參數我也建議你設置成 1,這樣可以保證 MySQL 誤刪除操作(刪除表數據,刪除庫數據) 通過binlog 仍可恢復。
關于日志系統的一些誤區和疑問
-
大家會不會想有了redo日志就可以了,為什么還要出現binlog日志呢?
解答:
- redo日志是只要InnoDB引擎才提供的一個內容。
- redo日志是環狀結構循環寫入,并且到了配置的固定大小后會被擦除,誤刪除數據庫或表數據的時候,備份可能會出現無法全部還原。
這里有一個問題:如果在擦除和記賬重合那一刻,數據庫異常重啟了,新的數據庫操作會怎么記錄,是擦除一部分,記錄上,會丟失,還是等待重啟后往上添加數據?
-
關于數據庫備份,是一天一備比較好,還是一周一備份比較好,一般備份文件保留多久?提出問題4解決
解答:對于數據庫備份周期這個問題,需要考慮以下指標:數據存量、增量、備份成本、恢復效率。
- 如果數據存量大到一天都沒法備份完成,只能一周一次甚至更長時間
- 業務數據的增量,如果增量非常大,如果一周備份一次,可能會出現增量備份失敗問題,而且恢復時長和成功率也比較困難,則可以考慮一日一備。
- 業務比較重要,且對恢復時間的忍耐程度低,之前多次發生過數據回滾的需求,數據增量還不小,可以考慮一天一備。相反業務實際不重要,出問題可以容忍一定的不可用,增量還不多,可以考慮一周一備份。
總的來說就是和項目,需求,場景有很多關系。
-
寫入redo日志也是io操作,數據更新直接寫入磁盤也是io操作,為什么說寫入redo日志效率高節省io成本呢?
解答:redo日志的寫入是順序寫入的,不用去“找位置”,而直接更新數據到磁盤的話,需要到磁盤中找到位置再寫入,肯定前者的效率高。
總結
以上內容是關于數據庫日志系統的講解,同時解決了我開篇提出的幾個數據庫日志相關的問題,希望能幫助大家更好的了解學習數據庫,如果有問題可以隨時關注公眾號聯系,互相學習哦。
<center>覺得本文對你有幫助?請分享給更多人<center>
歡迎大家關注我的公眾號——程序員成長指北。請自行微信搜索——“程序員成長指北”