Yüksek CPU kullanımı ancak düşük yük ortalaması


28

Yüksek CPU kullanımı ancak oldukça düşük bir yük ortalaması gördüğümüz garip bir davranışla karşı karşıyayız.

Davranış en iyi izleme sistemimizden gelen aşağıdaki grafiklerle gösterilmektedir.

CPU kullanımı ve yükü

Yaklaşık 11: 57'de CPU kullanımı% 25 ila% 75 arasındadır. Yük ortalaması önemli ölçüde değişmedi.

Her birinde 2 hiper iş parçacığı olan 12 çekirdekli sunucuları çalıştırıyoruz. İşletim sistemi bunu 24 CPU olarak görüyor.

CPU kullanımı verileri /usr/bin/mpstat 60 1her dakika çalıştırılarak toplanır . allSatır ve %usrsütun için veriler yukarıdaki grafikte gösterilmiştir. Bunun "istiflenmiş" kullanımı değil , CPU verisinin ortalamasını gösterdiğinden eminim . Grafikte% 75 kullanım görmemize rağmen, yaklaşık% 2000 “yığılmış” CPU kullanımını gösteren bir işlem görüyoruz top.

Yük ortalaması, /proc/loadavgher dakikadan alınmıştır .

uname -a verir:

Linux ab04 2.6.32-279.el6.x86_64 #1 SMP Wed Jun 13 18:24:36 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

Linux dağıtımı Red Hat Enterprise Linux Server release 6.3 (Santiago)

Makinelere oldukça ağır yük altında çalışan birkaç Java web uygulaması kullanıyoruz, makine başına 100 istek / saniye olduğunu düşünüyoruz.

CPU kullanım verilerini doğru yorumlarsam,% 75 CPU kullanımına sahip olduğumuzda, CPUlarımızın ortalama% 75 oranında bir işlem gerçekleştirdiği anlamına gelir. Bununla birlikte, eğer CPU'larımız zamanın% 75'iyle meşgulse, daha yüksek yük ortalaması görmemeli miyiz? İşlem sırasındaki sadece 2-4 işimiz varken CPU'lar nasıl% 75 meşgul olabilir?

Verilerimizi doğru yorumluyor muyuz? Bu davranışa ne sebep olabilir?


İzleme sistemi normalleştirilmiş CPU yükünü gösteriyor mu (load / #CPUs)? Düzenli Linux CPU yükü, farklı çekirdek / işlemci sayıları olan sistemler arasında karşılaştırmak zordur, bu nedenle bazı araçlar bunun yerine normalleştirilmiş bir CPU yükü kullanır.
Brian,

Her bir veri noktasını CPU sayısına bölmek mi istiyorsunuz? Yani bizim vakamızda loadavg / 24? Bu yardımcı olursa verilerden kolayca böyle bir grafik oluşturabilirim.
K Erlandsson

Grafiğinizin zaten bunu gösterdiğini öne sürüyordum.
Brian,

Ah, seni yanlış anladığım için üzgünüm. Güzel bir açıklama olurdu, ancak ne yazık ki gösterilen sistem genelinde yük ortalamasıdır. Daha yeni kontrol ettim.
K Erlandsson

Yanıtlar:


51

En azından Linux'ta, yük ortalaması ve CPU kullanımı aslında iki farklı şeydir. Yük ortalaması, belirli bir süre zarfında bir çekirdek çalıştırma kuyruğunda (yalnızca CPU zamanı değil, disk etkinliği) kaç işin beklediğinin bir ölçümüdür. CPU kullanımı şu anda CPU'nun ne kadar meşgul olduğunun bir ölçüsüdür. Tek bir CPU iş parçacığının bir dakika boyunca% 100 olarak ayarladığı en fazla yük 1 dakikalık yük ortalamasına "katkıda bulunabilir". 1'dir. Hiperthreading (8 sanal çekirdek) olan 4 çekirdekli bir işlemci 1 dakika boyunca% 100 1 dakikalık yük ortalaması.

Çoğu zaman bu iki sayı birbiriyle bağıntılı olan kalıplara sahiptir, ancak onları aynı şekilde düşünemezsiniz. Neredeyse% 0 CPU kullanımıyla yüksek bir yüke sahip olabilirsiniz (örneğin, bekleme durumunda kalmış çok fazla IO verisine sahip olduğunuzda) ve çalışan tek bir iş parçacıklı işleminiz olduğunda% 1 ve% 100 CPU yüküne sahip olabilirsiniz. tam eğilme. Ayrıca kısa süre boyunca CPU'yu% 100'e yakın bir değerde görebilirsiniz, ancak ortalama ölçümler henüz "yakalanmadı" çünkü yük hala 1'in altında.

Bir sunucunun 15.000'den fazla yükü (evet, gerçekten bir yazım hatası değil) ve% 0'a yakın bir CPU'su olduğunu gördüm. Bunun nedeni bir Samba paylaşımının sorunları olması ve çok sayıda müşterinin bir IO bekleme durumunda sıkışıp kalmaya başlamasıydı. Muhtemelen CPU aktivitesi olmayan düzenli bir yüksek yükleme numarası görüyorsanız, bir çeşit depolama problemi yaşıyorsunuz demektir. Sanal makinelerde bu, aynı VM sunucusundaki depolama kaynakları için rekabet eden diğer VM'lerin olduğu anlamına da gelebilir.

Yüksek yük, aynı zamanda mutlaka kötü bir şey değildir, çoğu zaman sistemin tam kapasite için kullanıldığı veya belki de devam edebilme kapasitesinin ötesinde olduğu anlamına gelir (yük sayısı işlemci çekirdeği sayısından yüksekse). Eskiden sysadmin olduğum bir yerde, ana sistemlerinde yük ortalamasını Nagios'tan daha yakın izleyen birileri vardı. Yük yüksek olduğunda, bana SMTP'den daha hızlı ve 7/24 arayacaklardı. Çoğu zaman hiçbir şey aslında yanlıştı, ancak yük sayısını yanlış olan bir şeyle ilişkilendirdiler ve bir şahin gibi izlediler. Kontrol ettikten sonra cevabım genellikle sistemin sadece işini yaptığıydı. Elbette burası yükün 15000'den fazla yükseldiği yerdi (aynı sunucu olmasa da), yani bazen bir şeyin yanlış olduğu anlamına geliyordu. Sisteminizin amacını göz önünde bulundurmalısınız. Eğer bir iş atı ise, yükün doğal olarak yüksek olmasını bekleyin.


Tek iş parçacıklı bir işlemle% 1 ve% 100 CPU yüküne sahip olabileceğimi kastediyor musunuz? Ne tür iplikten bahsediyorsun? Java işlemlerimizi göz önüne alırsak, tonlarca iş parçacığı var, ancak iş parçacığının işletim sistemi perspektifinden işlem gördüğü varsayımı altındaydım (sonuçta Linux'ta ayrı PID'ler var). Tek bir çoklu dişli java işleminin ortalama yük perspektifinden sadece bir görev olarak sayılması mümkün olabilir mi?
K Erlandsson

Sadece kendi başıma bir test yaptım, bir Java işlemindeki iş parçacıkları, ayrı işlemlerin sanki yük ortalamasına katkıda bulunuyor (Yani, yoğun bir bekleme döngüsünde 10 iş parçacığı çalıştıran bir java sınıfı bana 10'a yakın bir yük veriyor). Yukarıda bahsettiğin dişli işlemi hakkında bir açıklama için teşekkür ederiz. Teşekkür ederim!
K Erlandsson

Çok okuyuculu olmayan bir işleminiz varsa (yani, bir seferde sadece tek bir CPU kullanan). Örneğin, yoğun bir döngü çalıştıran basit bir C programı yazıyorsanız, sadece bir iş parçacığı çalışır ve bir seferde sadece 1 CPU kullanır.
deltaray

Bulduğum tüm bilgiler, dişlilerin çekirdekten bakıldığında ve yük hesaplanırken ayrı işlemler olarak sayıldığını söylüyor. Bu nedenle, tam tilt üzerinde çoklu dişli bir işleme nasıl sahip olduğumu göremiyorum, bir çoklu CPU sisteminde 1 yük ve% 100 CPU. Lütfen ne demek istediğini anlamama yardım eder misin?
K Erlandsson

Daha fazla ayrıntı arayanlar için: Brendan Gregg'in "Linux Yük Ortalamaları: Gizemi Çözmek", ihtiyacım olan tüm cevapları buldu.
Nickolay

24

Yük çok aldatıcı bir sayıdır. Bir tane tuzla alın.

Çok hızlı bir şekilde birçok işlemi çok hızlı bir şekilde tamamlarsanız, çalışma sırasındaki işlemlerin sayısı, yüklerini kaydetmek için çok küçüktür (çekirdek her beş saniyede bir yükü sayar).

Bu örneği düşünün, 8 mantıksal çekirdeğe sahip ana bilgisayarımda bu python betiği, büyük bir CPU kullanımını en üst düzeyde (yaklaşık% 85), ancak neredeyse hiç bir yükte kaydetmeyecek.

import os, sys

while True:
  for j in range(8):
    parent = os.fork()
    if not parent:
      n = 0
      for i in range(10000):
        n += 1
      sys.exit(0)
  for j in range(8):
    os.wait()

Başka bir uygulama, bu wait8 kişilik gruplardan kaçınır (ki bu testi bozar). Burada ebeveyn her zaman çocuk sayısını aktif CPU sayısında tutmaya çalışır, öyle ki ilk yöntemden daha yoğun ve umarım daha doğru olur.

/* Compile with flags -O0 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <err.h>
#include <errno.h>

#include <sys/signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#define ITERATIONS 50000

int maxchild = 0;
volatile int numspawned = 0;

void childhandle(
    int signal)
{
  int stat;
  /* Handle all exited children, until none are left to handle */
  while (waitpid(-1, &stat, WNOHANG) > 0) {
    numspawned--;
  }
}

/* Stupid task for our children to do */
void do_task(
    void)
{
  int i,j;
  for (i=0; i < ITERATIONS; i++)
    j++;
  exit(0);
}

int main() {
  pid_t pid;

  struct sigaction act;
  sigset_t sigs, old;

  maxchild = sysconf(_SC_NPROCESSORS_ONLN);

  /* Setup child handler */
  memset(&act, 0, sizeof(act));
  act.sa_handler = childhandle;
  if (sigaction(SIGCHLD, &act, NULL) < 0)
    err(EXIT_FAILURE, "sigaction");

  /* Defer the sigchild signal */
  sigemptyset(&sigs);
  sigaddset(&sigs, SIGCHLD);
  if (sigprocmask(SIG_BLOCK, &sigs, &old) < 0)
    err(EXIT_FAILURE, "sigprocmask");

  /* Create processes, where our maxchild value is not met */
  while (1) {
    while (numspawned < maxchild) {
      pid = fork();
      if (pid < 0)
        err(EXIT_FAILURE, "fork");

      else if (pid == 0) /* child process */
        do_task();
      else               /* parent */
        numspawned++;
    }
    /* Atomically unblocks signal, handler then picks it up, reblocks on finish */
    if (sigsuspend(&old) < 0 && errno != EINTR)
      err(EXIT_FAILURE, "sigsuspend");
  }
}

Bu davranışın nedeni algoritma, alt süreçler oluşturmak için asıl görevi yerine getirdiğinden daha fazla zaman harcıyor olmasıdır (10000'e kadar). Henüz yaratılmayan görevler 'çalıştırılabilir' duruma sayılmaz, ancak oluşturulduklarında CPU zamanında% sys alır.

Bu nedenle, cevabınız gerçekten ne olursa olsun, ne yapılırsa yapılsın, hızlı bir şekilde art arda çok sayıda göreve (iş parçacığı veya süreçler) rastlar.


Öneriniz için teşekkür ederim. Benim sorumdaki grafik% kullanıcı zamanını gösteriyor (CPU sistem zamanı hariç, sistem zamanında sadece çok küçük bir artış görüyoruz). Zaten birçok küçük görev açıklama olabilir mi? Yük ortalaması her 5 saniyede bir örnekleniyorsa, mpstat tarafından verilen CPU kullanım verisi daha sık örnekleniyor mu?
K Erlandsson,

CPU örneklemesinin orada nasıl yapıldığını bilmiyorum. Asla onunla ilgili çekirdek kaynağını okumayın. Benim örneğimde% usr% 70 + ve% sys% 15 idi.
Matthew Ife

İyi örnekler!
Xavier Lucas,

5

Yük ortalaması çok fazla artmıyorsa, bu sadece donanımınızın özellikleri ve işlenecek görevlerin niteliğinin, genel olarak iyi bir verimlilikle sonuçlanacağı ve görev kuyruğunda bir süre yığılmalarını önlediği anlamına gelir.

Bir çekişme olgusu olsaydı, örneğin ortalama görev karmaşıklığı çok yüksek ya da görev ortalama işlem süresi çok fazla CPU döngüsü alıyorsa, o zaman evet, yükleme ortalaması artacaktır.

GÜNCELLEME:

Asıl cevabımda net olmayabilir, bu yüzden şimdi açıklığa kavuşturuyorum:

Yük ortalama hesaplama tam formülü şöyledir: loadvg = tasks running + tasks waiting (for cores) + tasks blocked.

Kesinlikle iyi bir verime sahip olabilir ve 24 ortalama yüke yaklaşabilirsiniz ancak görevlerin işleme süresinde ceza verilmez. Öte yandan, yeterince hızlı bir şekilde tamamlamayan 2-4 periyodik göreviniz de olabilir, daha sonra bekleyen görev sayısının (CPU döngüleri için) arttığını göreceksiniz ve sonunda yüksek bir yük ortalamasına varacaksınız. Olabilecek diğer bir şey de, olağanüstü senkronize G / Ç işlemleri yürüten ve ardından bir çekirdeği engelleyen, iş hacmini düşüren ve bekleyen görev sırasını büyüten görevler yapmaktır (bu durumda iowaitmetrik değişimini görebilirsiniz )


Anladığım kadarıyla, ortalama yükleme şu anda yürütülmekte olan görevleri de içeriyor. Bu, CPU'lar için gerçek bir çekişme olmadan yük ortalamalarında kesinlikle bir artış olabileceği anlamına gelir. Yoksa yanılıyor muyum?
K Erlandsson,

@KristofferE Tamamen haklısın. Asıl formül loadavg = çalışır durumda çalışır + bekleyen görevler (mevcut çekirdekler için) + engellenen görevler. Bu, ortalama olarak 24 yüke sahip olabileceğiniz, bekleyen veya engellenen göreviniz olmadığı anlamına gelir, böylece herhangi bir çekişme olmadan sadece "tam kullanım" veya donanım kapasiteniz olur. Yük ortalaması ile CPU kullanımıyla çalışan işlemlerin sayısı konusunda kafanız karışmış gibi göründüğü için, cevabımı temel olarak, yük ortalamanın hala bu kadar az sayıda işlemle nasıl büyüyebileceği hakkındaki açıklamalara odaklandım. Yeniden okuduktan sonra bu o kadar net olmayabilir.
Xavier Lucas,

2

Yük ortalaması, disk IO'sunda engellenen görevleri içerir, böylece yalnızca çok yavaş bir diskten okumaya çalışan 10 göreve sahip olarak kolayca sıfır cpu kullanımına ve 10 yük ortalamasına sahip olabilirsiniz. Bu nedenle, yoğun bir sunucunun diski devirmeye başlaması yaygındır ve tüm arayanlar çok sayıda engellenen göreve neden olur, yük ortalamasını yükseltirken cpu kullanımı azalır, çünkü tüm görevler diskte engellenir.


1

Matthew Ife'in cevabı çok yardımcı olmuş ve bizi doğru yöne yönlendirmiş olsa da, davamızda davranışa neden olan tam olarak bu değildi. Bizim durumumuzda, iş parçacığı havuzu kullanan çok iş parçacıklı bir Java uygulamasına sahibiz, neden gerçek işler için hiçbir iş yapmıyoruz.

Ancak, dişlerin yaptığı asıl iş kısa ömürlüdür ve IO beklemelerini ya da senkronizasyon beklemelerini içerir. Matthew cevabından bahsettiği gibi, yük ortalaması OS tarafından örneklenir, bu nedenle kısa süren görevler kaçırılabilir.

Davranışı yeniden üreten bir Java programı yaptım. Aşağıdaki Java sınıfı, sunucularımızdan birinde% 28'lik bir CPU kullanımı (% 650 oranında istiflenmiş) oluşturur. Bunu yaparken, yük ortalaması yaklaşık 1.3. Buradaki anahtar, dişin içindeki uyku (), onsuz yük hesaplaması doğru.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MultiThreadLoad {

    private ThreadPoolExecutor e = new ThreadPoolExecutor(200, 200, 0l, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());

    public void load() {
        while (true) {
            e.execute(new Runnable() {

                @Override
                public void run() {
                    sleep100Ms();
                    for (long i = 0; i < 5000000l; i++)
                        ;
                }

                private void sleep100Ms() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }

    public static void main(String[] args) {
        new MultiThreadLoad().load();
    }

}

Özetlemek gerekirse, teorimiz, uygulamalarımızdaki iş parçacıklarının çok fazla boşta kalması ve kısa ömürlü bir çalışma gerçekleştirmesi, görevlerin neden yük ortalama hesaplamasıyla doğru şekilde örneklenemediğidir.


0

Yük ortalaması, CPU sırasındaki ortalama işlem sayısıdır. Her bir sistem için spesifiktir, bir LA'nın tüm sistemlerde genel olarak yüksek, diğerinin düşük olduğunu söyleyemezsiniz. Öyleyse 12 çekirdeğiniz var ve LA'nın önemli ölçüde artması için süreç sayısının gerçekten yüksek olması gerekir.

Başka bir soru "CPU Kullanımı" grafiği ile ne kastedilmektedir. Eğer SNMP'den alınmışsa, olması gerektiği gibi ve SNMP uygulamanız da net-snmp, o zaman sadece 12 işlemcinizin her birinden CPU-yükünü istifler. Yani net-snmptoplam CPU yükü miktarı% 1200'dür.

Varsayımlarım doğruysa, CPU kullanımı önemli ölçüde artmadı. Böylece, LA önemli ölçüde artmadı.


CPU kullanımı allsatır mpstat'tan alınmıştır . Tüm işlemciler arasında ortalama bir değer olduğundan eminim, yığılmadı. Örneğin, sorun oluştuğunda, üst bir işlem için% 2000 CPU kullanımını gösterir. Bu yığılmış kullanımdır.
K Erlandsson,

0

Buradaki senaryo biraz beklenmedik olmasına rağmen özellikle beklenmiyor değil. Xavier'nin üzerinde durduğu, ancak çok fazla gelişmediği şey, Linux (varsayılan olarak) ve Unix'in lezzetlerinin çoğunun önleyici çok görevli olmasına rağmen, sağlıklı bir makinede işler nadiren önlenir. Her görev, CPU'yu meşgul etmek için bir zaman dilimidir, yalnızca bu süreyi aşarsa ve çalıştırmayı bekleyen başka görevler varsa önceden kesilir (yükün hem CPU'daki hem de çalışmayı bekleyen ortalama işlem sayısını rapor ettiğini unutmayın) . Çoğu zaman, bir işlem kesintiye uğramak yerine verim elde eder.

(genel olarak, CPU sayısını yaklaştığında sadece yük hakkında endişelenmeniz gerekir - yani zamanlayıcı ön-boşaltma görevlerini başlattığında).

CPU'larımız zamanın% 75'iyle meşgulse, daha yüksek yük ortalaması görmemeli miyiz?

Her şey, faaliyet şekliyle ilgili olarak, bazı görevlerde (büyük olasılıkla küçük bir madencilik) CPU'nun açıkça kullanımının artması, diğer görevlerin işlenmesi üzerinde olumsuz bir etkiye sahip değildi. İşlenen işlemleri izole edebilecek olsanız, mevcut görev seti etkilenmezken, yavaşlama sırasında ortaya çıkan yeni bir grup görmenizi beklerdim.

güncelleştirme

Yüklemede büyük bir artış olmadan yüksek CPU'nun ortaya çıkabileceği yaygın bir senaryo, bir görevin, örneğin bir ağ isteğinin alınması üzerine, bir görevin diğer görevlerden birini (veya bir sırayı) tetiklediği, örneğin işleyicinin isteği ayrı bir iş parçacığı, ayrı iş parçacığına yönlendirdiği durumdur. daha sonra bazı diğer eşzamanlı olmayan çağrıları yapar… çalışma halinin örneklenmesi yükün gerçekte olduğundan daha düşük rapor edilmesine neden olur - ancak CPU kullanımı ile doğrusal olarak yükselmez - tetiklenen görevler zinciri çalıştırılamaz başlangıç ​​olayı ve sırayla meydana geldikleri (az ya da çok) nedeniyle çalışma sırası şişirilmez.


OP başlangıçta,% CPU toplamının "% 2000" olduğunu göstererek, sadece 1 meşgul işlem yerine CPU kullanan birçok görev olduğunu düşündürdü. Bir dakika boyunca tutarlı bir% 2000 olsaydı, normalde yükün 20-ish olmasını beklerdiniz.
Matthew Ife

... bir yorumda, soruda değil ve bundan pek emin değil. 'ALL' seçeneğinin yokluğunda, mpstat ortalama% değil toplam kullanım oranını bildirir. Ama bu cevabı değiştirmez - bu faaliyet modeliyle ilgilidir.
symcbean

Grafikte gördüğümüz CPU kullanımının “CPU başına ortalama” olduğu% 100 olumlu. Mpstat, ALL olmadan çalıştırılır, ancak bu yalnızca CPU başına düşen bilgiyi dışarıda bırakır, allsatır yine de CPU başına ortalaması gösterir. Soruyu açıklığa kavuşturacağım.
K Erlandsson,

Lütfen son bölümden biraz bahseder misiniz? Ne demek istediğinizi anlayamadım. Aldığım sorumun kısmı, en çok sorun anladığım kısım.
K Erlandsson,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.