MySQL IO執行緒及相關引數調優
阿新 • • 發佈:2018-12-26
一、關於一個SQL的簡單的工作過程
1、工作前提描述
1、啟動MySQL,在記憶體中分配一個大空間innodb_buffer_pool(還有log_buffer)
2、多使用者執行緒連線MySQL,從記憶體分配使用者工作空間(其中排序空間)
3、磁碟上有資料庫檔案、ib_logfile、tmp目錄、undo
2、SQL的簡易流程
1、DQL操作
1、首先進行記憶體讀
2、如果buffer pool中沒有所需資料,就進行物理讀
3、物理讀資料讀入buffer pool,再返回給使用者工作空間
2、DML操作(例update)
1、記憶體讀,然後進行物理讀,讀取所需修改的資料行
2、從磁碟調入undo頁到buffer pool中
3、修改前的資料存入undo頁裡,產生redo
4、修改資料行(buffer pool中資料頁成髒頁),產生redo
5、生成的redo先是存於使用者工作空間,擇機拷入log_buffer中
6、log執行緒不斷的將log_buffer中的記錄寫入redo logfile中
7、修改完所有資料行,提交事務,刻意再觸發一下log執行緒
8、待log_buffer中的相關資訊都寫完,響應事務提交成功
至此,日誌寫入磁碟,記憶體髒塊還在buffer pool中(後臺週期寫入磁碟,釋放buffer pool空間)。
二、影響SQL執行效能的因素,及具體看方式
1、大量物理讀
1、Innodb_buffer_pool_reads:物理讀次數
2、Innodb_data_read:物理讀資料位元組量
3、Innodb_data_reads:物理讀IO請求次數
4、Innodb_pages_read:物理讀資料頁數
5、Innodb_rows_read:物理讀資料行數
2、Log寫效能
mysql> show global status like 'i%read%';
| Innodb_buffer_pool_reads | 647 |
| Innodb_data_read | 48402944 |
| Innodb_data_reads | 2996 |
| Innodb_pages_read | 2949 |
| Innodb_rows_read | 1002172 |
mysql> show engine innodb status \G --- LOG --- Log sequence number 144064129 //已經生成的日誌量(累計值)/單位:位元組 Log flushed up to 144064129 //已經寫入的日誌量(累計值) Pages flushed up to 144064129 //已經寫入的髒頁量(累計值) Last checkpoint at 144064120 //檢查點關於redo log的寫入: 1、Innodb_os_log_written: 日誌刷盤的位元組數, 如果在commit不怎麼變化的情況下,這個值出現暴增,說明系統出現大事務了(處理:kill執行緒,必要情況kill掉mysql程序); 2、Innodb_log_writes:日誌寫的次數。 3、 磁碟排序0 pending log flushes, 0 pending chkp writes 92 log i/o's done, 0.00 log i/o's/second
mysql> show status like 'Sort_merge_passes';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Sort_merge_passes | 0 |
+-------------------+-------+
1 row in set (0.00 sec)
使用者所需資料,如果沒有記憶體buffer pool中,就發生物理讀;
如果需要過濾掉很多資料,就會影響物理讀和記憶體讀,因為返回很多的資料(物理讀),在記憶體中需要過濾掉很多資料(記憶體讀);
如果涉及到group/order by,會在使用者工作空間完成排序等,如果結果集過大,使用者空間過小,進行磁碟排序,Sort_merge_passes>0 ,這就很影響資料庫效能了。
三、MySQL執行緒及其工作 MySQL的工作機制是單程序多執行緒:IO執行緒=一個log執行緒+四個read執行緒+四個write執行緒mysql> show engine innodb status \G
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
1、讀操作:innodb_read_io_threads
1、發起者:使用者執行緒發起讀請求
2、完成者:讀執行緒執行請求佇列中的讀請求操作
3、如何調整讀執行緒的數量
mysql> show variables like 'innodb_read_io_threads';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_read_io_threads | 4 |
+------------------------+-------+
1 row in set (0.01 sec)
預設是開啟4個讀執行緒,靜態引數,修改至配置檔案中
4、
如何確定是否需要增加讀執行緒的數量
檢視執行緒的狀態:I/O thread 2 state: waiting for i/o request (read thread)
2、寫操作:innodb_write_io_threads
1、發起者:page_cleaner執行緒發起
2、完成者:寫執行緒執行請求佇列中的寫請求操作
3、如何調整寫執行緒的數量
mysql> show variables like 'innodb_write_io_threads';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_write_io_threads | 4 |
+-------------------------+-------+
1 row in set (0.01 sec)
預設是開啟4個寫執行緒,靜態引數,修改至配置檔案中
4、
如何確定是否需要增加寫執行緒的數量
檢視執行緒的狀態:I/O thread 6 state: waiting for i/o request (write thread)
3、日誌執行緒 3.1、只有一個日誌執行緒 1、是否繁忙 I/O thread 1 state: waiting for i/o request (log thread):閒 2、日誌寫效能關於innodb_purge_threads:page cleaner 執行緒
作用:1、負責對 undo 資料頁的清空
2、資料頁中 delete 標誌行的清除
3、清理 innodb buffer pool,負責把記憶體中的髒頁發起寫請求,write 執行緒負載把髒頁重新整理到磁碟上。
mysql> show global status like 'Innodb_log_waits';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| Innodb_log_waits | 0 |
+------------------+-------+
1 row in set (0.00 sec)
如果log buffer太小,就很容易滿,導致無法寫入,產生日誌等待。
3、日誌寫壓力 1、每秒吞吐量mysql> show global status like 'Innodb_os_log_written'; #redo log寫的位元組數
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Innodb_os_log_written | 57856 |
+-----------------------+-------+
1 row in set (0.01 sec)
2、每秒寫入次數
mysql> show global status like 'Innodb_log_writes';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Innodb_log_writes | 59 |
+-------------------+-------+
1 row in set (0.01 sec)
3.2、對於日誌監控來說,三個經典引數
1、Innodb_log_waits #redo寫入的等待次數
2、Innodb_log_writes #redo寫入的次數
3、Innodb_os_log_written #寫入redo logfile中的位元組量
3.3、日誌寫入異常判斷
mysql> show engine innodb status \G1、fsync:繞過檔案系統快取,直接將記憶體中的資料寫入儲存中,實現資料真正寫入可靠的介質磁盤裡。(對於redo log來說,通過fsync方式寫入磁碟才是可靠的保證,因為寫入檔案系統快取的提交成功響應並不是真正的將redo寫入磁碟的logfile中)(sync:同步) 2、pending:掛起(寫不動),redo寫入儲存cache過程中,某種原因io繁忙,cache被佔滿,超時響應,就會被掛起; 3、>0就說明系統IO出現問題,=0說明is OK。 四、log buffer調整依據 log buffer:日誌快取,一般都很小,調整100M足夠使用
Pending flushes (fsync) log: 0;
mysql> show global status like 'Innodb_os_log_pending_fsyncs'; +------------------------------+-------+ | Variable_name | Value | +------------------------------+-------+ | Innodb_os_log_pending_fsyncs | 0 | +------------------------------+-------+ 1 row in set (0.00 sec)
mysql> show variables like "%log_buffer%"; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+5.7預設是16M,5.6預設是8M 1、檔案中(log file):每次寫的時候全域性都寫,不會挑著撿著寫 1、日誌寫執行緒每一秒redo日誌緩衝重新整理到重做日誌檔案 2、每個事務提交時會將重做日誌緩衝重新整理到重做日誌檔案 3、每當重做日誌緩衝池剩餘空間小於1/2時,重做日誌緩衝重新整理到重做日誌檔案。 2、在企業中往往設定50-100M,最多設定為2、300M,調整依據: 1、記憶體空間足夠大 2、日誌產生量大,系統io阻塞了,系統的io佔用的是一個頻寬,log_writes執行緒被阻塞,log buffer滿了,資料庫會hang住。 3、 Innodb_log_waits(狀態值) The number of times that the log buffer was too small and a wait was required for it to be flushed before continuing.