InnoDB在設計lock-free的log system時,除了已有的參數外,還經過宏控制隱藏了一些參數,若是你使用源碼編譯時,打開cmake選項-DENABLE_EXPERIMENT_SYSVARS=1, 就能夠看到這些參數了。本文主要簡單的過一下這些隱藏的參數所表明的含義數組
A.
innodb_log_write_events
innodb_log_flush_events
二者的含義相似,表示用來喚醒等待log write/flush的event的個數,默認值都是2048
好比你要等待的位置在lsnA,那麼計算的slot爲:
slot = (lsnA - 1) /OS_FILE_LOG_BLOCK_SIZE & (innodb_log_write/flush_events - 1)
這意味着:若是事務的commit log的end lsn落在相同block裏,他們可能產生event的競爭
固然若是不在同一個block的時候,若是調大參數,就能夠減小競爭,但也會有無效的喚醒
喚醒操做一般由後臺線程log_write_notifier 或者log_flush_notifier異步來作,但若是推動的log write/flush還不足一個block的話,那就log_writter/flusher
本身去喚醒了。併發
B.
innodb_log_recent_written_size, 默認1MB
表示recent_written這個link_buf的大小,其實控制了併發往log buffer中同時拷貝的事務日誌量,向前由新的日誌加入,後面由log writer經過寫日誌向前推動,若是寫的慢的話,那這個link_buf極可能用滿,用戶線程就得spin等待。再慢io的系統上,咱們能夠稍微調大這個參數less
innodb_Log_recent_closed_size, 默認2MB
表示recent closed這個link_buf的大小,也是維護能夠併發往flush list上插入髒頁的並罰度,若是插入髒頁速度慢,或者lin_buf沒有及時合併推動,就會spin wait異步
簡單說下link_buf, 這本質上是一個數組,但使用無鎖的使用方式來維護lsn的推動,好比得到一個lsn開始和結束,那就 經過設置buf[start_lsn] = end_lsn的相似方式來維護lsn鏈,基於lsn是連續值的事實,最終必然不會出現空洞,因此在演化的過程當中,能夠從尾部 推動連續的lsn,頭部插入新的值. 若是新插入的值超過了尾部,表示buf滿了,就須要spin wait了
C.
innodb_log_wait_for_write_spin_delay,
innodb_log_wait_for_write_timeoutasync
從8.0版本開始用戶線程再也不本身去寫redo,而是等待後臺線程去寫,這兩個變量控制了spin以及condition wait的timeout時間,當spin一段時間還沒推動到某個想要的lsn點時,就會進入condition wait函數
另外兩個變量
innodb_log_wait_for_flush_spin_delay
innodb_log_wait_for_flush_timeout
含義相似,可是是等待log flush到某個指定lsnui
注意在實際計算過程當中,最大spin次數,會考慮到cpu利用率,以及另外兩個參數:
innodb_log_spin_cpu_abs_lwm
innodb_log_spin_cpu_pct_hwm線程
若是是等待flush操做的話,還收到參數innodb_log_wait_for_flush_spin_hwm限制,該參數控制了等待flush的時間上限,若是平均等待flush的時間超過了這個上限的話, 就不必去spin,而是直接進入condition wait設計
關於spin次數的計算方式在函數log_max_spins_when_waiting_in_user_thread中":日誌
函數的參數即爲配置項innodb_log_wait_for_write_spin_delay或innodb_log_wait_for_flush_spin_delay值
static inline uint64_t log_max_spins_when_waiting_in_user_thread( uint64_t min_non_zero_value) { uint64_t max_spins; /* Get current cpu usage. */ const double cpu = srv_cpu_usage.utime_pct; /* Get high-watermark - when cpu usage is higher, don't spin! */ const uint32_t hwm = srv_log_spin_cpu_pct_hwm; if (srv_cpu_usage.utime_abs < srv_log_spin_cpu_abs_lwm || cpu >= hwm) { /* Don't spin because either cpu usage is too high or it's almost idle so no reason to bother. */ max_spins = 0; } else if (cpu >= hwm / 2) { /* When cpu usage is more than 50% of the hwm, use the minimum allowed number of spin rounds, not to increase cpu usage too much (risky). */ max_spins = min_non_zero_value; } else { /* When cpu usage is less than 50% of the hwm, choose maximum spin rounds in range [minimum, 10*minimum]. Smaller usage of cpu is, more spin rounds might be used. */ const double r = 1.0 * (hwm / 2 - cpu) / (hwm / 2); max_spins = static_cast<uint64_t>(min_non_zero_value + r * min_non_zero_value * 9); } return (max_spins); }
D.
如下幾個參數是後臺線程等待任務時spin及condition wait timeout的值
log_writer線程:
innodb_log_writer_spin_delay,
innodb_log_writer_timeout
log_flusher線程:
innodb_ log_flusher_spin_delay
innodb_log_flusher_timeout
log_write_notifier線程:
innodb_ log_write_notifier_spin_delay
innodb_log_write_notifier_timeout
log_flush_notifier線程
innodb_log_flush_notifier_spin_delay
innodb_log_flush_notifier_timeout
log_closer線程(用於推動recent_closed這個link_buf的專用線程)
innodb_log_closer_spin_delay
innodb_log_closer_timeout
E.
innodb_ log_write_max_size
表示容許一個write操做最大的字節數,默認爲4kb, 這個是在推動recent_written這個link buf時計算的,我的認爲這個限制過小了,能夠適當調大這個參數。(然而8.0的最大寫入限制還受到innodb_log_write_ahead_size限制,二者得綜合起來看)
F.
innodb_log_checkpoint_every
默認1000毫秒(1秒),表示至少每隔這麼長時間log_checkpointer線程會去嘗試作一次checkpoint. 固然是否作checkpoint還受到其餘因素的影響,具體見函數log_should_checkpoint:
a) more than 1s elapsed since last checkpoint b) checkpoint age is greater than max_checkpoint_age_async c) it was requested to have greater checkpoint_lsn, and oldest_lsn allows to satisfy the request
G. 參考:
MySQL8.0.16源代碼
本文爲雲棲社區原創內容,未經容許不得轉載。