天天看點

MySQL · 專家投稿 · MySQL資料庫SYS CPU高的可能性分析

我們在管理繁忙的 mysql 資料庫時,可能都有碰到 sys cpu 高的經曆:系統突然 sys cpu 高起來,甚至比 user cpu 高很多,這時系統 qps、tps 急劇下降。

sys cpu高是什麼造成的呢?主要有2種可能:

1. context switch 不高,但在核心态 spin,導緻 sys cpu 高

2. context switch 高,每秒超過 200k,有時超過1m,過多 context switch 導緻 sys cpu 高

下面我們對這兩種情況逐一分析。

mysql 在核心态 spin,說明需要系統資源,當這個資源緊張不足時,就會在核心态 spin。

有些資源,使用者程序(或線程)通過執行系統調或因中斷進入核心,一般來說申請這些資源的執行時間很短,當出現資源争用時,如果采用 sleep 再喚醒機制,代價較大,是以多采用在核心态spin的政策。

例如申請記憶體或發生缺頁中斷,沒有 free 記憶體可用時,程序或線程就可能在核心态先執行記憶體回收再執行記憶體配置設定,但系統記憶體是共享資源,配置設定回收時需要鎖保護,當多個程序(或線程)同時回收配置設定記憶體時。就會在核心态 spin。

當 free 記憶體不足時,可能出現這種情況。典型症狀:

mysql running 高,但系統 qps、tps 下降

系統 free 記憶體不足;或系統 free 記憶體充足時,但啟用了 numa 記憶體配置設定政策,有的節點 free 記憶體很少

系統 context switch 不高

mysql innodb 的 mutex、rwlock 查不到等待資訊

sar -b 顯示有 pgscand 産生

當系統記憶體不足時,mysql 突然有大量通路,緊急需要大量記憶體,kswapd 在短時間内回收不了足夠多的 free 記憶體,或 kswapd 還沒有觸發執行,這時 mysql 使用者線程就會在核心态執行記憶體回收操作,進而出現以上症狀。

sar -b 輸出中,pgscank 是表示核心線程 kswapd 回收記憶體,k意思是 kernel;pgscand是表示使用者程序或線程直接回收記憶體,d意思是direct。

解決辦法:保證系統有充足 free 記憶體可用,numa 環境要求每個節點都有足夠free記憶體可用。

由于 linux 系統會盡量使用 free 記憶體,一個運作很久的 linux 系統,free記憶體通常很少,存在大量 filecache 記憶體,但 linux 沒有直接提供控制 filecache 占用多少的參數,那怎麼能夠保留足夠可用的 free 記憶體,以應對突然記憶體需求呢?

對此,linux 2.3.32+ 核心中增加一個新的參數<code>vm.extra_free_kbytes</code>,就是控制free記憶體的。

關于系統free記憶體,有2個重要參數:<code>vm.min_free_kbytes</code> 和 <code>vm.extra_free_kbytes</code>(2.6.32+)

<code>vm.min_free_kbytes</code>:系統保留給核心用的記憶體。

這個值決定 <code>/proc/zoneinfo</code> 中 zone 的min值。當系統 free 記憶體小于這個值時,kswapd 會回收記憶體,直到free記憶體達到<code>/proc/zoneinfo</code>中 high 值才停止回收;

當使用者程序或線程配置設定記憶體或發生缺頁中斷時,free 記憶體少于 <code>vm.min_free_kbytes</code>,會在使用者線程上下文中直接進行回收記憶體(pgscand)和配置設定記憶體。

<code>vm.extra_free_kbytes</code>:系統保留給應用的free記憶體。

這個值決定了<code>/proc/zoneinfo</code>中normal zone的low值。當系統free記憶體小于<code>vm.min_free_kbytes + vm.extra_free_kbytes</code> 時,kswapd會開始回收記憶體,直到free記憶體達到 <code>/proc/zoneinfo</code> 中high值才停止回收。

這個額外的<code>vm.extra_free_kbytes</code>就是給應用突發記憶體需求時使用的,避免急需記憶體時發生pgscand或kswapd回收記憶體不及時。

<code>vm.extra_free_kbytes</code> 配置設定多大合适呢?一般能應對流量高峰時1-2秒記憶體需求就可以了。free記憶體減少後,kswapd程序會在背景回收記憶體的,一般512m-2g可以滿足要求。

有很多種情況都會導緻 context switch。mysql 中的 mutex 和 rwlock 在擷取不成功後,短暫spin,還不成功,就會發生 context switch,sleep,等待喚醒。

在 mysql中,mutex 和 rwlock導緻的 context switch,一般在<code>show global status</code>,<code>show engine innodb mutex</code>,<code>show engine innodb status</code>,<code>performance_schema</code>等中會展現出來,針對不同的mutex和rwlock等待,可以采取不同的優化措施。

除了mysql的mutex和rwlock,還發現一種情況,是mysql外的mutex競争導緻context switch高。

典型症狀:

mysql running 高,但系統 qps、tps 低

系統context switch很高,每秒超過200k

在 mysql 記憶體查不到mutex和rwlock競争資訊

sys cpu 高,user cpu 低

并發執行的sql中出現timestamp字段,mysql的time_zone設定為system

對于使用 timestamp 的場景,mysql 在通路 timestamp 字段時會做時區轉換,當 time_zone 設定為 system 時,mysql 通路每一行的 timestamp 字段時,都會通過 libc 的時區函數,擷取 linux 設定的時區,在這個函數中會持有mutex,當大量并發sql需要通路 timestamp 字段時,會出現 mutex 競争。

mysql 通路每一行都會做這個時區轉換,轉換完後釋放mutex,所有等待這個 mutex 的線程全部喚醒,結果又會隻有一個線程會成功持有 mutex,其餘又會再次sleep,這樣就會導緻 context switch 非常高但 qps 很低,系統吞吐量急劇下降。

解決辦法:設定time_zone=’+8:00’,這樣就不會通路 linux 系統時區,直接轉換,避免了mutex問題。

另外,對于spin消耗,mysql配置變量中的<code>innodb_spin_wait_delay</code> 和 <code>innodb_sync_spin_loops</code> 可以用于微調。

作者介紹 高亞芳 北京理工大學計算機系畢業,it行業老兵,目前負責資料存儲基礎架構工作,開源愛好者。