mysql 5.7 io 性能 aio_深入理解MySQL的InnoDB引擎
在MySQL中的引擎一文中說了,我們在幾乎所有的情況下其實用的都是InnoDB引擎,這里我們就重點再看一下這個引擎,包括他的存儲結構,線程模型和數據文件。
我們可以通過show engine innodb status \G;(\G只是表示輸出結果縱向表格輸出)命令可以查看innodb引擎的的一些基本信息,如下圖:
image.png
image.png
上圖中可以看到有線程、事務、文件IO,緩沖區,內存,日志等等一些信息,我們把這些信息分為存儲結構、線程模型和數據文件三類,以下分別說明一下。
存儲結構
InnoDB的存儲引擎,其結構從大的劃分來講分為內存區域和磁盤區域兩部分:
image.png
InnoDB的內存區域
內存結構主要包括Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件,這里分別看一下:
1. Buffer Pool(緩沖池,簡稱BP)
BP以Page頁為單位,默認大小16K,BP的底層采用鏈表數據結構管理Page。在InnoDB訪問表記錄和索引時會在Page頁中緩存,以后使用可以減少磁盤IO操作,提升效率。以下我們看一下BP的頁管理,內存的淘汰算法LRU以及緩沖池的一些配置參數:
1)Page管理機制
Page根據狀態可以分為三種類型:
free page : 空閑page,未被使用
clean page:被使用page,數據沒有被修改過
dirty page:臟頁,被使用page,數據被修改過,頁中數據和磁盤的數據產生了不一致
針對上述三種page類型,InnoDB通過三種鏈表結構來維護和管理:
free list :表示空閑緩沖區,管理free page
flush list:表示需要刷新到磁盤的緩沖區,管理dirty page,內部page按修改時間排序。臟頁數據既存在于flush鏈表,也在LRU鏈表中,但是兩種互不影響,LRU鏈表負責管理page的可用性和釋放,而flush鏈表負責管理臟頁的刷盤操作。
lru list:表示正在使用的緩沖區,管理clean page和dirty page,緩沖區以midpoint為基點,前面鏈表稱為new列表區,存放經常訪問的數據,占63%;后面的鏈表稱為old列表區,存放使用較少數據,占37%。
2)改進型LRU算法維護
普通LRU:末尾淘汰法,新數據從鏈表頭部加入,釋放空間時從末尾淘汰。
改進型LRU:鏈表分為new和old兩個部分,加入元素時并不是從表頭插入,而是從中間midpoint位置插入,如果數據很快被訪問,那么page就會向new列表頭部移動,如果數據沒有被訪問,會逐步向old尾部移動,等待淘汰。
每當有新的page數據讀取到buffer pool時,InnoDb引擎會判斷是否有空閑頁,是否足夠,如果有就將free page從free list列表刪除,放入到LRU列表中。沒有空閑頁,就會根據LRU算法淘汰LRU鏈表默認的頁,將內存空間釋放分配給新的頁。
3)Buffer Pool配置參數
show variables like '%innodb_page_size%'; //查看page頁大小
show variables like '%innodb_old%'; //查看lru list中old列表參數
show variables like '%innodb_buffer%'; //查看buffer pool參數
建議:將innodb_buffer_pool_size設置為總內存大小的60%-80%,
innodb_buffer_pool_instances可以設置為多個,這樣可以避免緩存爭奪。
2. Change Buffer(寫緩沖區,簡稱CB)
在進行DML操作時,如果BP沒有相應的Page數據,并不會立刻將磁盤加載到緩沖池,而是在CB記錄緩沖變更,等未來數據被讀取時,再將數據合并恢復到BP中。ChangeBuffer占用BufferPool空間,默認占25%,最大允許占50%,可以通過參數innodb_change_buffer_max_size設置,具體調多大要根據讀寫業務量。
當更新一條記錄時,如果該記錄在BufferPool存在,就直接在BufferPool修改,也就是一次內存操作。如果該記錄在BufferPool不存在(沒有命中),會直接在ChangeBuffer進行一次內存操作,不用再去磁盤查詢數據,避免一次磁盤IO。當下次查詢記錄時,會先進行磁盤讀取,然后再從ChangeBuffer中讀取信息合并,最終載入BufferPool中。
這里要注意寫緩沖區只適用于非唯一普通索引頁。如果在索引設置唯一性,在進行修改時,InnoDB必須要做唯一性校驗,因此必須查詢磁盤,這樣就要做一次IO操作。會直接將記錄查詢到BufferPool中,然后在緩沖池修改,不會在ChangeBuffer操作。
3. Adaptive Hash Index(自適應哈希索引)
用于優化對BP數據的查詢。InnoDB存儲引擎會監控對表索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之為自適應。InnoDB存儲引擎會自動根據訪問的頻率和模式來為某些頁建立哈希索引。
4. Log Buffer(日志緩沖區)
日志緩沖區用來保存要寫入磁盤上log文件(Redo/Undo)的數據,日志緩沖區的內容定期刷新到磁盤log文件中。日志緩沖區滿時會自動將其刷新到磁盤,當遇到BLOB或多行更新的大事務操作時,增加日志緩沖區可以節省磁盤I/O。
LogBuffer主要是用于記錄InnoDB引擎日志,在DML操作時會產生Redo和Undo日志。
LogBuffer空間滿了,會自動寫入磁盤。可以通過將innodb_log_buffer_size參數調大,減少磁盤IO頻率。
innodb_flush_log_at_trx_commit參數控制日志刷新行為,默認為1
0 : 每隔1秒寫日志文件和刷盤操作(寫日志文件LogBuffer-->OS cache,刷盤OS
cache-->磁盤文件),最多丟失1秒數據
1:事務提交,立刻寫日志文件和刷盤,數據不丟失,但是會頻繁IO操作
2:事務提交,立刻寫日志文件,每隔1秒鐘進行刷盤操作
InnoDB的磁盤區域
InnoDB磁盤主要包含Tablespaces,InnoDB Data Dictionary,Doublewrite Buffer、Redo Log和Undo Logs,這里我們看一下前面三個區域,后面兩個我們在MySQL日志的學習中再討論。
1. 表空間(Tablespaces)
表空間用于存儲表結構和數據。表空間又分為系統表空間、獨立表空間、通用表空間、臨時表空間、Undo表空間等多種類型;
1.1 系統表空間(The System Tablespace)
包含InnoDB數據字典,Doublewrite Buffer,Change Buffer,Undo Logs的存儲區域。系統表空間也默認包含任何用戶在系統表空間創建的表數據和索引數據。系統表空間是一個共享的表空間因為它是被多個表共享的。
該空間的數據文件通過參數innodb_data_file_path控制,默認值是ibdata1:12M:autoextend(文件名為ibdata1、12MB、自動擴展)。
1.2 獨立表空間(File-Per-Table Tablespaces)
獨立表空間是一個單表表空間,默認是開啟的,該表創建于自己的數據文件中,而非創建于系統表空間中。當innodb_file_per_table選項開啟時,表將被創建于表空間中。否則,innodb將被創建于系統表空間中。每個表文件表空間由一個.ibd數據文件代表,該文件默認被創建于數據庫目錄中。表空間的表文件支持動態(dynamic)和壓縮(commpressed)行格式。
1.3通用表空間(General Tablespaces)
通用表空間為通過create tablespace語法創建的共享表空間。通用表空間可以創建于mysql數據目錄外的其他表空間,其可以容納多張表,且其支持所有的行格式。
CREATE TABLESPACE ts1 ADD DATAFILE ts1.ibd Engine=InnoDB; //創建表空間ts1
CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1; //將表添加到ts1表空間
1.3 撤銷表空間(Undo Tablespaces)
撤銷表空間由一個或多個包含Undo日志文件組成。在MySQL 5.7版本之前Undo占用的是System Tablespace共享區,從5.7開始將Undo從System Tablespace分離了出來。
InnoDB使用的undo表空間由innodb_undo_tablespaces配置選項控制,默認為0。參數值為0表示使用系統表空間ibdata1;大于0表示使用undo表空間undo_001、undo_002等。
1.4 臨時表空間(Temporary Tablespaces)
CREATE TABLESPACE ts1 ADD DATAFILE ts1.ibd Engine=InnoDB; //創建表空間ts1
CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1; //將表添加到ts1表空間
分為session temporary tablespaces 和global temporary tablespace兩種。session temporary tablespaces 存儲的是用戶創建的臨時表和磁盤內部的臨時表。global temporary tablespace儲存用戶臨時表的回滾段(rollback segments )。mysql服務器正常關閉或異常終止時,臨時表空間將被移除,每次啟動時會被重新創建。
2. 數據字典(InnoDB Data Dictionary)
InnoDB數據字典由內部系統表組成,這些表包含用于查找表、索引和表字段等對象的元數據。
元數據物理上位于InnoDB系統表空間中。由于歷史原因,數據字典元數據在一定程度上與InnoDB表元數據文件(.frm文件)中存儲的信息重疊。
3. 雙寫緩沖區(Doublewrite Buffer)
雙寫緩沖區位于系統表空間,是一個存儲區域。
在BufferPage的page頁刷新到磁盤真正的位置前,會先將數據存在Doublewrite 緩沖區。
如果在page頁寫入過程中出現操作系統、存儲子系統或mysqld進程崩潰,InnoDB可以在崩潰恢復期間從Doublewrite 緩沖區中找到頁面的一個好備份。
如果要禁用Doublewrite 緩沖區,可以將innodb_doublewrite設置為0。
在大多數情況下,默認情況下啟用雙寫緩沖區,使用Doublewrite 緩沖區時,建議將innodb_flush_method設置為O_DIRECT。這里的MySQL的innodb_flush_method這個參數控制著innodb數據文件及redo log的打開、刷寫模式。他有三個值:fdatasync(默認),O_DSYNC,O_DIRECT。設置O_DIRECT表示數據文件寫入操作會通知操作系統不要緩存數據,也不要用預讀,直接從Innodb Buffer寫到磁盤文件。
默認的fdatasync意思是先寫入操作系統緩存,然后再調用fsync()函數去異步刷數據文件與redo log的緩存信息。
新版本存儲結構的改變
MySQL在5.7和后續的8.0版本中的存儲結構,做了一定改變,如下圖所示:
image.png
MySQL 5.7 版本
1)將 Undo日志表空間從共享表空間 ibdata 文件中分離出來,可以在安裝 MySQL 時由用戶自行指定文件大小和數量。
2)增加了 temporary 臨時表空間,里面存儲著臨時表或臨時查詢結果集的數據。
3)Buffer Pool 大小可以動態修改,無需重啟數據庫實例。
MySQL 8.0 版本
1)將InnoDB表的數據字典和Undo都從共享表空間ibdata中徹底分離出來了,以前需要ibdata中數據字典與獨立表空間ibd文件中數據字典一致才行,8.0版本就不需要了。
2)emporary 臨時表空間也可以配置多個物理文件,而且均為 InnoDB 存儲引擎并能創建索引,這樣加快了處理的速度。
3)用戶可以像 Oracle 數據庫那樣設置一些表空間,每個表空間對應多個物理文件,每個表空間可以給多個表使用,但一個表只能存儲在一個表空間中。
4)將Doublewrite Buffer從共享表空間ibdata中也分離出來了。
線程模型
InnoDB的線程模型分為IO Thread、Purge Thread、Page Thread和Master Thread,如下圖所示:
image.png
IO Thread
在InnoDB中使用了大量的AIO(Async IO)來做讀寫處理,這樣可以極大提高數據庫的性能。在InnoDB1.0版本之前共有4個IO Thread,分別是write,read,insert buffer和log thread,后來版本將read thread和write thread分別增大到了4個,一共有10個了。
read thread : 負責讀取操作,將數據從磁盤加載到緩存page頁。4個
write thread:負責寫操作,將緩存臟頁刷新到磁盤。4個
log thread:負責將日志緩沖區內容刷新到磁盤。1個
insert buffer thread :負責將寫緩沖內容刷新到磁盤。1個
Purge Thread
事務提交之后,其使用的undo日志將不再需要,因此需要Purge Thread回收已經分配的undo頁。
show variables like '%innodb_purge_threads%';
Page Cleaner Thread
作用是將臟數據刷新到磁盤,臟數據刷盤后相應的redo log也就可以覆蓋,即可以同步數據,又能達到redo log循環使用的目的。會調用write thread線程處理。
show variables like '%innodb_page_cleaners%';
Master Thread
Master thread是InnoDB的主線程,負責調度其他各線程,優先級最高。作用是將緩沖池中的數據異步刷新到磁盤 ,保證數據的一致性。
這些工作包含:臟頁的刷新(page cleaner thread)、undo頁回收(purge thread)、redo日志刷新(log thread)、合并寫緩沖等。在其內部有兩個主去處理,分別是每隔1秒和10秒處理。
每1秒的操作:
刷新日志緩沖區,刷到磁盤
合并寫緩沖區數據,根據IO讀寫壓力來決定是否操作
刷新臟頁數據到磁盤,根據臟頁比例達到75%才操作(innodb_max_dirty_pages_pct,innodb_io_capacity)
每10秒的操作:
刷新臟頁數據到磁盤
合并寫緩沖區數據
刷新日志緩沖區
刪除無用的undo頁
數據文件
InnoDB數據文件存儲結構
分為一個ibd數據文件-->Segment(段)-->Extent(區)-->Page(頁)-->Row(行)
image.png
1. Tablesapce(表空間)
表空間用于存儲多個ibd數據文件,用于存儲表的記錄和索引。一個文件包含多個段。
2. Segment(段)
段用于管理多個Extent,分為數據段(Leaf node segment)、索引段(Non-leaf node segment)、回滾段(Rollback segment)。一個表至少會有兩個segment,一個管理數據,一個管理索引。每多創建一個索引,會多兩個segment。
3. Extent(區)
一個區固定包含64個連續的頁,大小為1M。當表空間不足,需要分配新的頁資源,不會一頁一頁分,直接分配一個區。
4 Page(頁)
頁用于存儲多個Row行記錄,大小為16K。包含很多種頁類型,比如數據頁,undo頁,系統頁,事務數據頁,大的BLOB對象頁。
Page是文件最基本的單位,無論何種類型的page,都是由page header,page trailer和page body組成。如下圖所示:
image.png
5. Row(行)
行包含了記錄的字段值,事務ID(Trx id)、滾動指針(Roll pointer)、字段指針(Fieldpointers)等信息。
InnoDB文件存儲格式
我們通過show table satus \G;命令,查看InnoDB的文件狀態(示例的數據庫employee表):
image.png
一般情況下,如果row_format為REDUNDANT、COMPACT,文件格式為Antelope;如果row_format為DYNAMIC和COMPRESSED,文件格式為Barracuda。
通過 information_schema 查看指定表的文件格式
select * from information_schema.innodb_sys_tables;
File文件格式(File-Format)
在早期的InnoDB版本中,文件格式只有一種,隨著InnoDB引擎的發展,出現了新文件格式,用于
支持新的功能。目前InnoDB只支持兩種文件格式:Antelope 和 Barracuda。
Antelope: 先前未命名的,最原始的InnoDB文件格式,它支持兩種行格式:COMPACT和REDUNDANT,MySQL 5.6及其以前版本默認格式為Antelope。
Barracuda: 新的文件格式。它支持InnoDB的所有行格式,包括新的行格式:COMPRESSED和 DYNAMIC。
通過innodb_file_format 配置參數可以設置InnoDB文件格式,之前默認值為Antelope,5.7版本開始改為Barracuda。
Row行格式(Row_format)
表的行格式決定了它的行是如何物理存儲的,這反過來又會影響查詢和DML操作的性能。如果在單個page頁中容納更多行,查詢和索引查找可以更快地工作,緩沖池中所需的內存更少,寫入更新時所需的I/O更少。
InnoDB存儲引擎支持四種行格式:REDUNDANT、COMPACT、DYNAMIC和COMPRESSED。
image.png
DYNAMIC和COMPRESSED新格式引入的功能有:數據壓縮、增強型長列數據的頁外存儲和大索引前綴。
每個表的數據分成若干頁來存儲,每個頁中采用B樹結構存儲。
如果某些字段信息過長,無法存儲在B樹節點中,這時候會被單獨分配空間,此時被稱為溢出頁,該字段被稱為頁外列。
1. REDUNDANT 行格式
使用REDUNDANT行格式,表會將變長列值的前768字節存儲在B樹節點的索引記錄中,其余的存儲在溢出頁上。對于大于等于786字節的固定長度字段InnoDB會轉換為變長字段,以便能夠在頁外存儲。
2. COMPACT 行格式
與REDUNDANT行格式相比,COMPACT行格式減少了約20%的行存儲空間,但代價是增加了某些操作的CPU使用量。如果系統負載是受緩存命中率和磁盤速度限制,那么COMPACT格式可能更快。如果系統負載受到CPU速度的限制,那么COMPACT格式可能會慢一些。
3. DYNAMIC 行格式
使用DYNAMIC行格式,InnoDB會將表中長可變長度的列值完全存儲在頁外,而索引記錄只包含指向溢出頁的20字節指針。大于或等于768字節的固定長度字段編碼為可變長度字段。
DYNAMIC行格式支持大索引前綴,最多可以為3072字節,可通過innodb_large_prefix參數控制。
4. COMPRESSED 行格式
COMPRESSED行格式提供與DYNAMIC行格式相同的存儲特性和功能,但增加了對表和索引數據壓縮的支持。
在創建表和索引時,文件格式都被用于每個InnoDB表數據文件(其名稱與*.ibd匹配)。
修改文件格式的方法是重新創建表及其索引,最簡單方法是對要修改的每個表使用以下命令:ALTER TABLE 表名 ROW_FORMAT=格式類型;
總結
以上是生活随笔為你收集整理的mysql 5.7 io 性能 aio_深入理解MySQL的InnoDB引擎的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不是区块链的特征_上市公司日照港物流区块
- 下一篇: mysql免安装如何改密码_mysql免