MySQL——innodb日誌管理
innodb日誌管理機制:
1、innodb存儲引擎是支持事務ACID特性的,這個理論基本就是一個關系型數據庫相關的數據恢復原形設計,包括日誌、回滾、redo、並發控制、buffer pool等管理方面,內容非常全面;
2、innodb的buffer pool主要用來存儲訪問過的數據頁面,他就是一塊連續的內存,通過一定的算法可以使這塊內存得到有效的管理,它是數據庫系統中擁有最大塊內存的系統模塊。
innodb存儲引擎中數據的訪問是按照頁(也可以叫塊,默認為16KB)的方式從數據庫文件讀取到buffer pool中的,然後在內存中用同樣大小的內存空間來做一個映射;未來提高數據訪問效率,數據庫系統預先就分配了很多這樣的空間,用來與文件中的數據進行交換;buffer pool的大小可以在配置文件中配置,有參數innodb_buffer_pool_size的大小來決定,默認大小為128MB。在MySQL5.7.4以前,一旦MySQL啟動這個值便不能再做修改,如果要修改只能退出MySQL進程,然後修改對應的配置文件來設置新的buffer pool大小,重啟才能生效。
註意:在MySQL5.7.5之後,可以在MySQL進程運行的情況下,動態調整innodb_buffer_pool_size,需要強調的是,如果buffer pool的大小超過了1GB,應該通過調整innodb_buffer_pool_instances=N,把它分成若幹個instance的做法,來提示MySQL處理請求的並發能力,因為buffer pool是通過鏈表的方式來管理頁面的,同時為了保護頁面,需要在存取的時候對鏈表加鎖,在多線程的情況下,並發去讀寫buffer pool裏面緩存的頁面需要鎖的競爭和等待。所以修改為多個instance,每個instance各自管理自己的內存和鏈表,可以提升效率。
3、buffer pool實現原理:
buffer pool可以有多個實例,可以通過配置文件中的參數innodb_buffer_pool_instance來設置,默認值為1,實現多個實例的buffer pool主要是為了提高數據頁訪問時的並發度。每個實例的空間大小都是相同的,也就是說系統會將整個配置的buffer pool大小按實例個數平分,然後每個實例各自進行初始化操作;
--註意:在運維過程中,看到狀態參數innodb_buffer_pool_bytes_data總是比innodb_buffer_pool_size小,就是因為控制頭信息占用了部分空間。實際的分配方式是,buffer pool頁面從整個實例池中從後向前分配,每次分配一個頁面,而控制結構使從前向後分配,每次分配一個buf_block_t結構的大小,知道相遇為止,這樣就將一個實例初始化好了。
第一、redo log日誌文件管理:
redo log是用來做數據庫crash recovery的,這是數據庫保障數據安全的重要功能之一。在數據庫操作中,它保存了對innodb表中數據的修改記錄,所以也叫日誌文件。在innodb存儲引擎中,一般默認包括2個日誌文件,新建數據庫之後會有名為ib_logfile0 和ib_logfile1的兩個文件,如果在啟動數據庫時,這兩個文件不存在,則innodb會根據配置參數或默認值,重新創建日誌文件;
1.1、LSN 全名叫:log sequence number:
在innodb內部的日誌管理中,一個很重要的概念是LSN,全名叫log sequence number,它用來精確記錄日誌位置信息,且是連續增長的。在innodb中,大小為8個字節值,它的增長量是根據一個MTR寫入的日誌量來計算的,寫多少日誌,LSN就增長多少。(LSN是一個完全邏輯的概念,每提交一個物理事務,LSN就加1)
1.2、在innodb中,通過日誌組來管理日誌文件,是一個邏輯定義,包含若幹個日誌文件,一個組中的日誌文件大小相等,大小通過參數來設置,現在innodb只持有一個日誌組。(在MySQL5.5以前日誌組最大4G;MySQL5.6.3以後可以設置的更大到512G)
1.3、redo日誌的寫入,都是字節連續的,雖然看上去是多個日誌文件,但理解的時候,完全可以把它想象成一個文件。(日誌組中的每個日誌文件,都有自己的格式,內部也是按照大小相等的頁面切割,每個頁面大小是512字節)
---註意:如果每次寫入是磁盤塊大小的倍數,效率才是最高的,並且日誌將邏輯事務對數據庫的分散隨機寫入轉化成了順序的512字節整數倍數據的寫入,這樣就大大提高了數據庫的效率。
1.4、redo日誌文件的格式:
每個日誌文件,都有文件頭(普通頁面中,都會有12個字節用來存儲頁面頭信息,這些信息主要用於管理這個頁面本身的數據存儲方式;---註意只有2KB是日誌頭,後面是一個個連續的,用來存儲MTR產生的日誌頁面)
1.5、MTRinnodb物理事務:
它是innodb存儲引擎中一個很重要的用來保證物理頁面寫入操作完整性及持久性的機制。之所以被稱為MTR,是因為它的意義相當於一個mini-transaction,用MTR來表示,這裏吧它稱作“物理事務”,這樣叫是相對邏輯事務而言的。
物理事務既然被稱為事務,那它同樣有事務的開始和提交,物理事務的開始其實就是對物理事務結構體mtr_struct的初始化,物理事務的提交主要是將所有這個物理事務產生的日誌寫入到innodb日誌系統的日誌緩沖區中,然後等待srv_master_thread線程定時將日誌系統的日誌緩沖區的日誌數據刷到日誌文件中;
---註意:日誌緩沖區的存儲只是一個暫時的中間狀態,日誌緩沖區的大小可以通過參數innodb_log_buffer_size來設置,一般都比較小,存儲不了多少日誌。
--日誌是在邏輯事務對數據庫做DML操作時,其所包含的物理事務MTR所記錄的,針對所有涉及的buffer pool頁面的修改記錄;
1.6、日誌提高性能的關鍵原因:
①:因為日誌是用來記錄buffer pool中page的修改記錄的,所以把page的寫入轉化為對日誌的寫入,那此時page就不需要每次都刷盤,寫page頁面只需要在內存中寫入即可,性能會非常好;
②:通常,一個頁面是16KB,如果不寫入職,每次寫入的單位還是16KB,即使修改很少的數據,也是如此,這樣會導致無效IO非常嚴重。
1.7、redo日誌大小設置的問題:
①:如果設置的非常大,固然性能可能會很好,但是如果數據庫出現異常停機,此時可能有很多日誌都沒有刷盤,也就是log flushed up to 與 last checkpointat 兩個值之間相差太多,恢復需要比較長的時間。(redo日誌的恢復是順序的,都是根據頁面號的大小排序恢復的;)
②:日誌容量大小的設置,最好與buffer pool的總大小匹配。如果日誌容量太小,buffer pool太大,這就會導致buffer pool頻繁做檢查點,大的buffer pool不能被好好利用,如果日誌容量過大,而buffer pool很小,此時buffer page經常會被淘汰出去,增加IO頻次,同時如果數據庫意外宕機,buffer pool太小,恢復起來也會比較慢;
1.8、redo日誌記錄格式:
innodb的日誌是具有邏輯意義的物理日誌,所以,日誌記錄的格式就不完全是物理信息,而是有一定邏輯意義,基本的格式如下: type(日誌類型),space(表空間ID值),offset(前面space所指定的文件中的頁面號,以頁面大小為單位),data(表示這條日誌記錄對應的數據,這個數據是不確定的,根據不同的type值而不同) ---type類型有很多,比較常用的有: ①:mlog_ibyte、mlog_2bytes、mlog_4bytes、mlog_8bytes:這四個類型,表示要在某個位置,寫入一個(兩個、四個、八個)字節的內容; ②:mlog_write_string:這種類型的日誌,其實和mlog_ibyte是類似的,只是mlog_ibyte是要寫一個固定長度的數據,而mlog_write_string是要寫一段變長的數據。 ③:mlog_undo_insert:這個類型的日誌,是在將一條記錄設置為頁面中的最小記錄時產生的,因為只是打個標記,存儲的內容比較簡單; ④:mlog_init_file_page:這個類型的日誌比較簡單,只有前面的基本頭信息,沒有data部分; ⑤:mlog_comp_page_create:這個類型只需要村一個類型及要創建的頁面的位置即可; ⑥:mlog_multi_rec_end:這個類型的記錄是非常特殊的,它只起一個標記的作用,其存儲的內容只有占一個字節的類型值。 ⑦:mlog_comp_rec_clust_delete_mark:這個類型的日誌是表示,需要將聚集索引中的某個記錄打上刪除標誌; ⑧:mlog_comp_rec_update_in_place:這個類型的日誌記錄更新後的記錄信息,包括所有被更新的列的信息。 ⑨:mlog_comp_page_reorganize:這個類型的日誌表示的是要重組指定的頁面,其記錄的內容也很簡單,只需要存儲要重組哪一個頁面即可;
1.9、日誌刷盤時機:共有5種時機:
①:log buffer空間用完了,這就會將已經產生的log buffer中的日誌刷到磁盤中,這是最普遍的一種方式; ②:master線程在後臺每秒鐘刷一次,將當前log buffer中的日誌刷到磁盤中; ③:每次執行DML操作時,都會主動檢查日誌空間是否足夠,如果使用空間的量已經超過了一個預設的經驗值,就會主動刷日誌,以保證在後面真正執行時,不會再執行過程中被動的刷盤,但這裏只會是寫文件(寫入OS緩沖中)不會刷盤 ④:在做檢查點的時候,要保證所有要刷的頁面中LSN值最小的日誌已經刷入到磁盤,不然,如果此時數據庫宕機,日誌不存在,但數據頁面已經被修改,從而導致數據不一致,就違背了寫日誌的原則; ⑤:提交邏輯事務時,會因為參數innodb_flush_log_at_trx_commit值的不同,產生不同的行為。如果設置0,則在事務提交時,根本不會去刷日誌緩沖區,這種設置是最危險的;如果設置2,則在事務提交時會將日誌寫入到文件中,但不會去刷盤,只要操作系統不掛,即使數據庫掛了,數據還是不會丟失,一般都是設置為2;
1.10、redo log刷盤機制:
當提交事務(邏輯)時,可以通過參數innodb_flush_log_at_trx_commit來控制redo log寫入的機制,參數值不同,產生的行為不同,主要參數值如下:
①:innodb_flush_log_at_trx_commit=0 事務提交時,MySQL不會去處理日誌緩存區的內容,也不會去處理日誌文件的刷盤操作,由MySQL的後臺master線程每隔1s將緩存區的文件刷新到日誌文件中;(主機正常,數據庫宕機後:一般只會丟失最近1s的事務) ②:innodb_flush_log_at_trx_commit=1 事務提交時,會將日誌緩沖區的日誌寫入到文件中,同時會刷新到磁盤中,保證數據庫事務完全不會丟失。這種設置影響數據庫性能;(主機正常,數據庫宕機後:數據不會丟失) ③:innodb_flush_log_at_trx_commit=2 事務提交時,會將日誌緩存區日誌寫入到文件中,但是不會刷新到磁盤中。由MySQL的後臺master線程每隔1s將系統緩存的日誌文件刷新到磁盤中;(主機正常,數據庫宕機後:數據不會丟失)
---註意:如果數據庫所在主機宕機後:參數0 會丟失最近1s的事務;參數1 不會有任何數據丟失; 參數2 會丟失最近1s的事務;
第二、數據庫undo段管理:
在innodb中支持的回滾段總共有:128X1024=131072個,在每一個事務開始的時候,都會分配一個rseg,就是從長度為128的數組中,根據最近使用的情況,找到一個臨近位置的rseg;
在事務執行的過程中,會產生兩種回滾日誌,一種是insert的undo記錄,一種是update的undo記錄;(因為innodb把undo分為兩類,一類就是新增,也就是insert,一類是修改,就是update,分類的依據就是事務提交後要不要做purge操作,因為insert是不需要purge的,只要事務提交了,那這個回滾記錄就可以丟掉了,而對於更新和刪除操作而言,如果事務提交了,還需要為MVCC服務,那就需要將這些日誌放到history list中去,等待去做purge已經MVCC的多版本查詢等,所以分為兩類)
2.1、數據庫undo日誌記錄格式:
undo有4種類型:
①:trx_undo_insert_rec:記錄插入的undo日誌類型,插入記錄用於回滾時,只需要通過其主鍵就可以實現回滾操作,所以在undo日誌中,只記錄了表ID及主鍵信息; ②:trx_undo_upd_exist_rec:更新一條存在記錄的undo日誌類型; ③:trx_undo_upd_del_rec:更新一條已經打了刪除標誌記錄的undo日誌類型; ④:trx_undo_del_mark_rec:刪除記錄時對記錄打刪除標誌的undo日誌類型; ---註意:與redo日誌記錄存儲不同,undo日誌的存儲,是不會垮頁面的; ---註意:使用參數innodb_force_recovery來決定要不要做回滾操作,如果設置3或3以上,那麽在啟動innodb的時候就不回滾了,這樣可能導致數據庫邏輯上的不一致;
本文出自 “笨小孩的dba之路” 博客,請務必保留此出處http://fengfeng688.blog.51cto.com/4896812/1953596
MySQL——innodb日誌管理