數據庫做爲存儲系統,全部業務訪問數據的操做都會轉化爲底層數據庫系統的IO行爲(緩存系統也能夠當作是key-value的數據庫),本文主要介紹訪問mysql數據庫的IO流程以及IO相關的參數。
一 MySQL 的文件
首先簡單介紹一下MySQL的數據文件,MySQL 數據庫包含以下幾種文件類型:
數據文件 (datafile) 存放表中的具體數據的文件。
數據字典 記錄數據庫中全部innodb表的信息。
重作日誌 (redolog) 記錄數據庫變動記錄的文件,用於系統異常crash(掉電)後的恢復操做,能夠配置多個好比 ib_logfile0、 ib_logfile1,
回滾日誌 (undolog) 也存在於mysql 的ibdata文件,用戶記錄事務的回滾操做。
歸檔日誌 (binlog) 事務提交以後,記錄到歸檔日誌中。
中繼日誌 (relaylog) 從master 獲取到slave 的中轉日誌文件,sql_thread 則會應用relay log
其餘日誌 slowlolg, errorlog, querylog
對於以上文件的IO訪問順序能夠分爲順序訪問 好比binlog ,redolog ,relay log是順序讀寫,datafile,ibdata file是隨機讀寫,這些IO訪問的特色決定了在os 配置磁盤信息時候,如何考慮分區 ,好比順序寫能夠的log 能夠放到SAS 盤 ,隨機讀寫的數據文件能夠放到ssd 或者fio 高性能的存儲。
二 數據訪問流程
數據庫訪問分爲兩種類型, 一種是讀操做,另一種是寫操做。
1 讀操做
create table t (
id int not null primary key ,
k1 int not null,
data varchar(50),
key ind_k1(k1)
) engine=innodb default charset=utf8;
以 select * from tab where k1=1 ;爲例
圖-1 讀操做的 IO 流程
1 查看緩存中是否存在id,
2 若是有 則從內存中訪問,不然要訪問磁盤,
3 並將索引數據存入內存,利用索引來訪問數據,
4 對於數據也會檢查數據是否存在於內存,
5 若是沒有則訪問磁盤獲取數據,讀入內存。
6 返回結果給用戶。
2 寫操做
爲了保證數據寫入操做的安全性,數據庫系統設置了 undo,redo 保護機制,避免由於os或者數據庫系統異常致使的數據丟失或者不一致的異常狀況發生。
以 insert into t values(1,1,'shuiyi');爲例
![](http://static.javashuo.com/static/loading.gif)
圖-2 寫操做的 IO 流程
咱們假定數據在內存中,不考慮從磁盤中獲取數據的情形。大體的寫操做步驟:
1 先寫undo log
2 在內存更新數據
3 記錄變動到redo log,prepare
4 寫入binlog
5 redo log 第二階段,commit
6 返回給client
若是有slave
第4步以後 通過slave 服務線程 io_thread 寫到從庫的relay log ,再由sql thread 應用relay log 到從庫中。
關於性能
寫undo redo log ,binlog的過程當中都是順序寫,都會很快的完成,隨機寫操做,inset_buffer 功能
對於非彙集類索引的插入和更新操做(5.5 版本及以上支持Update/Delete/Purge等操做的buffer功能),不是每一次都直接插入到索引頁中,而是先插入到內存中。具體作法是:若是該索引頁在緩衝池中,直接插入;不然,先將其放入插入緩衝區中,再以必定的頻率和索引頁合併,就能夠將同一個索引頁中的多個插入合併到一個IO操做中,改隨機寫爲順序寫,大大提升寫性能。
關於數據安全,這是數據庫寫入的重點
1,2,3 過程失敗 就是事務失敗,由於此時還未寫入磁盤,對磁盤中的數據無影響,返回事務失敗給client,從庫也不會受到影響。
4,5 過程失敗的時候或者已經將寫成功返回給客戶,能夠根據redo log 的記錄來進行恢復,若是出現部分寫失效 請參考《double write》
mysql的寫redo log的第一個階段會把全部須要作的操做作完,記錄數據變動,第二階段的工做比較簡單 ,只作事務提交確認。若是寫入binlog 成功,而第二階段失敗,mysql 啓動時也會將事務進行重作,最終更新到磁盤中。
5.5 +的 smei sync
能夠更好的保障主從的事務一致性。
三 文件訪問方式
IO 訪問的方式分爲兩種順序讀寫和隨機讀寫, 在mysql 的io過程當中能夠以此來將數據庫文件分類
順序讀寫:
重作日誌 ib_logfile*,binlog file
隨機讀寫
innodb 表數據文件,ibdata文件。
根據系統的訪問類型,對硬件作以下分類
讀多 SSD+RAID
寫多 FIO(flashcache)
容量密集 fio + flashcache
因爲隨機io會嚴重下降系統的性能,在當前的硬件水平下,能夠考慮選擇獎數據庫服務器配置ssd/fusionio。
四 影響IO的參數和策略
影響mysql io 的參數有不少個,這裏羅列幾個重要的參數。
innodb_buffer_pool_size
該參數控制innodb 緩存大小,用於緩存應用訪問的數據,推薦配置爲系統可用內存的80%。
binlog_cache_size
該參數控制二進制日誌緩衝大小,當事務尚未提交時,事務日誌存放於cache,當遇到大事務cache不夠用的時,mysql會把uncommitted的部分寫入臨時文件,等到committed的時候纔會寫入正式的持久化日誌文件。
innodb_max_dirty_pages_pct
該參數能夠直接控制Dirty Page在BP中所佔的比率,當dirty page 達到了該參數的閾值,就會觸發MySQL 系統刷新數據到磁盤
innodb_flush_log_at_trx_commit
該參數肯定日誌文件什麼時候write、flush。
爲0,log buffer將每秒一次地寫入log file中,而且log file的flush(刷到磁盤)操做同時進行.該模式下,在事務提交的時候,不會主動觸發寫入磁盤的操做。
爲1,每次事務提交時MySQL都會把log buffer的數據寫入log file,而且flush(刷到磁盤)中去.
爲2,每次事務提交時MySQL都會把log buffer的數據寫入log file.可是flush(刷到磁盤)操做並不會同時進行。該模式下,MySQL會每秒執行一次 flush(刷到磁盤)操做。
注意:
因爲進程調度策略問題,這個「每秒執行一次 flush(刷到磁盤)操做」並非保證100%的「每秒」。
sync_binlog
sync_binlog 的默認值是0,像操做系統刷其餘文件的機制同樣,MySQL不會同步到磁盤中去而是依賴操做系統來刷新binary log。
當sync_binlog =N (N>0) ,MySQL 在每寫 N次 二進制日誌binary log時,會使用fdatasync()函數將它的寫二進制日誌binary log同步到磁盤中去。
innodb_flush_method
該參數控制日誌或數據文件如何write、flush。可選的值爲 fsync, o_dsync ,o_direct,littlesync,nosync
fdatasync 模式:寫數據時,write這一步並不須要真正寫到磁盤纔算完成(可能寫入到操做系統buffer中就會返回完成),真正完成是flush操做,buffer交給操做系統去flush,而且文件的元數據信息也都須要更新到磁盤。
O_DSYNC 模式:寫日誌操做是在write這步完成,而數據文件的寫入是在flush這步經過fsync完成
O_DIRECT模式:數據文件的寫入操做是直接從mysql innodb buffer到磁盤的,並不用經過操做系統的緩衝,而真正的完成也是在flush這步,日誌仍是要通過OS緩衝
注意:關於mysql 和io相關的參數,並非一成不變的,須要根據自身業務系統和硬件系統作相應調整,系統上線以前,測試出一個最佳值。
五 小結
數據庫的io是一個很複雜和細緻的知識層面,涉及數據庫層和OS層面的IO寫入策略,也和硬件的配置有關,本文主要針對MySQL 層面作分析,可能分析的不夠全面,請各位朋友指點。
六 參考文檔