天天看點

[MySQL 5.6] innodb_flush_method新值O_DIRECT_NO_FSYNC 及bug#68555

facebook的mark大神最近一直在測試5.6的性能,并且發現了不少問題. 看來facebook是要跳過5.5,直接上5.6了。同為網際網路行業,facebook的許多需求和我們是類似的,online ddl, 熱點資料更新問題等。。。

當然,我最關注的還是5.6存在的bug。

related blog:

<a href="http://mysqlha.blogspot.com/2013/03/mysql-56-cached-update-only-workload.html">http://mysqlha.blogspot.com/2013/03/mysql-56-cached-update-only-workload.html</a>

<a href="http://mysqlha.blogspot.com/2013/03/mysql-56-no-odirectnofsync-for-you.html">http://mysqlha.blogspot.com/2013/03/mysql-56-no-odirectnofsync-for-you.html</a>

related bug:

<a href="http://bugs.mysql.com/bug.php?id=45892">http://bugs.mysql.com/bug.php?id=45892</a>

提到兩個問題,一個是從5.6.7開始innodb_flush_method有一個新值:o_direct_no_fsync。他的含義也很簡單。當檔案被設定為o_direct時,如果将其設定為o_direct_no_fsync時,就無需在寫檔案後,再做一次flush(實際上是随後的調用邏輯性能太差了,而不僅僅是fsync很慢的緣故)。

從函數fil_flush可以很清晰的看到,fil_buffering_disabled為true時,很快就釋放全局鎖fil_system-&gt;mutex,傳回。根據mark的測試,其性能提升也非常理想:

update-only &amp; io-bound workload

updates/second for update 1 row by pk via sysbench

    8      16      32      64     128     256   concurrent clients

18234   24359   10379    9795    9843   10283   o_direct

17996   26853   30265   28923   29293   29477   o_direct_no_fsync

可惜的是,這種設定隻對部分檔案系統是安全的,一些檔案系統,例如xfs,即使設定了o_direct,還需要将metadata資訊fsync到磁盤。另外當free list為空時(髒頁太快,page cleaner跟不上),使用者線程可能去從lru擷取一個空閑block,這會導緻如下backtrace。

os_thread_sleep,fil_flush,fil_flush_file_spaces,buf_flush_sync_datafiles,

buf_flush_single_page_from_lru,buf_lru_get_free_block,

buf_page_init_for_read,buf_read_page_low,..

這種場景發生在io-bound負載下,即使在掃描lru也沒有發現非髒block可以轉移到free list後,會去嘗試從lru尾部刷一個髒block(buf_flush_single_page_from_lru),然後将其放到free list上,這其中如果包含了sync操作,顯然會大大的影響使用者線程的性能。

buf_flush_list, log_preflush_pool_modified_pages, log_checkpoint_margin, log_check_margins, log_free_check, row_upd, row_upd_step, row_update_for_mysql, ha_innobase::update_row

當更新記錄時,由于要寫redo log,需要確定buffer有足夠的空間(log_free_check),是否需要刷日志由log_sys-&gt;check_flush_or_checkpoint來标記,當為true時,表示可能有log需要刷磁盤,或者需要 preflush buffer pool page,或者需要做一次checkpoint。當lsn – last_checkpoint_lsn &gt;max_checkpoint_age時候,這個值必須為true。

注意在log_free_check中檢查check_flush_or_checkpoint時未持有log_sys-&gt;mutex。

在判斷是否需要做checkpoint時(log_checkpoint_margin),如果髒頁的lsn範圍(從每個bp instance的flush list上檢視)大于max_modified_age_sync了,需要去做刷髒頁操作(log_preflush_pool_modified_pages)

mark指出的問題是,如果有線程在做flush,後來的線程進入log_preflush_pool_modified_pages,輪詢每個bp instance,如果每個bp都正在做flush,那麼就會傳回false,可能會去強制将log_sys-&gt;check_flush_or_checkpoint設定為true,後面新來的線程是以可能持續的進入log_preflush_pool_modified_pages-&gt;buf_flush_list函數去輪詢每個bp instance,有任意一個bp instance正在被重新整理,都會導緻傳回值為false。線程在将log_sys-&gt;check_flush_or_checkpoint這樣一個全局可見的變量設定為true後會繼續loop。

讨論還在繼續,持續關注中….

繼續閱讀