背景:邏輯備份的全表掃描痛點
Facebook 使用 mysqldump 邏輯備份 TB 級資料。InnoDB 全表掃描按主鍵順序讀取葉子頁,但主鍵頁面碎片化導致物理讀取呈隨機模式,HDD 上隨機讀比順序讀慢 10-100 倍,備份耗時極長。
問題本質:碎片化導致的隨機 I/O
graph LR
Page3[葉子頁 #3] -->|邏輯順序| Page5230[葉子頁 #5230]
Page5230 -->|邏輯順序| Page4[葉子頁 #4]
Page4 -->|邏輯順序| Page5231[葉子頁 #5231]
style Page3 fill:#f9f,stroke:#333
style Page5230 fill:#bbf,stroke:#333
style Page4 fill:#f9f,stroke:#333
style Page5231 fill:#bbf,stroke:#333
- 主鍵
(user_id, object_id) 插入順序非單調 → 頁分裂 → 新頁分配在遠離處
- 邏輯順序 ≠ 物理順序 → 全表掃描變隨機 I/O
- SSD 緩解但成本高,HDD 仍是主流
既有方案局限
| 方案 | 原理 | 局限 |
| Linear Read Ahead | 連續讀 56 頁後預讀 1 extent (64 頁) | Extent 太小,碎片表下一頁不在同 extent |
| Physical Read Ahead (UDF) | 啟動時順序讀整個 .ibd 檔載入 Buffer Pool | 表>Buffer Pool 失效;讀取二級索引頁浪費;需應用修改 |
創新:Logical Read Ahead (LRA) - 邏輯預讀
核心流程
- 讀取 B+ 樹非葉子分支頁,計算葉子頁總數與分佈
- 按頁號順序(接近物理順序)批次預讀葉子頁至 Buffer Pool
- 再按主鍵順序讀取行資料(此时大多在記憶體)
關鍵 Session 變數
-- 控制每次預讀葉子頁數量 (512MB-4GB 對應頁數)
SET SESSION innodb_lra_size = 1073741824; -- 1GB
-- 控制預讀批次間隔,避免佔滿 I/O 頻寬
SET SESSION innodb_lra_sleep = 50000; -- 50ms (微秒)
優於 Physical Read Ahead 的優勢
- 僅預讀主鍵葉子頁,忽略二級索引、系統頁
- 預讀量可控,不超 Buffer Pool
- 零 SQL 語法修改,應用透明
- 僅在需要全表掃描時啟用(mysqldump、pt-online-schema-change 等)
第二優化:批次提交 Async I/O 請求
InnoDB 5.6+ 使用 Linux Native AIO,但每次 io_submit 僅提交 1 頁 (16KB)。修改為批次提交 64 頁 (1MB):
- HDD RAID10 單頁提交:~160 MB/s
- 批次 64 頁提交:>1000 MB/s (6 倍提升)
- Kernel 內部合併相鄰請求,發揮順序讀優勢
基準測試結果
純 HDD 環境全表掃描 (無其他負載)
原版: ~80 MB/s
LRA: ~700 MB/s (9x 提升)
高負載線上 Schema 變更
原版: ~45 MB/s
LRA: ~800 MB/s (18x 提升)
原始碼與部署
- GitHub: facebook/mysql-5.6 (含 LRA diff、批次 AIO diff、mysqldump 啟用 LRA diff)
- 適用 MySQL 5.6/5.7、Percona Server、MariaDB 10.2+
- 編譯部署需內核支援 AIO (libaio)
生產環境最佳實踐
- 備份腳本啟用 LRA:
mysql -e "SET SESSION innodb_lra_size=2G; SET SESSION innodb_lra_sleep=50000;" \
-e "SOURCE /path/to/mysqldump_with_lra.sql"
- 監控指標:
Innodb_buffer_pool_read_ahead、Innodb_buffer_pool_read_ahead_evicted、Innodb_data_read
- 參數調優:大表調大
innodb_lra_size,高併發環境調大 innodb_lra_sleep
- 回滾方案:保留原版 mysqldump,LRA 異常時回退
官方化展望
Facebook 已向 Oracle MySQL、Percona、MariaDB 社群提交 Patch。期待 LRA 成為 InnoDB 核心功能,惠及所有大表全掃描場景:備份、Schema 變更、大表遷移、分析查詢等。
- 上一篇文章: MySQL 效能優化 12 條實戰技巧:從配置到 SQL 改寫
- 下一篇文章: MySQL 安全升級完整指南:跨大版本、邏輯備份遷移與風險控制
Copyright ©
程式碼之家 All Rights Reserved