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 高
下面我們對這兩種情況逐一分析。
context switch 不高,但在內核態 spin
MySQL 在內核態 spin,說明需要系統資源,當這個資源緊張不足時,就會在內核態 spin。
有些資源,用戶進程(或線程)通過執行系統調或因中斷進入內核,一般來說申請這些資源的執行時間很短,當出現資源爭用時,如果采用 sleep 再喚醒機制,代價較大,因此多采用在內核態spin的策略。
例如申請內存或發生缺頁中斷,沒有 free 內存可用時,進程或線程就可能在內核態先執行內存回收再執行內存分配,但系統內存是共享資源,分配回收時需要鎖保護,當多個進程(或線程)同時回收分配內存時。就會在內核態 spin。
當 free 內存不足時,可能出現這種情況。典型癥狀:
分析
當系統內存不足時,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+ 內核中增加一個新的參數vm.extra_free_kbytes,就是控制free內存的。
關于系統free內存,有2個重要參數:vm.min_free_kbytes?和?vm.extra_free_kbytes(2.6.32+)
vm.min_free_kbytes:系統保留給內核用的內存。
這個值決定?/proc/zoneinfo?中 zone 的min值。當系統 free 內存小于這個值時,kswapd 會回收內存,直到free內存達到/proc/zoneinfo中 high 值才停止回收;
當用戶進程或線程分配內存或發生缺頁中斷時,free 內存少于?vm.min_free_kbytes,會在用戶線程上下文中直接進行回收內存(pgscand)和分配內存。
vm.extra_free_kbytes:系統保留給應用的free內存。
這個值決定了/proc/zoneinfo中Normal zone的low值。當系統free內存小于vm.min_free_kbytes + vm.extra_free_kbytes?時,kswapd會開始回收內存,直到free內存達到?/proc/zoneinfo?中high值才停止回收。
這個額外的vm.extra_free_kbytes就是給應用突發內存需求時使用的,避免急需內存時發生pgscand或kswapd回收內存不及時。
vm.extra_free_kbytes?分配多大合適呢?一般能應對流量高峰時1-2秒內存需求就可以了。free內存減少后,kswapd進程會在后臺回收內存的,一般512M-2G可以滿足要求。
context switch 高
有很多種情況都會導致 context switch。MySQL 中的 mutex 和 RWlock 在獲取不成功后,短暫spin,還不成功,就會發生 context switch,sleep,等待喚醒。
在 MySQL中,mutex 和 RWlock導致的 context switch,一般在show global status,show engine innodb mutex,show engine innodb status,performance_schema等中會體現出來,針對不同的mutex和RWlock等待,可以采取不同的優化措施。
除了MySQL的mutex和RWlock,還發現一種情況,是MySQL外的mutex競爭導致context switch高。
典型癥狀:
分析
對于使用 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配置變量中的innodb_spin_wait_delay?和?innodb_sync_spin_loops?可以用于微調。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的MySQL数据库SYS CPU高的可能性分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MongoDB Driver:使用正确的
- 下一篇: TCP 的那些事儿