mysql的"雙1驗證"指的是innodb_flush_log_at_trx_commit和sync_binlog兩個參數設置,這兩個是是控制MySQL 磁盤寫入策略以及數據安全性的關鍵參數。下面從參數含義,性能,安全角度闡述兩個參數爲不一樣的值時對db 性能,數據的影響。mysql
1、參數意義ios
innodb_flush_log_at_trx_commit
若是innodb_flush_log_at_trx_commit設置爲0:log buffer將每秒一次地寫入log file中,而且log file的flush(刷到磁盤)操做同時進行.該模式下,在事務提交的時候,不會主動觸發寫入磁盤的操做;
若是innodb_flush_log_at_trx_commit設置爲1:每次事務提交時MySQL都會把log buffer的數據寫入log file,而且flush(刷到磁盤)中去;
若是innodb_flush_log_at_trx_commit設置爲2:每次事務提交時MySQL都會把log buffer的數據寫入log file,可是flush(刷到磁盤)操做並不會同時進行。該模式下,MySQL會每秒執行一次 flush(刷到磁盤)操做。sql
注意:因爲進程調度策略問題,這個"每秒執行一次 flush(刷到磁盤)操做"並非保證100%的"每秒"。數據庫
sync_binlog
sync_binlog 的默認值是0,像操做系統刷其餘文件的機制同樣,MySQL不會同步到磁盤中去而是依賴操做系統來刷新binary log。
當sync_binlog =N (N>0) ,MySQL 在每寫 N次 二進制日誌binary log時,會使用fdatasync()函數將它的寫二進制日誌binary log同步到磁盤中去。緩存
注意:若是啓用了autocommit,那麼每個語句statement就會有一次寫操做;不然每一個事務對應一個寫操做。安全
2、性能服務器
兩個參數在不一樣值時對db的純寫入的影響表現以下:
測試場景1
innodb_flush_log_at_trx_commit=2
sync_binlog=1000app
測試場景2
innodb_flush_log_at_trx_commit=1
sync_binlog=1000async
測試場景3
innodb_flush_log_at_trx_commit=1
sync_binlog=1函數
測試場景4
innodb_flush_log_at_trx_commit=1
sync_binlog=1000
測試場景5
innodb_flush_log_at_trx_commit=2
sync_binlog=1000
在以上5個場景下的TPS分別爲:
場景1 41000
場景2 33000
場景3 26000
場景4 33000
因而可知,當兩個參數設置爲雙1的時候,寫入性能最差,sync_binlog=N (N>1 ) innodb_flush_log_at_trx_commit=2 時,(在當前模式下)MySQL的寫操做才能達到最高性能。
3、安全
當innodb_flush_log_at_trx_commit和sync_binlog 都爲 1 時是最安全的,在mysqld 服務崩潰或者服務器主機crash的狀況下,binary log 只有可能丟失最多一個語句或者一個事務。可是魚與熊掌不可兼得,雙11 會致使頻繁的io操做,所以該模式也是最慢的一種方式。
當innodb_flush_log_at_trx_commit設置爲0,mysqld進程的崩潰會致使上一秒鐘全部事務數據的丟失。
當innodb_flush_log_at_trx_commit設置爲2,只有在操做系統崩潰或者系統掉電的狀況下,上一秒鐘全部事務數據纔可能丟失。
"雙1設置"適合數據安全性要求很是高,並且磁盤IO寫能力足夠支持業務,好比訂單,交易,充值,支付消費系統。雙1模式下,當磁盤IO沒法知足業務需求時 好比11.11 活動的壓力。推薦的作法是 innodb_flush_log_at_trx_commit=2 ,sync_binlog=N (N爲500 或1000) 且使用帶蓄電池後備電源的緩存cache,防止系統斷電異常。
4、小結
系統性能和數據安全是業務系統高可用穩定的必要因素。咱們在對系統的優化須要尋找一個平衡點,合適的纔是最好的,根據不一樣的業務場景需求,能夠將兩個參數作組合調整,以即是db系統的性能達到最優化。
案例分享1:一條insert語句的執行,耗時40ms緣由剖析
背景:一個簡單的帶有主鍵的insert語句,執行起來竟然要耗時40ms ,實在是難以忍受!排查分析過程以下:
所以須要關注的是數據從插入落地的IO中間都幹了什麼?
1、MySQL的文件
首先簡單介紹一下MySQL的數據文件,MySQL 數據庫包含以下幾種文件類型:
1)數據文件 (datafile)
存放表中的具體數據的文件。
2)數據字典
記錄數據庫中全部innodb表的信息。
3)重作日誌 (redolog)
記錄數據庫變動記錄的文件,用於系統異常crash(掉電)後的恢復操做,能夠配置多個(配置這個參數inodb_log_files_in_group)好比 ib_logfile0、 ib_logfile1。
4)回滾日誌 (undolog)
也存在於mysql 的ibdata文件,用戶記錄事務的回滾操做。注在mysql5.6以上版本能夠拆開出來,單獨文件夾存在。
5)歸檔日誌 (binlog)
事務提交以後,記錄到歸檔日誌中。
6)中繼日誌 (relaylog)
從master獲取到slave的中轉日誌文件,sql_thread則會應用relay log並重放於從機器。
7)其餘日誌slowlolg, errorlog, querylog
這裏慢日誌也常常用。能夠結合pt-query-digest工具和anemometer一塊兒展現出來。
對於以上文件的IO訪問順序能夠分爲順序訪問 好比binlog ,redolog ,relay log是順序讀寫,datafile,ibdata file是隨機讀寫,這些IO訪問的特色決定了在os 配置磁盤信息時候,如何考慮分區 ,好比順序寫能夠的log能夠放到SAS盤 ,隨機讀寫的數據文件能夠放到ssd或者fio高性能的存儲。
2、寫操做
爲了保證數據寫入操做的安全性,數據庫系統設置了 undo,redo 保護機制,避免由於os或者數據庫系統異常致使的數據丟失或者不一致的異常狀況發生。
1)先寫undo log。
2)在內存更新數據,這步操做就在內存中造成了髒頁,若是髒頁過多,checkpoint機制進行刷新,innodb_max_dirty_pages_pct決定了刷新髒頁比例。innodb_io_capacity參數能夠動態調整刷新髒頁的數量,innodb_lru_scan_depth這個參數決定了刷新每一個innodb_buffer_pool的髒頁數量。
3)記錄變動到redo log,prepare這裏會寫事務id。innodb_flush_log_at_trx_commit決定了事務的刷盤方式。爲0時,log buffer將每秒一次地寫入log file中,而且log file的flush(刷到磁盤)操做同時進行。該模式下,在事務提交的時候,不會主動觸發寫入磁盤的操做。爲1,每次事務提交時MySQL都會把log buffer的數據寫入log file,而且flush(刷到磁盤)中去.爲2,每次事務提交時MySQL都會把log buffer的數據寫入log file.可是flush(刷到磁盤)操做並不會同時進行。該模式下,MySQL會每秒執行一次 flush(刷到磁盤)操做。
4)寫入binlog這裏會寫入一個事務id這裏有個sync_binlog參數決定多個事務進行一次性提交。
5)redo log第二階段,這裏會進行判斷前2步是否成功,成功則默認commit,不然rollback。刷入磁盤操做。這裏是先從髒頁數據刷入到內存2M大小的doublewrite buffer,而後是一次性從內存的doublewrite buffer刷新到共享表空間的doublewrite buffer,這裏產生了一次IO。而後從內存的內存的doublewrite buffer刷新2m數據到磁盤的ibd文件中,這裏須要發生128次io。而後校驗,若是不一致,就由共享表空間的副本進行修復。這裏有個參數innodb_flush_method決定了數據刷新直接刷新到磁盤,繞過os cache。
6)返回給client。
若是有slave,第4步以後通過slave服務線程io_thread寫到從庫的relay log ,再由sql thread應用relay log到從庫中。
3、關於性能
寫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啓動時也會將事務進行重作,最終更新到磁盤中。MySQL 5.5+的smei sync能夠更好的保障主從的事務一致性。
4、文件訪問方式
IO 訪問的方式分爲兩種順序讀寫和隨機讀寫, 在MySQL的io過程當中能夠以此來將數據庫文件分類。
順序讀寫:重作日誌ib_logfile*,binlog file。
隨機讀寫:innodb表數據文件,ibdata文件。
根據系統的訪問類型,對硬件作以下分類:讀多(SSD+RAID)、寫多FIO(flashcache)、容量密集(fio + flashcache)。
因爲隨機io會嚴重下降系統的性能,在當前的硬件水平下,能夠考慮選擇獎數據庫服務器配置ssd/fusionio。
5、影響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。
數據庫的I/O是一個很複雜和細緻的知識層面,涉及數據庫層和OS層面的IO寫入策略,也和硬件的配置有關。
案例分享2: 同一條sql語句,有時插入塊,有時插入慢緣由剖析
背景:同一條sql ,有時插入時間幾毫秒,有時插入時間倒是幾十毫秒!爲何呢? 分析過程以下:
Sql角度:簡單insert
表角度: 一個主鍵
系統參數角度:
開啓了雙1 策略。
也就意味着每次事物就會有刷新磁盤
關閉雙1 ,設置爲 0 100 ,或者 2 100 ,會極大提高性能。這是由於不刷硬盤了,但不能解決爲何時快時慢問題。
操做系統角度
使用"iostat -xmd 1"命令看磁盤使用狀況
以上看出磁盤明顯不夠快,讀寫0.15M就使用了7%
上面能夠看出,來個順序文件拷貝操做,30M使用就使用了100%,離散讀寫更慢了!
使用"sar -B 1"命令能夠查看頁面交換
pgpgin/s: 表示每秒從磁盤或SWAP置換到內存的字節數(KB)
pgpgout/s: 表示每秒從內存置換到磁盤或SWAP的字節數(KB)
fault/s: 每秒鐘系統產生的缺頁數,即主缺頁與次缺頁之和(major + minor)
majflt/s: 每秒鐘產生的主缺頁數.
pgfree/s: 每秒被放入空閒隊列中的頁個數
pgscank/s: 每秒被kswapd掃描的頁個數
pgscand/s: 每秒直接被掃描的頁個數
pgsteal/s: 每秒鐘從cache中被清除來知足內存須要的頁個數
%vmeff: 每秒清除的頁(pgsteal)佔總掃描頁(pgscank+pgscand)的百分比
以上表示內存和swap進行了頻繁的數據交換!
那個進程在使用swap呢?
下面截圖中命令是for i in $(ls /proc | grep "^[0-9]" | awk '$0>100'); do awk '/Swap:/{a=a+$2}END{print '"$i"',a/1024"M"}' /proc/$i/smaps;done| sort -k2nr | head
在通過幾個小時後 ,mysql 使用swap由88M變成了104M ,這說明一直在使用和增長的。
問題基本定位
1)首先是磁盤性能不高,順序寫才30M ,離散寫會下降10倍
2)其次是mysql又使用了swap 空間,這就使得性能更差
3) Mysql 開啓了雙1 驗證,就會等待數據刷磁盤,
磁盤使用頻率不穩定,致使了mysql的插入時間會時快時慢
如何解決?
1)減小mysql使用swap方式。即把swapness設置爲1。
即執行"sysctl vm.swappiness=1",而且在/etc/sysctl.conf文件中也要設置爲1;
2)下降內存,好比設置innodb_buffer_pool_size =4G,原來設置的是6G ,這樣能夠節約一部份內存空間;
3)開啓innodb_numa_interleave = ON 來操做numa;
4)更換SSD 或者不用開啓雙1,改爲 2 100
只調整操做系統參數,不更換硬件,依然開啓雙一,重啓mysql以後呢?
能夠看到mysql已經再也不使用swap空間了。可是由於雙一參數的使用,每次事物都會刷磁盤,而這個機械磁盤的性能在隨機讀寫的狀況下不穩定。會依然存在時快時慢的問題。