【我在拉勾訓練營學技術】Mysql 架構原理

前言

文章內容輸出來源:拉勾教育Java高薪訓練營;

mysql 數據庫作爲現在互聯網企業首選的數據庫,我們程序員就應該對它多一些瞭解,我在拉勾訓練營學到第五階段啦,瞭解了mysql 整體架構,記錄下來。

Mysql 體系結構

MySQL Server架構自頂向下大致可以分網絡連接層、服務層、存儲引擎層和系統文件層。

一、網絡連接層

客戶端連接器(Client Connectors):提供與MySQL服務器建立的支持。目前幾乎支持所有主流的服務端編程技術,例如常見的 Java、C、Python、.NET等,它們通過各自API技術與MySQL建立連接。

二、服務層(MySQL Server)

服務層是MySQL Server的核心,主要包含系統管理和控制工具、連接池、SQL接口、解析器、查詢優化器和緩存六個部分。

  • 連接池(Connection Pool):負責存儲和管理客戶端與數據庫的連接,一個線程負責管理一個連接。

  • 系統管理和控制工具(Management Services & Utilities):例如備份恢復、安全管理、集羣管理等

  • SQL 接口(SQL Interface):用於接受客戶端發送的各種SQL命令,並且返回用戶需要查詢的結果。比如DML、DDL、存儲過程、視圖、觸發器等。

  • 解析器(Parser):負責將請求的SQL解析生成一個"解析樹"。然後根據一些MySQL規則進一步檢查解析樹是否合法。

  • 查詢優化器(Optimizer):當“解析樹”通過解析器語法檢查後,將交由優化器將其轉化成執行計劃,然後與存儲引擎交互。

  • 緩存(Cache&Buffffer):緩存機制是由一系列小緩存組成的。比如表緩存,記錄緩存,權限緩存,引擎緩存等。如果查詢緩存有命中的查詢結果,查詢語句就可以直接去查詢緩存中取數據。

三、存儲引擎層(Pluggable Storage Engines)

存儲引擎負責 mysql 中的數據存儲的與提取,與底層的系統文件進行交互。mysql 存儲引擎是插件式的,服務器中的查詢執行引擎通過接口與存儲引擎進行通信 ,接口屏蔽了不同的存儲引擎之間的差異。現在有很多的存儲引擎,常見的就是 MyISAM 和InnoDB

四、系統文件層(File System)

該層負責將數據庫的數據和日誌存儲在文件系統上,並完成與存儲引擎的交互,是文件的物理存儲層。主要包含日誌,數據文件,配置文件,pid 文件,socket 文件等。

  • 日誌文件

    • 錯誤日誌(Error log)默認開啓,

      show variables like '%log_error%'
  • 通用查詢日誌(General query log):記錄一般查詢語句,

    show variables like '%general%';
    image-20200830132831117
  • 二進制日誌(binary log):記錄了對MySQL數據庫執行的更改操作,並且記錄了語句的發生時間、執行時長;但是它不記錄select、show等不修改數據庫的SQL。主要用於數據庫恢復和主從複製。

    show variables like '%log_bin%'; //是否開啓
    show variables like '%binlog%'; //參數查看
    show binary logs;//查看日誌文件
  • 慢查詢日誌(Slow query log):記錄所有執行時間超時的查詢SQL,默認是10秒

```
show variables like '%slow_query%'; //是否開啓
show variables like '%long_query_time%'; //時長
```
  • 配置文件

    用於存儲 MySQL 的所有配置信息文件,比如my.cnf、my.ini 等

  • 數據文件

    • db.opt 文件:記錄這個庫的默認使用的字符集和校驗規則。
    • frm 文件:存儲與表有關的元數據信息(meta),包括表結構的定義信息等,每張表都會有一個frm 文件。
    • MYD 文件:MyIsAM 存儲引擎專用,存放MyISAM 表的數據,每張表都會有一個 .MYD 文件
    • MYI 文件:MyISAM 存儲引擎專用,存放 MyISAM 表的索引相關信息,每一張 MyISAM 表對應一個 .MYI 文件。
    • ibd文件和 IBDATA 文件:存放 InnoDB 的數據文件(包括索引)。InnoDB 存儲引擎有兩種表空間方式:獨享表空間和共享表空間。獨享表空間使用 .ibd 文件來存放數據,且每一張InnoDB 表對應一個 .ibd 文件。共享表空間使用 .ibdata 文件,所有表共同使用一個(或多個,自行配置).ibdata 文件。
    • ibdata1 文件:系統表空間數據文件,存儲表元數據、Undo日誌等 。
    • ib_logfifile0、ib_logfifile1 文件:Redo log 日誌文件。
  • pid 文件

    pid 文件是 mysqlId 應用程序在 unix/linux 環境下的一個進程文件,和許多其他的unix/linux 服務端程序一樣,它存放着自己的進程id 。

  • socket 文件

    socket 文件也是在 unix/linux 環境下才有的,用戶在linux 環境下客戶端連接不可以通過 TCP/IP 網絡而直接使用 Unix Socket 來連接 MySQL 。

MySQL 運行機制

  • ①建立連接(Connectors&Connection Pool),通過客戶端/服務器通信協議與MySQL建立連接。MySQL 客戶端與服務端的通信方式是 “ 半雙工 ”。對於每一個 MySQL 的連接,時刻都有一個線程狀態來標識這個連接正在做什麼。

    通訊機制:

    線程狀態:

    show processlist; //查看用戶正在運行的線程信息,root用戶能查看所有線程,其他用戶只能看自己的

    • 全雙工:能同時發送和接收數據,例如平時打電話。

    • 半雙工:指的某一時刻,要麼發送數據,要麼接收數據,不能同時。例如早期對講機

    • 單工:只能發送數據或只能接收數據。例如單行道

  • id:線程ID,可以使用kill xx;

  • user:啓動這個線程的用戶

  • Host:發送請求的客戶端的IP和端口號

  • db:當前命令在哪個庫執行

  • Command:該線程正在執行的操作命令

    • Create DB:正在創建庫操作
    • Drop DB:正在刪除庫操作
    • Execute:正在執行一個PreparedStatement
    • Close Stmt:正在關閉一個PreparedStatement
    • Query:正在執行一個語句
    • Sleep:正在等待客戶端發送語句
    • Quit:正在退出
    • Shutdown:正在關閉服務器
  • Time:表示該線程處於當前狀態的時間,單位是秒

  • State:線程狀態

    • Updating:正在搜索匹配記錄,進行修改
    • Sleeping:正在等待客戶端發送新請求
    • Starting:正在執行請求處理
    • Checking table:正在檢查數據表
    • Closing table : 正在將表中數據刷新到磁盤中
    • Locked:被其他查詢鎖住了記
    • Sending Data:正在處理Select查詢,同時將結果發送給客戶端
  • Info:一般記錄線程執行的語句,默認顯示前100個字符。想查看完整的使用show full processlist;

  • ②查詢緩存(Cache&Buffffer),這是MySQL的一個可優化查詢的地方,如果開啓了查詢緩存且在查詢緩存過程中查詢到完全相同的SQL語句,則將查詢結果直接返回給客戶端;如果沒有開啓查詢緩存或者沒有查詢到完全相同的 SQL 語句則會由解析器進行語法語義解析,並生成“解析樹”。

    • 查詢語句使用SQL_NO_CACHE
    • 查詢的結果大於query_cache_limit設置
    • 查詢中有一些不確定的參數,比如now()
    • 緩存Select查詢的結果和SQL語句
    • 執行Select查詢時,先查詢緩存,判斷是否存在可用的記錄集,要求是否完全相同(包括參數值),這樣纔會匹配緩存數據命中。
    • 即使開啓查詢緩存,以下SQL也不能緩存
    • show variables like '%query_cache%'; //查看查詢緩存是否啓用,空間大小,限制等
    • show status like 'Qcache%'; //查看更詳細的緩存參數,可用緩存空間,緩存塊,緩存多少等
  • ③解析器(Parser)將客戶端發送的SQL進行語法解析,生成"解析樹"。預處理器根據一些MySQL規則進一步檢查“解析樹”是否合法,例如這裏將檢查數據表和數據列是否存在,還會解析名字和別名,看看它們是否有歧義,最後生成新的“解析樹”。

  • ④查詢優化器(Optimizer)根據“解析樹”生成最優的執行計劃。MySQL使用很多優化策略生成最優的執行計劃,可以分爲兩類:靜態優化(編譯時優化)、動態優化(運行時優化)。

    • 等價變換策略。基於聯合索引,調整條件位置等。
    • 優化count、min、max等函數。InnoDB引擎min函數只需要找索引最左邊
    • 提前終止查詢。使用了limit查詢,獲取limit所需的數據,就不在繼續遍歷後面數據
    • 提前終止查詢。MySQL對in查詢,會先進行排序,再採用二分法查找數據。比如where id in (2,1,3),變成 in (1,2,3)
  • ⑤查詢執行引擎負責執行 SQL 語句,此時查詢執行引擎會根據 SQL 語句中表的存儲引擎類型,以及對應的API接口與底層存儲引擎緩存或者物理文件的交互,得到查詢結果並返回給客戶端。若開啓用查詢緩存,這時會將SQL 語句和結果完整地保存到查詢緩存(Cache&Buffffer)中,以後若有相同的 SQL 語句執行則直接返回結果。

    • 如果開啓了查詢緩存,先將查詢結果做緩存操作

    • 返回結果過多,採用增量模式返回

MySQL 存儲引擎

存儲引擎在MySQL的體系架構中位於第三層,負責MySQL中的數據的存儲和提取,是與文件打交道的子系統,它是根據MySQL提供的文件訪問層抽象接口定製的一種文件訪問機制,這種機制就叫作存儲引擎。

使用下面命令,就可以查看當前數據庫支持的引擎信息。

show engines;

在5.5版本之前默認採用MyISAM存儲引擎,從5.5開始採用InnoDB存儲引擎。

  • InnoDB:支持事務,具有提交,回滾和崩潰恢復能力,事務安全

  • MyISAM:不支持事務和外鍵,訪問速度快

  • Memory:利用內存創建表,訪問速度非常快,因爲數據在內存,而且默認使用Hash索引,但是一旦關閉,數據就會丟失

  • Archive:歸檔類型引擎,僅能支持insert和select語句

  • Csv:以CSV文件進行數據存儲,由於文件限制,所有列必須強制指定not null,另外CSV引擎也不支持索引和分區,適合做數據交換的中間表

  • BlackHole: 黑洞,只進不出,進來消失,所有插入數據都不會保存

  • Federated:可以訪問遠端MySQL數據庫中的表。一個本地表,不保存數據,訪問遠程表內容。

  • MRG_MyISAM:一組MyISAM表的組合,這些MyISAM表必須結構相同,Merge表本身沒有數據,對Merge操作可以對一組MyISAM表進行操作。

InnoDB 和 MyISAM 對比

InnoDB 和 MyISAM 是使用 MySQL 時最常用的兩種引擎類型,我們重點來看下兩者區別。

  • 事務和外鍵

    InnoDB支持事務和外鍵,具有安全性和完整性,適合大量 insert 或 update 操作

    MyISAM 不支持事務和外鍵,它提供高速存儲和檢索,適合大量的 select 查詢操作

  • 鎖機制

    InnoDB支持行級鎖,鎖定指定記錄。基於索引來加鎖實現。

    MyISAM支持表級鎖,鎖定整張表。

  • 索引結構

    InnoDB使用聚集索引(聚簇索引),索引和記錄在一起存儲,既緩存索引,也緩存記錄。

    MyISAM使用非聚集索引(非聚簇索引),索引和記錄分開。

  • 併發處理能力

    MyISAM使用表鎖,會導致寫操作併發率低,讀之間並不阻塞,讀寫阻塞。

    InnoDB讀寫阻塞可以與隔離級別有關,可以採用多版本併發控制(MVCC)來支持高併發

  • 存儲文件

    InnoDB表對應兩個文件,一個.frm表結構文件,一個.ibd數據文件。InnoDB表最大支持64TB;

    MyISAM表對應三個文件,一個.frm表結構文件,一個MYD表數據文件,一個.MYI索引文件。從MySQL5.0開始默認限制是256TB。

    image-20200830142200796
  • 適用場景

    MyISAM:

    InnoDB:

    • 需要事務支持(具有較好的事務特性)
    • 行級鎖定對高併發有很好的適應能力
    • 數據更新較爲頻繁的場景
    • 數據一致性要求較高
    • 硬件設備內存較大,可以利用InnoDB較好的緩存能力來提高內存利用率,減少磁盤IO
    • 不需要事務支持(不支持)
    • 併發相對較低(鎖定機制問題)
    • 數據修改相對較少,以讀爲主
    • 數據一致性要求不高

兩種引擎該如何選擇?

  • 是否需要事務?有,InnoDB
  • 是否存在併發修改?有,InnoDB
  • 是否追求快速查詢,且數據修改少?是,MyISAM
  • 在絕大多數情況下,推薦使用InnoDB

InnoDB 存儲結構

從MySQL 5.5版本開始默認使用InnoDB作爲引擎,它擅長處理事務,具有自動崩潰恢復的特性,在日常開發中使用非常廣泛。下面是官方的InnoDB引擎架構圖,主要分爲內存結構和磁盤結構兩大部分。

image-20200830142555125

內存結構主要包括 Buffffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四大組件。

  • Buffer Pool:緩衝池,簡稱BP。BP以Page頁爲單位,默認大小16K,BP的底層採用鏈表數據結構管理Page。在InnoDB訪問表記錄和索引時會在Page頁中緩存,以後使用可以減少磁盤IO操作,提升效率。

    • free list :表示空閒緩衝區,管理free page
    • flush list:表示需要刷新到磁盤的緩衝區,管理dirty page,內部page按修改時間排序。髒頁即存在於flush鏈表,也在LRU鏈表中,但是兩種互不影響,LRU鏈表負責管理page的可用性和釋放,而flflush鏈表負責管理髒頁的刷盤操作。
    • lru list:表示正在使用的緩衝區,管理clean page和dirty page,緩衝區以midpoint爲基點,前面鏈表稱爲new列表區,存放經常訪問的數據,佔63%;後面的鏈表稱爲old列表區,存放使用較少數據,佔37%。
    • free page :空閒page,未被使用

    • clean page:被使用page,數據沒有被修改過

    • dirty page:髒頁,被使用page,數據被修改過,頁中數據和磁盤的數據產生了不一致

    • Page管理機制 Page根據狀態可以分爲三種類型:

    • 針對上述三種page類型,InnoDB通過三種鏈表結構來維護和管理

    • 改進型LRU算法維護

      普通LRU:末尾淘汰法,新數據從鏈表頭部加入,釋放空間時從末尾淘汰

      改性LRU:鏈表分爲new和old兩個部分,加入元素時並不是從表頭插入,而是從中間midpoint位置插入,如果數據很快被訪問,那麼page就會向new列表頭部移動,如果數據沒有被訪問,會逐步向old尾部移動,等待淘汰。每當有新的page數據讀取到buffffer pool時,InnoDb引擎會判斷是否有空閒頁,是否足夠,如果有就將free page從free list列表刪除,放入到LRU列表中。沒有空閒頁,就會根據LRU算法淘汰LRU鏈表默認的頁,將內存空間釋放分配給新的頁。

    • Buffer Pool配置參數

      show variables like '%innodb_page_size%'; //查看page頁大小

      show variables like '%innodb_old%'; //查看lru list中old列表參數

      show variables like '%innodb_buffer%'; //查看buffffer pool參數

      image-20200830144549455

      建議:將innodb_buffer_pool_size設置爲總內存大小的60%-80%,

      innodb_buffer_pool_instances可以設置爲多個,這樣可以避免緩存爭奪。

  • Change Buffffer:寫緩衝區,簡稱CB。在進行DML操作時,如果BP沒有其相應的Page數據,並不會立刻將磁盤頁加載到緩衝池,而是在CB記錄緩衝變更,等未來數據被讀取時,再將數據合併恢復到BP中。ChangeBuffer佔用 BufferPoo l空間,默認佔25%,最大允許佔50%,可以根據讀寫業務量來進行調整。

    參數:innodb_change_buffer_max_size;

    當更新一條記錄時,該記錄在 BufferPool 存在,直接在BufferPool修改,一次內存操作。如果該記錄在BufferPool不存在(沒有命中),會直接在ChangeBuffer進行一次內存操作,不用再去磁盤查詢數據,避免一次磁盤IO。當下次查詢記錄時,會先進性磁盤讀取,然後再從ChangeBuffer中讀取信息合併,最終載入BufferPool中。

    寫緩衝區,僅適用於非唯一普通索引頁,爲什麼?

    如果在索引設置唯一性,在進行修改時,InnoDB必須要做唯一性校驗,因此必須查詢磁盤,做一次IO操作。會直接將記錄查詢到BufferPool中,然後在緩衝池修改,不會在ChangeBuffer操作。

  • Adaptive Hash Index:自適應哈希索引,用於優化對BP數據的查詢。InnoDB存儲引擎會監控對錶索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之爲自適應。InnoDB存儲引擎會自動根據訪問的頻率和模式來爲某些頁建立哈希索引。

  • Log Buffer:日誌緩衝區,用來保存要寫入磁盤上log文件(Redo/Undo)的數據,日誌緩衝區的內容定期刷新到磁盤log文件中。日誌緩衝區滿時會自動將其刷新到磁盤,當遇到BLOB或多行更新的大事務操作時,增加日誌緩衝區可以節省磁盤I/O。

    LogBuffer主要是用於記錄InnoDB引擎日誌,在DML操作時會產生Redo和Undo日誌。

    LogBuffer空間滿了,會自動寫入磁盤。可以通過將innodb_log_buffffer_size參數調大,減少磁盤IO頻率

InnoDB 磁盤結構

InnoDB磁盤主要包含Tablespaces,InnoDB Data Dictionary,Doublewrite Buffffer、Redo Log和Undo Logs。

  • 表空間(Tablespaces):用於存儲表結構和數據。表空間又分爲系統表空間、獨立表空間、通用表空間、臨時表空間、Undo表空間等多種類型;

    • 系統表空間(The System Tablespace)

      包含InnoDB數據字典,Doublewrite Buffer,Change Buffer,Undo Logs的存儲區域。系統表空間也默認包含任何用戶在系統表空間創建的表數據和索引數據。系統表空間是一個共享的表空間因爲它是被多個表共享的。該空間的數據文件通過參數innodb_data_file_path控制,默認值是ibdata1:12M:autoextend(文件名爲ibdata1、12MB、自動擴展)。

    • 獨立表空間(File-Per-Table Tablespaces)

      默認開啓,獨立表空間是一個單表表空間,該表創建於自己的數據文件中,而非創建於系統表空間中。當innodb_file_per_table選項開啓時,表將被創建於表空間中。否則,innodb將被創建於系統表空間中。每個表文件表空間由一個.ibd數據文件代表,該文件默認被創建於數據庫目錄中。表空間的表文件支持動態(dynamic)和壓縮(commpressed)行格式。

    • 通用表空間(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 表空間
    • 撤銷表空間(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等。

    • 臨時表空間(Temporary Tablespaces)

      分爲session temporary tablespaces 和global temporary tablespace兩種。session temporary tablespaces 存儲的是用戶創建的臨時表和磁盤內部的臨時表。global temporary tablespace儲存用戶臨時表的回滾段(rollback segments )。mysql服務器正常關閉或異常終止時,臨時表空間將被移除,每次啓動時會被重新創建。

    • 數據字典(InnoDB Data Dictionary)

      InnoDB數據字典由內部系統表組成,這些表包含用於查找表、索引和表字段等對象的元數據。元數據物理上位於InnoDB系統表空間中。由於歷史原因,數據字典元數據在一定程度上與InnoDB表元數據文件(.frm文件)中存儲的信息重疊。

    • 雙寫緩衝區(Doublewrite Buffffer)

      位於系統表空間,是一個存儲區域。在BufffferPage的page頁刷新到磁盤真正的位置前,會先將數據存在Doublewrite 緩衝區。如果在page頁寫入過程中出現操作系統、存儲子系統或mysqld進程崩潰,InnoDB可以在崩潰恢復期間從Doublewrite 緩衝區中找到頁面的一個好備份。在大多數情況下,默認情況下啓用雙寫緩衝區,要禁用Doublewrite 緩衝區,可以將innodb_doublewrite設置爲0。使用Doublewrite 緩衝區時建議將innodb_flflush_method設置爲O_DIRECT。

    • 重做日誌(Redo Log)

      重做日誌是一種基於磁盤的數據結構,用於在崩潰恢復期間更正不完整事務寫入的數據。MySQL以循環方式寫入重做日誌文件,記錄InnoDB中所有對Buffffer Pool修改的日誌。當出現實例故障(像斷電),導致數據未能更新到數據文件,則數據庫重啓時須redo,重新把數據更新到數據文件。讀寫事務在執行的過程中,都會不斷的產生redo log。默認情況下,重做日誌在磁盤上由兩個名爲ib_logfifile0和ib_logfifile1的文件物理表示。

    • 撤銷日誌(Undo Logs)

      撤消日誌是在事務開始之前保存的被修改數據的備份,用於例外情況時回滾事務。撤消日誌屬於邏輯日誌,根據每行記錄進行記錄。撤消日誌存在於系統表空間、撤消表空間和臨時表空間中。

新版本的區別:

image-20200830161321230

MySQL 5.7 版本

  • 將 Undo日誌表空間從共享表空間 ibdata 文件中分離出來,可以在安裝 MySQL 時由用戶自行指定文件大小和數量。

  • 增加了 temporary 臨時表空間,裏面存儲着臨時表或臨時查詢結果集的數據。

  • Buffer Pool 大小可以動態修改,無需重啓數據庫實例。

MySQL 8.0 版本

  • 將InnoDB表的數據字典和Undo都從共享表空間ibdata中徹底分離出來了,以前需要 ibdata中數據字典與獨立表空間ibd文件中數據字典一致纔行,8.0版本就不需要了。

  • temporary 臨時表空間也可以配置多個物理文件,而且均爲 InnoDB 存儲引擎並能創建索引,這樣加快了處理的速度。

  • 用戶可以像 Oracle 數據庫那樣設置一些表空間,每個表空間對應多個物理文件,每個表空間可以給多個表使用,但一個表只能存儲在一個表空間中。

  • 將Doublewrite Buffer從共享表空間ibdata中也分離出來了。

InnoDB 線程模型

image-20200830162556135
  • IO Thread

    在InnoDB中使用了大量的 AIO(Async IO)來做讀寫處理,這樣可以極大提高數據庫的性能。在 InnoDB1.0版本之前共有4個IO Thread,分別是write,read,insert buffffer和log thread,後來版本將read thread和write thread分別增大到了4個,一共有10個了。

    • read thread :負責讀取操作,將數據從磁盤加載到緩存page頁。4個
    • write thread:負責寫操作,將緩存髒頁刷新到磁盤。4個
    • log thread:負責將日誌緩衝區內容刷新到磁盤。1個
    • insert buffffer 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秒的操作:

    每10秒的操作:

    • 刷新髒頁數據到磁盤

    • 合併寫緩衝區數據

    • 刷新日誌緩衝區

    • 刪除無用的undo頁

    • 刷新日誌緩衝區,刷到磁盤

    • 合併寫緩衝區數據,根據IO讀寫壓力來決定是否操作

    • 刷新髒頁數據到磁盤,根據髒頁比例達到75%才操作(innodb_max_dirty_pages_pct,innodb_io_capacity)

InnoDB 數據文件

InnoDB數據文件存儲結構:

分爲一個ibd數據文件-->Segment(段)-->Extent(區)-->Page(頁)-->Row(行)

  • Tablesapce :表空間,用於存儲多個ibd數據文件,用於存儲表的記錄和索引。一個文件包含多個段。

  • Segment:段,用於管理多個Extent,分爲數據段(Leaf node segment)、索引段(Non-leaf nodesegment)、回滾段(Rollback segment)。一個表至少會有兩個segment,一個管理數據,一個管理索引。每多創建一個索引,會多兩個segment。

  • Extent:區,一個區固定包含64個連續的頁,大小爲1M。當表空間不足,需要分配新的頁資源,不會一頁一頁分,直接分配一個區。

  • Page:頁,用於存儲多個Row行記錄,大小爲16K。包含很多種頁類型,比如數據頁,undo頁,系統頁,事務數據頁,大的BLOB對象頁。

  • Row:行,包含了記錄的字段值,事務ID(Trx id)、滾動指針(Roll pointer)、字段指針(Field

    pointers)等信息。

Page是文件最基本的單位,無論何種類型的page,都是由page header,page trailer和page

body組成。如下圖所示

InnoDB 文件存儲格式

show table status;

一般情況下,如果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_fifile_format 配置參數可以設置InnoDB文件格式,之前默認值爲Antelope,5.7版本開始改爲Barracuda

Row 行格式(Row_format)

表的行格式決定了它的行是如何物理存儲的,這反過來又會影響查詢和DML操作的性能。如果在單個page頁中容納更多行,查詢和索引查找可以更快地工作,緩衝池中所需的內存更少,寫入更新時所需的I/O更少。

InnoDB存儲引擎支持四種行格式:REDUNDANT、COMPACT、DYNAMIC和COMPRESSED。

image-20200830171138185

DYNAMIC和COMPRESSED新格式引入的功能有:數據壓縮、增強型長列數據的頁外存儲和大索引前綴。

每個表的數據分成若干頁來存儲,每個頁中採用B樹結構存儲;如果某些字段信息過長,無法存儲在B樹節點中,這時候會被單獨分配空間,此時被稱爲溢出頁,該字段被稱爲頁外列。

  • REDUNDANT 行格式

    使用REDUNDANT行格式,表會將變長列值的前768字節存儲在B樹節點的索引記錄中,其餘的存儲在溢出頁上。對於大於等於786字節的固定長度字段InnoDB會轉換爲變長字段,以便能夠在頁外存儲。

  • COMPACT 行格式

    與REDUNDANT行格式相比,COMPACT行格式減少了約20%的行存儲空間,但代價是增加了某些操作的CPU使用量。如果系統負載是受緩存命中率和磁盤速度限制,那麼COMPACT格式可能更快。如果系統負載受到CPU速度的限制,那麼COMPACT格式可能會慢一些。

  • DYNAMIC 行格式

    使用DYNAMIC行格式,InnoDB會將表中長可變長度的列值完全存儲在頁外,而索引記錄只包含指向溢出頁的20字節指針。大於或等於768字節的固定長度字段編碼爲可變長度字段。DYNAMIC行格式支持大索引前綴,最多可以爲3072字節,可通過innodb_large_prefifix參數控制。

  • COMPRESSED 行格式

    COMPRESSED行格式提供與DYNAMIC行格式相同的存儲特性和功能,但增加了對錶和索引數據壓縮的支持

在創建表和索引時,文件格式都被用於每個InnoDB表數據文件(其名稱與*.ibd匹配)。修改文件格式的方法是重新創建表及其索引,最簡單方法是對要修改的每個表使用以下命令:

ALTER TABLE 表名 ROW_FORMAT=格式類型;

Undo Log

Undo:意爲撤銷或取消,以撤銷操作爲目的,返回指定某個狀態的操作。

Undo Log:數據庫事務開始之前,會將要修改的記錄存放到 Undo 日誌裏,當事務回滾時或者數據庫崩潰時,可以利用 Undo 日誌,撤銷未提交事務對數據庫產生的影響。

Undo Log產生和銷燬:Undo Log在事務開始前產生;事務在提交時,並不會立刻刪除undo log,innodb會將該事務對應的undo log放入到刪除列表中,後面會通過後臺線程purge thread進行回收處理。Undo Log屬於邏輯日誌,記錄一個變化過程。例如執行一個delete,undolog會記錄一個insert;執行一個update,undolog會記錄一個相反的update。

Undo Log存儲:undo log採用段的方式管理和記錄。在innodb數據文件中包含一種rollback segment回滾段,內部包含1024個undo log segment。可以通過下面一組參數來控制Undo log存儲

Undo Log 作用

  • 實現事務的原子性

    Undo Log 是爲了實現事務的原子性而出現的產物。事務處理過程中,如果出現了錯誤或者用戶執行了 ROLLBACK 語句,MySQL 可以利用 Undo Log 中的備份將數據恢復到事務開始之前的狀態。

  • 實現多版本併發控制(MVCC)

    Undo Log 在 MySQL InnoDB 存儲引擎中用來實現多版本併發控制。事務未提交之前,Undo Log 保存了未提交之前的版本數據,Undo Log 中的數據可作爲數據舊版本快照供其他併發事務進行快照讀。

    image-20200831173843394

Redo Log

Redo Log和Binlog是MySQL日誌系統中非常重要的兩種機制,也有很多相似之處,下面介紹下兩者細節和區別。

Redo:顧名思義就是重做。以恢復操作爲目的,在數據庫發生意外時重現操作。

Redo Log:指事務中修改的任何數據,將最新的數據備份存儲的位置(Redo Log),被稱爲重做日誌。

Redo Log 的生成和釋放:隨着事務操作的執行,就會生成Redo Log,在事務提交時會將產生 Redo Log寫入Log Buffer,並不是隨着事務的提交就立刻寫入磁盤文件。等事務操作的髒頁寫入到磁盤之後,Redo Log 的使命也就完成了,Redo Log佔用的空間就可以重用(被覆蓋寫入)。

Redo Log工作原理

Redo Log 是爲了實現事務的持久性而出現的產物。防止在發生故障的時間點,尚有髒頁未寫入表的 IBD 文件中,在重啓 MySQL 服務的時候,根據 Redo Log 進行重做,從而達到事務的未入磁盤數據進行持久化這一特性。

image-20200831174044919

Redo Log寫入機制

Redo Log 文件內容是以順序循環的方式寫入文件,寫滿時則回溯到第一個文件,進行覆蓋寫。

image-20200831174111509
  • write pos 是當前記錄的位置,一邊寫一邊後移,寫到最後一個文件末尾後就回到 0 號文件開頭;
  • checkpoint 是當前要擦除的位置,也是往後推移並且循環的,擦除記錄前要把記錄更新到數據文件;

write pos 和 checkpoint 之間還空着的部分,可以用來記錄新的操作。如果 write pos 追上 checkpoint,表示寫滿,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推進一下

Binlog 日誌

Redo Log 是屬於InnoDB引擎所特有的日誌,而MySQL Server也有自己的日誌,即 Binary log(二進制日誌),簡稱Binlog。Binlog是記錄所有數據庫表結構變更以及表數據修改的二進制日誌,不會記錄SELECT和SHOW這類操作。Binlog日誌是以事件形式記錄,還包含語句所執行的消耗時間。開啓Binlog日誌有以下兩個最重要的使用場景。

  • 主從複製:在主庫中開啓Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog後實現數據恢復達到主從數據一致性。

  • 數據恢復:通過mysqlbinlog工具來恢復數據。

Binlog文件名默認爲“主機名_binlog-序列號”格式,例如oak_binlog-000001,也可以在配置文件中指定名稱。文件記錄模式有STATEMENT、ROW和MIXED三種,具體含義如下。

  • ROW(row-based replication, RBR):日誌中會記錄每一行數據被修改的情況,然後在slave端對相同的數據進行修改。

    優點:能清楚記錄每一個行數據的修改細節,能完全實現主從數據同步和數據的恢復。

    缺點:批量操作,會產生大量的日誌,尤其是alter table會讓日誌暴漲。

  • STATMENT(statement-based replication, SBR):每一條被修改數據的SQL都會記錄到 master的Binlog中,slave在複製的時候SQL進程會解析成和原來master端執行過的相同的 SQL再次執行。簡稱SQL語句複製。

    優點:日誌量小,減少磁盤IO,提升存儲和恢復速度

    缺點:在某些情況下會導致主從數據不一致,比如last_insert_id()、now()等函數。

  • MIXED(mixed-based replication, MBR):以上兩種模式的混合使用,一般會使用 STATEMENT模式保存binlog,對於STATEMENT模式無法複製的操作使用ROW模式保存 binlog,MySQL會根據執行的SQL語句選擇寫入模式。

Binlog文件結構

MySQL的binlog文件中記錄的是對數據庫的各種修改操作,用來表示修改操作的數據結構是Log event。不同的修改操作對應的不同的log event。比較常用的log event有:Query event、Row event、Xid event等。binlog文件的內容就是各種Log event的集合。

Binlog文件中Log event結構如下圖所示:

Binlog寫入機制

  • 根據記錄模式和操作觸發event事件生成log event(事件觸發執行機制)

  • 將事務執行過程中產生log event寫入緩衝區,每個事務線程都有一個緩衝區 Log Event保存在一個binlog_cache_mngr數據結構中,在該結構中有兩個緩衝區,一個是stmt_cache,用於存放不支持事務的信息;另一個是trx_cache,用於存放支持事務的信息。

  • 事務在提交階段會將產生的log event寫入到外部binlog文件中。

  • 不同事務以串行方式將log event寫入binlog文件中,所以一個事務包含的log event信息在 binlog文件中是連續的,中間不會插入其他事務的log event。

Redo Log和Binlog區別

  • Redo Log是屬於InnoDB引擎功能,Binlog是屬於MySQL Server自帶功能,並且是以二進制文件記錄。

  • Redo Log屬於物理日誌,記錄該數據頁更新狀態內容,Binlog是邏輯日誌,記錄更新過程。

  • Redo Log日誌是循環寫,日誌空間大小是固定,Binlog是追加寫入,寫完一個寫下一個,不會覆蓋使用。Redo Log作爲服務器異常宕機後事務數據自動恢復使用,Binlog可以作爲主從複製和數據恢復使用。Binlog沒有自動crash-safe能力。

總結

拉勾老師講解的筆記很詳細,我基本都是從課程上整理下來的,雖然很多概念記不住,但是知道有地方可查,忘了的時候就翻翻,覺得有用的小夥伴趕緊收藏吧


本文分享自微信公衆號 - 程序員愛酸奶(cxyisnai)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章