一、重要的日志模塊:redo log
1、通過酒店掌櫃記賬思路刨析redo log工作原理

2、InnoDB 的 redo log 是固定大小的

只要賒賬記錄在了粉板上或寫了賬本上,之后即使掌櫃忘記了,
比如停業幾天,回復生意后依然可以通過賬本和粉板上的數據明確賒賬賬目
有了redo log,InnoDB就可以保證即使數據庫發生異常重啟,之前提交的記錄都不會丟失,這個能力成為crash-safe二、重要的日志模塊:binlog
二、重要的日志模塊binlog
1、redo和三點區別binlog
redo是物理的,binlog是邏輯的;現在由於redo是屬於InnoDB引擎,所以必須要有binlog,因為你可以使用別的引擎

2、binlog幾大模式

一般采用row,因為遇到時間,從庫可能會出現不一致的情況,但是row更新前后都有,會導致日志變大
最后2個參數,保證事務成功,日志必須落盤,這樣,數據庫crash后,就不會丟失某個事務的數據了
3、企業場景如何選擇binglog:
1、互聯網公司,使用MySQL的功能相對少(存儲過程、觸發器、函數)
選擇默認的語句模式,Statement Level(默認)
2、公司如果用到使用MySQL的特殊功能(存儲過程、觸發器、函數)
則選擇Mixed模式
3、公司如果用到使用MySQL的特殊功能(存儲過程、觸發器、函數)又希望數據最大化一直,此時最好選擇Row level模式
4、行模式和語句模式的區別

5、 ROW模式下binlog日志記錄效果
[root@db01]# mysqlbinlog --base64-output="decode-rows" --verbose mysql-bin.000248 /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #160628 11:06:52 server id 1 end_log_pos 107 Start: binlog v 4, server v 5.5.49-log created 160628 11:06:52 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; # at 107 #160628 11:07:09 server id 1 end_log_pos 177 Query thread_id=1 exec_time=0 error_code=0 SET TIMESTAMP=1467083229/*!*/; SET @@session.pseudo_thread_id=1/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=0/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;/*!\C utf8 *//*!*/; SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; BEGIN /*!*/; # at 177 # at 223 #160628 11:07:09 server id 1 end_log_pos 223 Table_map: `oldboy`.`sc` mapped to number 33 #160628 11:07:09 server id 1 end_log_pos 785 Update_rows: table id 33 flags: STMT_END_F ### UPDATE `oldboy`.`sc` ### WHERE ### @1=1 ### @2=1001
三、update 語句的執行流程圖
1、update語句的執行流程圖
圖中綠色框表示是在內粗執行,紅色框表示是在執行器中執行

2、 流程說明
1.首先客戶端通過tcp/ip發送一條sql語句到server層的SQL interface
2.SQL interface接到該請求后,先對該條語句進行解析,驗證權限是否匹配
3.驗證通過以后,分析器會對該語句分析,是否語法有錯誤等
4.接下來是優化器器生成相應的執行計划,選擇最優的執行計划
5.之后會是執行器根據執行計划執行這條語句。在這一步會去open table,如果該table上有MDL,則等待。如果沒有,則加在該表上加短暫的MDL(S),
(如果opend_table太大,表明open_table_cache太小。需要不停的去打開frm文件)
6.進入到引擎層,首先會去innodb_buffer_pool里的data dictionary(元數據信息)得到表信息
7.通過元數據信息,去lock info里查出是否會有相關的鎖信息,並把這條update語句需要的鎖信息寫入到lock info里(鎖這里還有待補充)
8.然后涉及到的老數據通過快照的方式存儲到innodb_buffer_pool里的undo page里,並且記錄undo log修改的redo
(如果data page里有就直接載入到undo page里,如果沒有,則需要去磁盤里取出相應page的數據,載入到undo page里)
9.在innodb_buffer_pool的data page做update操作。並把操作的物理數據頁修改記錄到redo log buffer里
由於update這個事務會涉及到多個頁面的修改,所以redo log buffer里會記錄多條頁面的修改信息。
因為group commit的原因,這次事務所產生的redo log buffer可能會跟隨其它事務一同flush並且sync到磁盤上
10.同時修改的信息,會按照event的格式,記錄到binlog_cache中。(這里注意binlog_cache_size是transaction級別的,不是session級別的參數,
一旦commit之后,dump線程會從binlog_cache里把event主動發送給slave的I/O線程)
11.之后把這條sql,需要在二級索引上做的修改,寫入到change buffer page,等到下次有其他sql需要讀取該二級索引時,再去與二級索引做merge
(隨機I/O變為順序I/O,但是由於現在的磁盤都是SSD,所以對於尋址來說,隨機I/O和順序I/O差距不大)
12.此時update語句已經完成,需要commit或者rollback。這里討論commit的情況,並且雙1
13.commit操作,由於存儲引擎層與server層之間采用的是內部XA(保證兩個事務的一致性,這里主要保證redo log和binlog的原子性),
所以提交分為prepare階段與commit階段
14.prepare階段,將事務的xid寫入,將binlog_cache里的進行flush以及sync操作(大事務的話這步非常耗時)
15.commit階段,由於之前該事務產生的redo log已經sync到磁盤了。所以這步只是在redo log里標記commit
16.當binlog和redo log都已經落盤以后,如果觸發了刷新臟頁的操作,先把該臟頁復制到doublewrite buffer里,把doublewrite buffer里的刷新到共享表空間,然后才是通過page cleaner線程把臟頁寫入到磁盤中
其實在實現上5是調用了6的過程了的,所以是一回事。MySQL server 層和InnoDB層都保存了表結構,所以有書上描述時會拆開說。
四、兩階段提交
1、保證數據庫的一致性:
必須要保證2份日志一致,使用的2階段式提交;其實感覺像事務,不是成功就是失敗,不能讓中間環節出現,也就是一個成功,一個失敗
如果有一天mysql只有InnoDB引擎了,有redo來實現復制,那么感覺oracle的DG就誕生了,物理的速度也將遠超邏輯的,畢竟只記錄了改動向量
2、binlog能不能去掉?
老師,今天MYSQL第二講中提到binlog和redo log, 我感覺binlog很多余,按理是不是只要redo log就夠了?[費解]
一個原因是,redolog只有InnoDB有,別的引擎沒有。 另一個原因是,redolog是循環寫的,不持久保存,binlog的“歸檔”這個功能,redolog是不具備的。
3、運維同學的實戰疑惑
老師您好,我之前是做運維的,通過binlog恢復誤操作的數據,但是實際上,我們會后知后覺,誤刪除一段時間了,才發現誤刪除,此時,我把之前誤刪除的binlog導入,再把誤刪除之后binlog導入,會出現問題,比如主鍵沖突,而且binlog導數據,不同模式下時間也有不同,但是一般都是row模式,時間還是很久,有沒什么方式,時間短且數據一致性強的方式
其實恢復數據只能恢復到誤刪之前到一刻, 誤刪之后的,不能只靠binlog來做,因為業務邏輯可能因為誤刪操作的行為,插入了邏輯錯誤的語句, 所以之后的,跟業務一起,從業務快速補數據的。只靠binlog補出來的往往不完整
4、怎樣讓數據庫恢復到半個月內任意一秒的狀態?
1 prepare階段
2 寫binlog
3 commit
當在2之前崩潰時
重啟恢復:后發現沒有commit,回滾。備份恢復:沒有binlog 。一致
當在3之前崩潰
重啟恢復:雖沒有commit,但滿足prepare和binlog完整,所以重啟后會自動commit。備份:有binlog. 一致
五、思考題(同學們的經典留言)
1、Jason同學
備份時間周期的長短,感覺有2個方便
首先,是恢復數據丟失的時間,既然需要恢復,肯定是數據丟失了。如果一天一備份的話,只要找到這天的全備,加入這天某段時間的binlog來恢復,如果一周一備份,假設是周一,而你要恢復的數據是周日某個時間點,那就,需要全備+周一到周日某個時間點的全部binlog用來恢復,時間相比前者需要增加很多;看業務能忍受的程度
其次,是數據庫丟失,如果一周一備份的話,需要確保整個一周的binlog都完好無損,否則將無法恢復;而一天一備,只要保證這天的binlog都完好無損;當然這個可以通過校驗,或者冗余等技術來實現,相比之下,上面那點更重要
2、justd同學的形象比喻
1、一個完整的交易過程:
1、賬本記上 賣一瓶可樂(redo log為 prepare狀態), 2、然后收錢放入錢箱(bin log記錄) 3、然后回過頭在賬本上打個勾(redo log置為commit)表示一筆交易結束。
2、如果收錢時交易被打斷
1、回過頭來整理此次交易,發現只有記賬沒有收錢,則交易失敗,刪掉賬本上的記錄(回滾); 2、如果收了錢后被終止,然后回過頭發現賬本有記錄(prepare)而且錢箱有本次收入(bin log),則繼續完善賬本(commit),本次交易有效。
