1. innodb_thread_concurrency
innodb有一系列的計數器來統計和控制內部的工作線程。其中最重要的一個是innodb_thread_concurrency,和它相關的innodb_thread_sleep_delay 和innodb_concurrency_tickets。
由於MySQL是插件式db,讀取行的時候可以有很多方式,比如說順序讀or隨機讀,而DML(insert,delete,update)語句是要判斷是否已經進入到了innodb線程里,如果超過了 innodb_thread_concurrency的值,首先要等innodb_thread_sleep_delay ms后嘗試再次進入工作線程,如果失敗,則會進入到FIFO隊列等待喚醒。這里要提下為什么需要兩次嘗試?因為需要減少等待線程的個數和上下文切換的次數。
如果一個線程能夠進到innodb層,則會發放一個innodb_concurrency_tickets 票,下次的時候如果在有效期內,則不會檢查tickets,代碼很簡單,在 srv_conc_enter_innodb function in innobase/srv/srv0srv.c里:
if (thread->n_tickets_to_enter_innodb > 0) { thread->n_tickets_to_enter_innodb--; ENTER; } retry: if (entered_thread < innodb_thread_concurrency) { entered_threads++; thread->n_tickets_to_enter_innodb = innodb_concurrency_tickets; ENTER; } if (innodb_thread_sleep_delay > 0) { thread_sleep(innodb_thread_sleep_delay); } goto retry; // (only once) WAIT_IN_FIFO_QUEUE; thread->n_tickets_to_enter_innodb = innodb_concurrency_tickets; ENTER;
那么innodb_thread_concurrency最佳值是多少呢?在MySQL5.6之前建議要比cpu的核數小
理論上可以設置2*(NumCPUs+NumDisks),這樣就有每個cpu和磁盤分配2倍的active threads,但是這僅僅是理想情況。根據實踐,一般在8核cpu推薦設置1,2,4;如果這個值遠遠比cpu個數少的話就會不能充分利用cpu,這樣線程就會在進入innodb的隊列之前sleep一段時間。
2. innodb_commit_concurrency
innodb_thread_concurrency限制行的並發度,但是在提交階段(innodb的結構和鎖爭用很嚴重的),缺沒有得到很好的保護。MySQL從5.0就開始引進的innodb_commit_concurrency,
Command-Line Format | --innodb_commit_concurrency=# |
||
Option-File Format | innodb_commit_concurrency |
||
System Variable Name | innodb_commit_concurrency |
||
Variable Scope | Global | ||
Dynamic Variable | Yes | ||
Permitted Values | |||
Type | numeric |
||
Default | 0 |
||
Range | 0 .. 1000 |
這個參數設置了同一時刻允許同時commit的線程數。默認是0,也即是不限制。這個值可以在0到1000隨意設置,如果剛開始是0,要想設置>0,必須在配置文件里添加:
innodb_commit_concurrency=n(n>0),在n>0的情況下可以設置(0~1000]的范圍變化,但是不能動態的設置成0,也不能動態的設置為n,必須重啟MySQL;
這個值一般場景下,不限制(為0)就能滿足需求,但是0並不是適用於所有的場景,對於大量寫場景,對性能提升還是很明顯的。
參考:http://www.mysqlperformanceblog.com/2006/06/05/innodb-thread-concurrency/