首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL InnoDB 存儲引擎深度解析:文件 IO 子系統架構與原理

     編輯:MySQL 綜合教學

MySQL InnoDB 存儲引擎深度解析:文件 IO 子系統架構與原理

InnoDB 作為 MySQL 預設的交易型存儲引擎,其文件 IO 子系統是效能的關鍵。本文基於 MySQL 5.6 源碼結構,深入剖析 os_file.*(底層 IO 抽象與非同步實現)與 fil0fil.*(表空間管理與 IO 調度)兩大核心模組,並說明 Native AIO、模擬 AIO 與 Direct I/O 的演進邏輯。

1. 底層系統文件 IO 封裝(os_file.*)

InnoDB 封裝了跨平台的基本文件操作,統一介面如下:

函數功能
os_file_create_simple建立/開啟檔案(不重試)
os_file_create建立/開啟檔案(失敗重試至成功)
os_file_close關閉檔案
os_file_read / os_file_write讀/寫資料(Linux 預用 pread/pwrite,無則退回 lseek+read/write)
os_file_flushfsync 強制落盤
os_file_get_size / os_file_set_size取得/設定檔案大小

2. 非同步 IO (AIO) 實現

為避免同步 IO 阻塞工作執行緒,InnoDB 實作了自己的 AIO 框架:

  • Windows:使用 IOCP (I/O Completion Port)。
  • Linux:
    • Native AIO (libaio):核心支援 io_setup/io_submit/io_getevents,效能最佳。
    • 模擬 AIO:若核心不支援或未啟用,啟動專用的 os_aio_handler_thread 執行緒池,以 pthread_cond 模擬完成通知。

核心資料結構

/* 單一 IO 槽位 */
struct os_aio_slot_t {
    bool is_read;           // 讀/寫
    ulint pos;              // 陣列索引
    bool reserved;          // 是否被佔用
    ulint len;              // 傳輸長度
    byte *buf;              // 資料緩衝區
    ulint type;             // OS_FILE_READ / OS_FILE_WRITE
    ulint offset, offset_high; // 檔案偏移 (64-bit)
    os_file_t file;         // 檔案控制代碼
    char *name;             // 檔案名 (除錯用)
    bool io_already_done;   // 模擬 AIO 用
    #ifdef POSIX_ASYNC_IO
    struct aiocb control;   // POSIX AIO 控制塊
    #endif
};

/* IO 槽位陣列 (分段管理) */
struct os_aio_array_t {
    os_mutex_t mutex;           // 保護陣列
    os_event_t not_full;        // 有空槽位訊號
    os_event_t is_empty;        // 陣列空訊號
    ulint n_slots;              // 總槽位數
    ulint n_segments;           // 區段數 (每區段對應一組 handler thread)
    ulint n_reserved;           // 已使用槽位數
    os_aio_slot_t *slots;       // 槽位陣列
    os_event_t *events;         // 事件陣列
};

AIO 記憶體結構關係圖

3. 表空間與文件管理(fil0fil.*)

InnoDB 定義三層管理結構:

  • fil_system_t:全域單例,管理所有表空間、開啟檔案數限制、LRU 列表(最近使用檔案,避免頻繁開關)。
  • fil_space_t:表空間邏輯單位(如 ibdata1、ib_logfile*、ibtmp*),對應 space_id,含雜湊索引、RW-Latch、Insert Buffer 指標等。
  • fil_node_t:單一物理檔案(.ibd 或 ibdata 分檔),管理檔案控制代碼、頁數、髒頁標記、LRU 節點。

關鍵結構體片段

struct fil_system_t {
    mutex_t mutex;
    hash_table_t *spaces;        // space_id -> fil_space_t
    ulint n_open_pending;        // 正在進行 IO 的檔案數
    ulint max_n_open;            // 最大開啟檔案數 (預設 500)
    os_event_t can_open;         // 可開啟新檔案訊號
    UT_LIST_BASE_NODE_T(fil_node_t) LRU;       // 最近使用檔案
    UT_LIST_BASE_NODE_T(fil_node_t) space_list;// 所有 fil_node 串聯
};

struct fil_space_t {
    char *name;
    ulint id;                    // space_id
    ulint purpose;               // FIL_TABLESPACE / FIL_LOG / FIL_ARCH_LOG
    ulint size;                  // 頁數
    rw_lock_t latch;             // 並發保護
    ibuf_data_t *ibuf_data;      // Insert Buffer
    UT_LIST_BASE_NODE_T(fil_node_t) chain; // 屬於此 space 的檔案鏈
};

struct fil_node_t {
    char *name;                  // 檔案路徑
    bool open;                   // 是否開啟
    os_file_t handle;            // 檔案控制代碼
    ulint size;                  // 頁數 (16KB/page)
    ulint n_pending;             // 排隊 IO 數
    bool is_modified;            // 有髒頁待刷盤
    UT_LIST_NODE_T(fil_node_t) chain;
    UT_LIST_NODE_T(fil_node_t) LRU;
};

fil_system/space/node 記憶體關係圖

4. IO 提交與調度流程

  1. 上層呼叫 fil_io(),判斷 IO 類型與檔案開啟模式。
  2. 檢查 n_open_pending:若超過 max_n_open * 3/4 喚醒所有 AIO handler 處理並 sleep;若達 max_n_open 等待 can_open 訊號。
  3. 定位 fil_space_t 與 fil_node_t,若檔案未開啟則開啟(LRU 滿時淘汰尾部節點關檔)。
  4. 提交至 os_aio 執行非同步 IO,等待完成。
  5. 完成後將節點移至 LRU 首部,更新狀態,發送 can_open 訊號喚醒等待者。

IO 提交流程圖

5. MySQL 5.6 引入 Direct I/O (O_DIRECT)

繞過作業系統頁面快取,直接在使用者空間緩衝區與磁碟間傳輸,減少記憶體拷貝與快取污染。InnoDB 透過 os_file_create 以 O_DIRECT 旗標開啟資料檔,Redo Log 預設仍用緩衝 IO(可由 innodb_flush_log_at_trx_commit 控制)。Oracle、OceanBase 等亦廣泛採用此技術。

6. 總結與學習建議

InnoDB IO 子系統涉及作業系統 IO 模型、鎖同步、記憶體管理、LRU 淘汰等核心技術。建議:

  • 閱讀源碼時搭配 gdb 或 perf 做單元測試驗證呼叫鏈。
  • 重點掌握 fil_io() → os_aio → handler thread 完整路徑。
  • 關注 innodb_use_native_aio、innodb_max_dirty_pages_pct、innodb_io_capacity 等參數對 IO 調度的影響。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved