負載可以說是一個服務器是否正常的風向標,當接入的軟件運行緩慢的時候,相信大部分人排查線上服務器第一件事就是要看下負載的高低?通過uptime命令可以直觀的看到系統1、5、15分鍾內的平均負載值,本文簡稱為負載。那么關於負載就有一些有意思的話題了。如什么是負載,如何判定負載的高低?那些原因導致負載升高?下面結合我的一些工作經驗簡單聊一聊。
什么是負載?
在我最早接觸負載一詞的時候,大腦里的印象就是衡量服務器的繁忙程度,因此服務器的負載不能太高,高了的話服務器就忙不過來了。我對負載這樣的認識一直大概保持了一年半,后來還是因為有個原 因,於是去man了下uptime。
關於負載的解釋,uptime上有算是較為詳細的說明:
System load averages is the average number of processes that are either in a runnable or uninterruptable state. A process in a runnable state is either using the CPU or waiting to use the CPU. A process in uninterruptable state is waiting for some I/O access, eg waiting for disk. The averages are taken over the three time intervals. Load averages are not normalized for the number of CPUs in a system, so a load average of 1 means a single CPU system is loaded all the time while on a 4 CPU system it means it was idle 75% of the time.
根據以上的描述,負載的概念就清晰起來了,首先負載是什么? 負載是一個平均進程數。那么,是所有狀態下的進程數嗎?不是的,對進程的狀態有要求,就是進程的狀態需要處於 runnable state(可運行狀態) 和 uninterrupttable state(不可中斷狀態)。
ok,現在的重點來到了這兩種狀態的進程的理解上,何為 runnable 狀態,上面也給出了清晰的解釋,就是要么進程正在使用cpu,要么正在等待着使用cpu。對這句解釋稍作補充,在一個進程的生命周期中,會有不同狀態,處於runnable狀態的進程代表着一切資源准備就緒了(cpu資源除外),那么就會有兩種情況,一種是已經獲得了cpu資源的,那么就代表着他正在使用cpu資源進行運行,另外一種就是他在排隊等待cpu資源。(進程調度器會為使用cpu資源的進程維護一個隊列)因為linux是多用戶多進程系統,進程數量一般遠大於cpu數量,因此cpu的資源是珍貴的,使用需要申請和排隊。
何為uninterruptable 狀態?,就是進程正在等待一些IO的請求,諸如磁盤IO/網絡IO。說實在的,對於這個理解我還只能停留在表面。uninterruptable和 interruptable都是進程的sleep狀態。我們可以理解為進程在睡覺(進程要繼續運行的條件和資源不充分,因此他們要睡覺),進入這兩種狀態下,他們會立即釋放掉cpu資源,不同點在於,處於interruptable是一種淺睡,任何的風吹草動(信號)都會驚醒他,然后他就會醒來接着干活。那么uninterruptable 就是一種沉睡,只有他等到的東西等來了他才醒來。
總結來說,負載數值即是處於runnable state 和uninterruptable state 的進程數。可以大致理解為系統正在處理的進程數。
如何判斷負載的高低?
記得畢業后剛入職幾個月的時候,適逢雙十一,上面分了幾台小的服務器,讓盯梢負載。然后,我問旭哥說多高負載算高,旭哥說超過1就很高了。所以,從此我就記住了,負載高於1就高了。直到有一次一個持有相同概念的同事被另外一個同事鄙視后,我偷偷弄明白了負載后,負載高於1就過載的說法就不攻自破了。
關於負載過1就過載的說法在只有一個cpu的情況下是可以理解的,因為一個cpu同一時刻只能處理一個進程,所以剛好是100%的滿負荷運行。但是在一個四核的機器上,無異於其他三個cpu在空閑着。所以看負載是否過載,要有一個前提,那就是需要明確有幾個cpu,如果負載數長時間高於cpu數,那么就可以判斷為過載。
cat /proc/cpuinfo
以上命令可以查看cpu的個數。但這並不是說,我們都要線上的機器都要滿負荷的去跑,肯定是要有一定的余量的,至於余多少,可以根據自己業務的訪問情況決定。
那些原因導致負載升高?
有了對負載本質的了解,就不難分析出負載較高的情況了?導致負載升高的原因無非有兩個原因,一個是處於 runnable state 的進程不斷增多,另一個是處於 uninterruptable state的進程不斷增多。runnable state 增多一般是cpu資源不夠,而uninterruptable state增多大部分時間是磁盤IO成為瓶頸。
cpu資源不夠,為了方便理解,我們可以假設機器只有一個cpu,而每個進程處理需要1s,但是每1s就會2個進程需要處理,此時每1過1s就會累積一個進程處理不掉,那么負載自然就不斷的增加
IO成為瓶頸,有的時候cpu利用率不是很高,但是負載依然會很高,比如大量的讀請求,導致磁盤io成為瓶頸,此時進程在等待磁盤IO的同時是不可中斷的狀態,因此仍然會參與負載值的計算,因此負載會變高
個人遇到的一些導致負載升高的原因
本人從事電商ERP系統開發,服務器中安裝有mysql服務器,因此一般情況下,出問題大部分是mysql中的一些問題。
- 大量數據請求時,包括搜索時全表掃描、以及大量的導出數據等。這種情況下一般大量的讀請求讓IO成為瓶頸,導致其他進程也處理緩慢,因此隨着時間的增加負載就會升高
- 事務未提交,一般一些業務處理系統,耦合關系強,如訂單的出庫和庫存的關系,一般是需要原子性操作,這個時候一般會使用事務來進行控制,但是不幸出現事務未提交的情況,會導致大量資源被鎖,其他請求處於長時間等待的情況,這種情況也會導致負載升高
- 死鎖,mysql的死鎖檢測以及回滾都會有一定的時間,加之事務對資源的獨占,出現死鎖會出現短暫的擁堵現象,同時負載的短時間內上升,不過后面繼續會下降。但是死鎖很頻繁的情況下,負載也會一直較高
- 內存不足時,mysql服務器是相當耗費內存的,如果內存不足導致交換分區長時間使用的話,也會讓機器負載升高
- 其他導致的一些IO問題,如磁盤損壞以及磁盤空間不足