MySQL5.6.12的Innodb效能改進
簡單的記錄下,在MySQL5.6.12中innodb層的3點跟效能相關的改進
1.在檔案操作部分,移除了許多sleep操作,而是改用condition wait
對應的bug http://bugs.mysql.com/bug.php?id=68588。 在Mark的測試中,有近一倍的效能提升
主要修改都幾種在函式fil_flush中:
每個檔案結構體node都增加了一個event:
fil_node_create: node->sync_event = os_event_create(); fil_node_free: os_event_free(node->sync_event)
fil_flush:
當檔案上已經有執行緒在做flush時:
5638 if (node->n_pending_flushes > 0) { 5639 /* We want to avoid calling os_file_flush() on 5640 the file twice at the same time, because we do 5641 not know what bugs OS`s may contain in file 5642 i/o */ 5643 5644 ib_int64_t sig_count = 5645 os_event_reset(node->sync_event); 5646 5647 mutex_exit(&fil_system->mutex); 5648 5649 os_event_wait_low(node->sync_event, sig_count); 5650 5651 mutex_enter(&fil_system->mutex); 5652 5653 if (node->flush_counter >= old_mod_counter) { 5654 5655 goto skip_flush; 5656 } 5657 5658 goto retry; 5659 } 5661 ut_a(node->open); 5662 file = node->handle; 5663 node->n_pending_flushes++; 5664 5665 mutex_exit(&fil_system->mutex); 5666 5667 os_file_flush(file); 5668 5669 mutex_enter(&fil_system->mutex); 5670 5671 os_event_set(node->sync_event); 5672 5673 node->n_pending_flushes--;
好吧,我承認我摘錄上述程式碼的目的,只是簡單記錄下innodb condition wait的用法…
2.使用者執行緒在查詢空閒block,會刷單個page,這可能導致sync所有的檔案
使用者執行緒做了single page flush後,加入一個IO非同步請求佇列後,會呼叫buf_flush_sync_datafiles.隨後會喚醒IO執行緒,並在之後fsync所有的資料檔案。
該bzr主要修改包括:
* 所有batch flush操作非同步進行(和以前一樣)
buf_dblwr_flush_buffered_writes:
914 for (ulint i = 0; i < first_free; i++) {
915 buf_dblwr_write_block_to_datafile(
916 buf_dblwr->buf_block_arr[i], false); // false表示非同步寫
917 }
* single page flush以尋找一個空閒塊,這是同步操作
buf_flush_single_page_from_LRU->buf_flush_page->buf_flush_write_block_low->buf_dblwr_write_single_page
1130 /* We know that the write has been flushed to disk now
1131 and during recovery we will find it in the doublewrite buffer
1132 blocks. Next do the write to the intended position. */
1133 buf_dblwr_write_block_to_datafile(bpage, sync); //該backtrace的sync為TRUE
buf_flush_page在多處被呼叫到,其增加了一個sync引數,用於表示該page flush操作需要同步還是非同步進行。而在5.6.11中會在呼叫buf_flush_page後呼叫buf_flush_sync_datafiles()來sync所有的資料檔案。
另外,有一種情況,在做SINGLE PAGE FLUSH時,採用非同步的方式,backtrace如下:
row_import_for_mysql->buf_LRU_remove_pages->buf_flush_dirty_pages->buf_flush_or_remove_pages->buf_flush_page
這其實就是5.6的新特性ibd import功能的backtrace,後面單獨開篇介紹
* 將single page flush的dblwr slot處理轉移到IO執行緒
函式:buf_dblwr_update
當IO操作完成寫一個page後,這個函式會被呼叫到,在5.6.12中會做兩件事兒:
對於batch flush操作(BUF_FLUSH_LIST 或者BUF_FLUSH_LRU),當預留給batch flush的slot都全部完成重新整理後(buf_dblwr->b_reserved = 0),會去sync資料檔案(fil_flush_file_spaces(FIL_TABLESPACE)),將batch_running設為false,併傳送完成訊號
對於single page flush操作,找到當前page的slot,然後將其設定為未使用(in_use[i] = false),隨後傳送condition 訊號(buf_dblwr->s_event)
這裡採用順序遍歷,來尋找當前page的slot,是否存在效率問題?
而在5.6.11版本中,只考慮了batch flush操作。
* 移除對dblwr buffer中的sleep,改用condition wait
寫double write buffer時,如果已經在刷dblwr,以前是sleep 10ms,現在改成condition wait了,這裡包括batch flush 和single page flush,這兩者都增加了條件變數
當髒頁重新整理非常頻繁時,會看到很明顯的效能提升
*其他
另外一個沒提到的修改是函式buf_flush_LRU_tail
在5.6.11的版本中,並沒有對buf_flush_LRU的返回值進行處理。而在5.6.12中,增加了如下邏輯:
2092 for (ulint j = 0; 2093 j < scan_depth; 2094 j += PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE) { 2095 2096 ulint n_flushed = 0; 2097 2098 /* Currently page_cleaner is the only thread 2099 that can trigger an LRU flush. It is possible 2100 that a batch triggered during last iteration is 2101 still running, */ 2102 if (buf_flush_LRU(buf_pool, 2103 PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE, 2104 &n_flushed)) { 2105 2106 /* Allowed only one batch per 2107 buffer pool instance. */ 2108 buf_flush_wait_batch_end( 2109 buf_pool, BUF_FLUSH_LRU); 2110 } 2111 2112 if (n_flushed) { 2113 total_flushed += n_flushed; 2114 } else { 2115 /* Nothing to flush */ 2116 break; 2117 } 2118 }
3.優化batch flush的效率,之前的時間複雜度為O(N*N)
每個buffer pool例項增加了一個新的變數:
const buf_page_t* flush_list_hp;/*!< “hazard pointer”
used during scan of flush_list
while doing flush list batch.
Protected by flush_list_mutex */
根據註釋,其在批量重新整理時使用,用flush_list_mutex 來保護
buf_flush_set_hp :設定flush_list_hp指標,指向引數傳遞的page
buf_flush_update_hp:當flush_list上的block移除或者移動時,需要檢查buf_flush_set_hp指標是否被其他正在掃描flush list的執行緒設定,如果flush_list_hp指向我們下一個將要掃描的page,則將其設定為NULL,表示需要重新掃描
有兩個地方會呼叫到這個函式:
* 從flush list上移除一個page的時候(buf_flush_remove)
* 為flush list上的一個page重分配控制塊,buf_flush_relocate_on_flush_list
buf_do_flush_list_batch:
在該函式的修改是核心部分,主要消除了在bug#69170中描述的o(n*n)的時間複雜度。所有作用於flush list的執行緒,都需要先檢查flush_list_hp指標,
這裡的方法很簡單,從flush list的尾部開始掃描, 每次獲取一個page後,將bp->flush_list_hp的指標指向該page的前一個, 然後釋放bp->flush_list_mutex
然後執行該page的重新整理
flushed = buf_flush_page_and_try_neighbors(
bpage, BUF_FLUSH_LIST, min_n, &count);
再次持有flush_list_mutex鎖,檢視bp->flush_list_hp是否發生變化,如果發生變化了,則表明該指標被其他執行緒設定了,也就是說,有其他執行緒對flush list做了操作,因此需要從flush list尾部重新開始掃描
在5.6.11的版本中,總是無條件的從尾部開始重新掃描。
相關文章
- Chrome渲染管道的效能改進Chrome
- 【翻譯】.NET 5中的效能改進
- ASP.NET Core 6 的效能改進ASP.NET
- 【譯】.NET 7 中的效能改進(五)
- 【譯】.NET 7 中的效能改進(六)
- 【譯】.NET 7 中的效能改進(一)
- 【譯】.NET 7 中的效能改進(二)
- 【譯】.NET 7 中的效能改進(七)
- 【譯】.NET 7 中的效能改進(八)
- 【譯】.NET 7 中的效能改進(九)
- 【譯】.NET 7 中的效能改進(十)
- 【譯】.NET 7 中的效能改進(三)
- 【譯】.NET 7 中的效能改進(四)
- 【譯】.NET 7 中的效能改進(十一)
- 【譯】.NET 7 中的效能改進(十二)
- 【譯】.NET 7 中的效能改進(十三)
- 使用 ProxySQL 改進 MySQL SSL 的連線效能MySql
- 【譯】ASP.NET Core 6 中的效能改進ASP.NET
- mysql併發執行緒控制之innodb_thread_concurrency的改進MySql執行緒thread
- GNOME 3.36 釋出,對視覺和效能進行了改進視覺
- Mqttnet記憶體與效能改進錄MQQT記憶體
- Strom及DRPC效能測試與改進RPC
- oracle效能改進方法論告訴我們!Oracle
- Python 3.11以來效能改進的背後原理Python
- 效能改進之專案例會匯入實踐
- [譯] 使用 Kotlin 協程改進應用效能Kotlin
- 改進資料庫效能-SQL查詢優化資料庫SQL優化
- C++11在時空效能方面的改進C++
- 【譯】Visual Studio 2022 - 17.8 的效能改進
- mysql的innodb和myisam的dml效能對比MySql
- 瞭解Postgres 14新功能:效能和監控改進
- .NET平臺系列15 .NET5的吊炸天效能改進
- 演算法信仰的力量:改進演算法能提升多少效能?演算法
- 按照oracle效能改進方法論的步驟來優化系統!Oracle優化
- SQL Server效能的改進得益於邏輯資料庫設計SQLServer資料庫
- MySQL核心月報2015.01-MySQL·優化改進·複製效能改進過程MySql優化
- InnoDB 隔離模式對 MySQL 效能的影響模式MySql
- Mysql innodb儲存引擎的效能最佳化MySql儲存引擎