<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文讀懂|Linux系統(tǒng)平均負載

          共 4827字,需瀏覽 10分鐘

           ·

          2022-11-15 14:20

          我們經常會使用?top?命令來查看系統(tǒng)的性能情況,在?top?命令的第一行可以看到?load average?這個數據,如下圖所示:

          089a11f8bb81ce8451b8f31287bc88c3.webp

          load average?包含 3 列,分別表示 1 分鐘、5 分鐘和 15 分鐘的?系統(tǒng)平均負載

          對于系統(tǒng)平均負載這個數值,可能很多同學并不完全理解其意義,并不知道數值達到多少時才表示系統(tǒng)負載過高。本文將會以簡單的語言來介紹系統(tǒng)平均負載這個概念,并且會介紹 Linux 內核是怎么計算這個數值。

          系統(tǒng)平均負載

          《Understanding Linux CPU Load(鏈接在文章最后)》這篇文章已經非常通俗的解釋了什么是?系統(tǒng)平均負載,這里借用一下此文中的例子。

          如果將 CPU 比作是橋梁,對于單核的 CPU 就好比是單車道的橋梁。每次橋梁只能讓一輛汽車通過,并且要以規(guī)定的速度通過。那么:

          • 如果每個時刻都只有一輛汽車通過,那么所有汽車都不用排隊,此時橋梁的使用率最高。以平均負載 1.0 表示,如下圖所示:

          8dca58fd82734816605b0731b6b7bfe6.webp

          • 如果每隔一段時間才有一輛汽車通過,那么表示橋梁部分時間處于空閑的情況。并且間隔的時間越長,表示橋梁空閑率越高。此時的平均負載小于 1.0,如下圖所示:

          3110d86386f8756278e31fa76a8a57a9.webp

          • 當有大量的汽車通過橋梁時,有些汽車需要等待其他車輛通過后才能繼續(xù)通行,這時表示橋梁超負荷工作。此時平均負載大于1.0,如下圖所示:

          977bfbd90a76b9371fc37276b98fa3e2.webp

          系統(tǒng)的平均負載與上面的例子一樣,在單核 CPU 的環(huán)境下:

          • 當平均負載等于 1.0 時,表示 CPU 使用率最高。
          • 當平均負載小于 1.0 時,表示 CPU 使用率處于空閑狀態(tài)。
          • 當平均負載大于 1.0 時,表示 CPU 使用率已經超過負荷。

          對于單核 CPU 來說,平均負載 1.0 表示使用率最高。但對于多核 CPU 來說,平均負載要乘以核心數。比如在 4 核 CPU 的系統(tǒng)中,當平均負載為 4.0 時,才表示 CPU 的使用率最高。

          Linux 平均負載計算原理

          在介紹系統(tǒng)平均負載的計算原理前,先要介紹一下什么是系統(tǒng)負載。在 Linux 系統(tǒng)中,系統(tǒng)負載表示?系統(tǒng)中當前正在運行的進程數量,其包括?可運行狀態(tài)?的進程數和?不可中斷休眠狀態(tài)?的進程數的和。注意:不可中斷休眠狀態(tài)的進程一般是在等待 I/O 完成的進程。

              系統(tǒng)負載 = 可運行狀態(tài)進程數 + 不可中斷休眠狀態(tài)進程數

          知道了什么是?系統(tǒng)負載,那么?系統(tǒng)平均負載?就容易理解了。比如每 5 秒統(tǒng)計一次系統(tǒng)負載,1 分鐘內會統(tǒng)計 12 次。如下所示:

              第5秒  -> 系統(tǒng)負載
          第10秒 -> 系統(tǒng)負載
          第15秒 -> 系統(tǒng)負載
          ...
          第60秒 -> 系統(tǒng)負載

          然后把每次統(tǒng)計到的系統(tǒng)負載加起來,再除以統(tǒng)計次數,即可得出? 系統(tǒng)平均負載 。如下圖所示:

          6d47c5c541980e305f417ab972b0ecd4.webp

          但這種計算方式有些缺陷,就是預測系統(tǒng)負載的準確性不夠高,因為越老的數據越不能反映現在的情況。打個比方,要預測某條公路今天的車流量,使用昨天的數據作為預測依據,會比使用一個月之前的數據作為依據要準確得多。

          所以,時間越近的數據,對未來的預測準確性越高。

          Linux 內核使用一種名為?指數平滑法?的算法來解決這個問題,指數平滑法的核心思想是對新老數據進行加權,越老的數據權重越低。

          指數平滑法:是由 Robert G..Brown 提出的一種加權移動平均法,有興趣了解其數學原理的可以搜索相關資料,本文不作詳細介紹。

          其計算公式如下(來源于 Linux 內核代碼 kernel/sched/core.c):

              load1?=?load0?*?e?+?active?*?(1?-?e)

          解釋一下上面公式的意思:

          • load1:表示時間 t + 1 的系統(tǒng)負載。
          • load0:表示時間 t 的系統(tǒng)負載。
          • e:表示衰減系數。
          • active:表示系統(tǒng)中的活躍進程數(可運行狀態(tài)進程數 + 不可中斷休眠狀態(tài)進程數)。

          所以,我們就可以使用上面的公式來預測任何時間的系統(tǒng)平均負載了。比如,我們要預測時間點 n 的系統(tǒng)平均負載,那么可以這樣來計算:

              load1?=?load0?*?e?+?active?*?(1?-?e)
          load2?=?load1?*?e?+?active?*?(1?-?e)
          load3?=?load2?*?e?+?active?*?(1?-?e)
          ...
          loadn?=?loadn-1?*?e?+?active?*?(1?-?e)

          現在就只剩下?衰減系數?該如何計算了。

          從 Linux 內核的注釋可以了解到,計算 1 分鐘內系統(tǒng)平均負載的?衰減系數?的計算方式如下:

              1 / exp(5sec / 1min)

          其中:

          • 5sec:表示統(tǒng)計的時間間隔,5秒。

          • 1min:表示統(tǒng)計的時長,1分鐘。

          • exp:表示以自然常數 e 為底的指數函數。

          也就是說,要計算一分鐘的系統(tǒng)平均負載時,需要使用上面的?衰減系數。對于 5 分鐘和 15 分鐘的?衰減系數?的計算方式分別為:

              1 / exp(5sec / 5min)
          1 / exp(5sec / 15min)

          Linux 內核已經把 1 分鐘、5 分鐘和 15 分鐘的?衰減系數?結果計算出來,并且定義在?include/linux/sched.h?文件中,如下所示:

              
                #define?EXP_1???????1884????????/*?1/exp(5sec/1min)?as?fixed-point?*/
                
          #define?EXP_5???????2014????????/*?1/exp(5sec/5min)?*/
          #define?EXP_15??????2037????????/*?1/exp(5sec/15min)?*/

          通過上述公式計算出來的?衰減系數?是個浮點數,而在內核中是不能進行浮點數運行的。解決方法是先對?衰減系數?進行擴大,然后在展示時最縮小。所以,上面的?衰減系數?數值是經過擴大 2048 倍后的結果。

          Linux 平均負載計算實現

          萬事俱備,只欠東風。上面我們已經把所有的知識點介紹了,現在來分析一下 Linux 內核代碼是怎樣實現的。

          1. 數據存儲

          在 Linux 內核中,使用了?avenrun?數組來存儲 1 分鐘、5 分鐘和 15 分鐘的系統(tǒng)平均負載,如下代碼所示:

              unsigned?long?avenrun[3];

          如元素?avenrun[0]?用于存儲 1 分鐘內的系統(tǒng)平均負載,而元素?avenrun[1]?用于存儲 5 分鐘的系統(tǒng)平均負載,如此類推。

          2. 統(tǒng)計過程

          由于統(tǒng)計需要定時進行,所以內核把統(tǒng)計過程放置到?時鐘中斷?中進行。當?時鐘中斷?觸發(fā)時,將會調用?do_timer()?函數,而?do_timer()?函數將會調用?calc_global_load()?來統(tǒng)計系統(tǒng)平均負載。

          我們來看看?calc_global_load()?函數的實現:

              void?calc_global_load(unsigned?long?ticks)
          {
          ????long?active,?delta;

          ????//?1.?如果還沒到統(tǒng)計的時間間隔,那么將不進行統(tǒng)計(5秒統(tǒng)計一次)
          ????if?(time_before(jiffies,?calc_load_update?+?10))
          ????????return;

          ????//?2.?獲取活躍進程數
          ????delta?=?calc_load_fold_idle();
          ????if?(delta)
          ????????atomic_long_add(delta,?&calc_load_tasks);

          ????active?=?atomic_long_read(&calc_load_tasks);
          ????active?=?active?>?0???active?*?FIXED_1?:?0;

          ????//?3.?統(tǒng)計各個時間段系統(tǒng)平均負載
          ????avenrun[0]?=?calc_load(avenrun[0],?EXP_1,?active);
          ????avenrun[1]?=?calc_load(avenrun[1],?EXP_5,?active);
          ????avenrun[2]?=?calc_load(avenrun[2],?EXP_15,?active);

          ????//?4.?更新下次統(tǒng)計的時間(增加5秒)
          ????calc_load_update?+=?LOAD_FREQ;

          ????...
          }

          calc_global_load()?函數主要完成 4 件事情:

          1. 判斷當前時間是否需要進行統(tǒng)計,如果還沒到統(tǒng)計的時間間隔,那么將不進行統(tǒng)計(5秒統(tǒng)計一次)。
          2. 獲取活躍進程數(可運行狀態(tài)進程數 + 不可中斷休眠狀態(tài)進程數)。
          3. 統(tǒng)計各個時間段系統(tǒng)平均負載(1分鐘、5分鐘和15分鐘)。
          4. 更新下次統(tǒng)計的時間(增加5秒)。

          從上面的分析可知,calc_global_load()?函數將會調用?calc_load()?來計算系統(tǒng)平均負載。其代碼如下:

              /*
          ?*?a1?=?a0?*?e?+?a?*?(1?-?e)
          ?*/

          static?unsigned?long
          calc_load(unsigned?long?load,?unsigned?long?exp,?unsigned?long?active)
          {
          ????load?*=?exp;
          ????load?+=?active?*?(FIXED_1?-?exp);
          ????load?+=?1UL?<<?(FSHIFT?-?1);

          ????return?load?>>?FSHIFT;
          }

          calc_load()?函數的各個參數意義如下:

          • loadt-1?時間點的系統(tǒng)負載。
          • exp:衰減系數。
          • active:活躍進程數。

          可以看出,calc_load()?函數的實現就是按照?指數平滑法?來計算的。

          參考文獻:

          • 《Understanding Linux CPU Load》https://scoutapm.com/blog/unders> tanding-load-averages
          • 《Linux系統(tǒng)平均負載是如何計算的》https://blog.csdn.net/rikeyone/article/details/108309665



          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本在线视频一区二区三区 | 在线观看国产色情 | 天天综合91 | 香焦尻屄视频影院 | 日本欧美国产 |