Sử dụng CPU cao nhưng tải trung bình thấp


28

Chúng tôi đang chạy vào một hành vi kỳ lạ, nơi chúng tôi thấy việc sử dụng CPU cao nhưng tải trung bình khá thấp.

Hành vi được minh họa tốt nhất bằng các biểu đồ sau từ hệ thống giám sát của chúng tôi.

Sử dụng và tải CPU

Vào khoảng 11:57, việc sử dụng CPU tăng từ 25% đến 75%. Trung bình tải không thay đổi đáng kể.

Chúng tôi chạy các máy chủ với 12 lõi với 2 luồng siêu tốc. HĐH coi đây là 24 CPU.

Dữ liệu sử dụng CPU được thu thập bằng cách chạy /usr/bin/mpstat 60 1mỗi phút. Dữ liệu cho allhàng và %usrcột được hiển thị trong biểu đồ trên. Tôi chắc chắn điều này không hiển thị mức trung bình trên mỗi dữ liệu CPU, chứ không phải việc sử dụng "xếp chồng". Mặc dù chúng tôi thấy mức sử dụng 75% trong biểu đồ, chúng tôi thấy một quá trình hiển thị để sử dụng khoảng 2000% CPU "xếp chồng" vào top.

Con số trung bình tải được lấy từ /proc/loadavgmỗi phút.

uname -a cho:

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 là Red Hat Enterprise Linux Server release 6.3 (Santiago)

Chúng tôi chạy một vài ứng dụng web Java dưới tải khá nặng trên các máy, nghĩ 100 yêu cầu / s trên mỗi máy.

Nếu tôi diễn giải chính xác dữ liệu sử dụng CPU, thì khi chúng ta sử dụng 75% CPU, điều đó có nghĩa là CPU của chúng ta đang thực hiện một quá trình trung bình 75% thời gian. Tuy nhiên, nếu CPU của chúng tôi bận rộn 75% thời gian, chúng ta có nên thấy tải trung bình cao hơn không? Làm thế nào các CPU có thể bận rộn 75% trong khi chúng ta chỉ có 2-4 công việc trong hàng đợi chạy?

Chúng tôi đang giải thích dữ liệu của chúng tôi chính xác? Điều gì có thể gây ra hành vi này?


Hệ thống giám sát có hiển thị tải CPU được chuẩn hóa (tải / #CPUs) không? Tải CPU Linux thông thường khó có thể so sánh giữa các hệ thống với số lượng lõi / cpu khác nhau, vì vậy một số công cụ sử dụng tải CPU được chuẩn hóa thay thế.
Brian

Bạn có nghĩa là chia mỗi điểm dữ liệu với số lượng CPU? Tức là loadavg / 24 trong trường hợp của chúng tôi? Tôi có thể dễ dàng tạo một biểu đồ như vậy từ dữ liệu nếu điều đó có ích.
K Erlandsson 12/2/2015

Tôi đã gợi ý biểu đồ của bạn có thể đã cho thấy điều đó.
Brian

Ah, xin lỗi vì đã hiểu lầm bạn. Nó sẽ là một lời giải thích tốt đẹp, nhưng thật không may, đó là mức trung bình tải toàn hệ thống được hiển thị. Tôi chỉ kiểm tra ba lần.
K Erlandsson

Câu trả lời:


51

Trên Linux ít nhất, mức trung bình tải và sử dụng CPU thực sự là hai điều khác nhau. Tải trung bình là một phép đo xem có bao nhiêu tác vụ đang chờ trong hàng đợi chạy kernel (không chỉ thời gian CPU mà cả hoạt động của đĩa) trong một khoảng thời gian. Việc sử dụng CPU là thước đo mức độ bận rộn của CPU ngay bây giờ. Tải trọng lớn nhất mà một luồng CPU duy nhất được chốt ở mức 100% trong một phút có thể "đóng góp" cho mức trung bình tải 1 phút là 1. Một CPU 4 lõi có siêu phân luồng (8 lõi ảo) tất cả ở mức 100% trong 1 phút sẽ đóng góp 8 tải trung bình 1 phút.

Thông thường, hai số này có các mẫu tương quan với nhau, nhưng bạn không thể nghĩ chúng giống nhau. Bạn có thể tải cao với mức sử dụng CPU gần 0% (chẳng hạn như khi bạn có nhiều dữ liệu IO bị kẹt trong trạng thái chờ) và bạn có thể có tải 1 và 100% CPU, khi bạn có một quy trình xử lý luồng đơn nghiêng hoàn toàn. Ngoài ra, trong khoảng thời gian ngắn, bạn có thể thấy CPU ở mức gần 100% nhưng tải vẫn dưới 1 vì các số liệu trung bình chưa "bắt kịp".

Tôi đã thấy một máy chủ có tải hơn 15.000 (vâng, thực sự đó không phải là một lỗi đánh máy) và% CPU gần bằng 0%. Nó đã xảy ra vì một chia sẻ Samba có vấn đề và rất nhiều khách hàng bắt đầu bị mắc kẹt trong trạng thái chờ đợi IO. Rất có thể nếu bạn đang thấy một số tải cao thông thường không có hoạt động CPU tương ứng, bạn đang gặp vấn đề về lưu trữ. Trên các máy ảo, điều này cũng có nghĩa là có các máy ảo khác cạnh tranh mạnh về tài nguyên lưu trữ trên cùng một máy chủ VM.

Tải cao cũng không hẳn là một điều xấu, hầu hết thời gian nó chỉ có nghĩa là hệ thống đang được sử dụng hết công suất hoặc có thể vượt quá khả năng của nó để theo kịp (nếu số lượng tải cao hơn số lõi xử lý). Tại một nơi tôi từng là một sysadmin, họ có một người theo dõi mức trung bình tải trên hệ thống chính của họ gần hơn Nagios. Khi tải cao, họ sẽ gọi cho tôi 24/7 nhanh hơn bạn có thể nói là SMTP. Hầu hết thời gian không có gì là thực sự sai, nhưng họ liên kết số tải với một cái gì đó sai và xem nó như một con chim ưng. Sau khi kiểm tra, phản hồi của tôi thường là hệ thống chỉ hoạt động. Tất nhiên đây là cùng một nơi mà tải đã tăng hơn 15000 (mặc dù không phải cùng một máy chủ) nên đôi khi điều đó có nghĩa là có gì đó không đúng. Bạn phải xem xét mục đích của hệ thống của bạn. Nếu đó là một công việc, thì hy vọng tải sẽ cao tự nhiên.


Làm thế nào để bạn có nghĩa là tôi có thể tải CPU 1 và 100% với một quy trình luồng đơn? Bạn đang nói về loại chủ đề nào? Nếu chúng ta xem xét các quy trình Java của chúng ta, chúng có vô số luồng, nhưng tôi đã giả định rằng các luồng được coi là các tiến trình theo quan điểm của HĐH (rốt cuộc chúng có các PID riêng biệt trên Linux). Có thể vì vậy mà một quá trình java đa luồng đơn chỉ được tính là một tác vụ từ góc độ trung bình tải?
K Erlandsson

Tôi vừa tự mình thực hiện một thử nghiệm, các luồng trong quy trình Java đóng góp vào mức trung bình tải như thể chúng ở các quy trình riêng biệt (Tức là một lớp java chạy 10 luồng trong vòng lặp bận-chờ cho tôi tải gần 10). Tôi sẽ đánh giá cao một sự làm rõ về quá trình luồng mà bạn đã đề cập ở trên. Cảm ơn bạn!
K Erlandsson

Ý tôi là nếu bạn có một quá trình không đa luồng (nghĩa là một quá trình chỉ sử dụng một CPU duy nhất tại một thời điểm). Chẳng hạn, nếu bạn chỉ viết một chương trình C đơn giản chạy một vòng lặp bận rộn, thì nó chỉ là một luồng duy nhất đang chạy và chỉ sử dụng 1 CPU mỗi lần.
deltaray

Tất cả thông tin tôi đã tìm thấy nói rằng các luồng được tính là các quá trình riêng biệt khi nhìn từ kernel và khi tính toán tải. Do đó, tôi không thấy làm thế nào tôi có thể có một quy trình đa luồng ở độ nghiêng hoàn toàn dẫn đến 1 tải và 100% CPU trên hệ thống nhiều CPU. Bạn có thể vui lòng giúp tôi hiểu ý của bạn?
K Erlandsson 14/2/2015

Đối với bất kỳ ai đang tìm kiếm chi tiết hơn: "Trung bình tải Linux: Giải quyết bí ẩn" của Brendan Gregg có tất cả các câu trả lời tôi cần.
Nickolay

24

Tải là một con số rất lừa đảo. Mang nó theo một hạt muối.

Nếu bạn sinh ra nhiều tác vụ liên tiếp rất nhanh, hoàn thành rất nhanh, số lượng tiến trình trong hàng đợi chạy quá nhỏ để đăng ký tải cho chúng (hạt nhân sẽ tải một lần trong năm giây).

Hãy xem xét ví dụ này, trên máy chủ của tôi có 8 lõi logic, tập lệnh python này sẽ đăng ký sử dụng CPU lớn ở trên cùng (khoảng 85%), nhưng hầu như không tải.

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()

Một cách thực hiện khác, điều này tránh waittrong các nhóm 8 (sẽ làm sai lệch bài kiểm tra). Ở đây, cha mẹ luôn cố gắng giữ số lượng trẻ em ở số lượng CPU hoạt động như vậy sẽ bận rộn hơn nhiều so với phương pháp đầu tiên và hy vọng chính xác hơn.

/* 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");
  }
}

Lý do cho hành vi này là thuật toán dành nhiều thời gian để tạo các tiến trình con hơn là nó chạy tác vụ thực tế (đếm đến 10000). Các tác vụ chưa được tạo không thể được tính vào trạng thái 'có thể chạy được', nhưng sẽ chiếm% sys về thời gian CPU khi chúng được sinh ra.

Vì vậy, câu trả lời thực sự có thể là trong trường hợp của bạn rằng bất kỳ công việc nào đang được thực hiện đều sinh ra số lượng lớn các nhiệm vụ liên tiếp (luồng hoặc quy trình).


Cảm ơn vì đã góp ý. Biểu đồ trong câu hỏi của tôi cho thấy% thời gian người dùng (thời gian hệ thống CPU bị loại trừ, chúng tôi chỉ thấy thời gian hệ thống tăng rất nhẹ). Có thể nhiều nhiệm vụ nhỏ là giải thích dù sao? Nếu trung bình tải được lấy mẫu cứ sau 5 giây, dữ liệu sử dụng CPU được cung cấp bởi mpstat có được lấy mẫu thường xuyên hơn không?
K Erlandsson

Tôi không quen với cách lấy mẫu CPU được thực hiện ở đó. Không bao giờ đọc nguồn kernel liên quan đến nó. Trong ví dụ của tôi,% usr là 70% + và% sys là 15%.
Matthew Ife

Ví dụ tốt!
Xavier Lucas

5

Nếu trung bình tải không tăng nhiều thì điều đó chỉ có nghĩa là thông số kỹ thuật phần cứng của bạn và bản chất của các tác vụ sẽ được xử lý dẫn đến thông lượng tổng thể tốt, tránh việc chúng bị chất đống trong hàng đợi nhiệm vụ trong một thời gian.

Nếu có một hiện tượng tranh chấp vì ví dụ độ phức tạp của nhiệm vụ trung bình quá cao hoặc thời gian xử lý trung bình của nhiệm vụ mất quá nhiều chu kỳ CPU, thì có, trung bình tải sẽ tăng.

CẬP NHẬT:

Nó có thể không rõ ràng trong câu trả lời ban đầu của tôi, vì vậy bây giờ tôi đang làm rõ:

Công thức chính xác của tính toán trung bình tải là : loadvg = tasks running + tasks waiting (for cores) + tasks blocked.

Bạn chắc chắn có thể có thông lượng tốt và đạt gần mức trung bình tải là 24 nhưng không bị phạt về thời gian xử lý tác vụ. Mặt khác, bạn cũng có thể có 2-4 nhiệm vụ định kỳ không hoàn thành đủ nhanh, sau đó bạn sẽ thấy số lượng tác vụ đang chờ (đối với chu kỳ CPU) đang tăng lên và cuối cùng bạn sẽ đạt mức trung bình tải cao. Một điều khác có thể xảy ra là có các tác vụ chạy các hoạt động I / O đồng bộ xuất sắc sau đó chặn lõi, hạ thấp thông lượng và làm cho hàng đợi nhiệm vụ chờ tăng lên (trong trường hợp đó bạn có thể thấy iowaitsố liệu thay đổi)


Theo hiểu biết của tôi, tải trung bình cũng bao gồm các tác vụ hiện đang thực thi. Điều đó có nghĩa là chúng tôi chắc chắn có thể có mức tăng trung bình tải mà không có sự tranh chấp thực tế cho CPU. Hay tôi đang nhầm / hiểu lầm bạn?
K Erlandsson

@KristofferE Bạn hoàn toàn đúng. Công thức thực tế là loadavg = taks đang chạy + nhiệm vụ đang chờ (đối với các lõi khả dụng) + các tác vụ bị chặn. Điều này có nghĩa là bạn có thể có trung bình tải là 24, không có nhiệm vụ chờ hoặc bị chặn, do đó chỉ có "mức sử dụng đầy đủ" hoặc dung lượng phần cứng của bạn mà không có bất kỳ tranh chấp nào. Vì bạn có vẻ bối rối về mức trung bình tải so với số lượng tiến trình đang chạy so với việc sử dụng CPU, tôi chủ yếu tập trung vào câu trả lời của mình về các giải thích về cách trung bình tải vẫn có thể phát triển với rất ít quá trình chạy tổng thể. Nó có thể không rõ ràng thực sự sau khi đọc lại nó.
Xavier Lucas

2

Tải trung bình bao gồm các tác vụ bị chặn trên IO đĩa, do đó bạn có thể dễ dàng sử dụng cpu bằng 0 và trung bình tải là 10 chỉ bằng cách có tất cả 10 tác vụ cố gắng đọc từ đĩa rất chậm. Do đó, thông thường máy chủ bận rộn bắt đầu đập đĩa và tất cả các tìm kiếm gây ra nhiều tác vụ bị chặn, tăng trung bình tải, trong khi việc sử dụng cpu giảm xuống, vì tất cả các tác vụ đều bị chặn trên đĩa.


1

Mặc dù câu trả lời của Matthew Ife rất hữu ích và đưa chúng ta đi đúng hướng, nhưng đó không chính xác là nguyên nhân gây ra hành vi trong trường hợp của chúng ta. Trong trường hợp của chúng tôi, chúng tôi có một ứng dụng Java đa luồng sử dụng nhóm luồng, tại sao không có công việc nào được thực hiện để tạo các tác vụ thực tế.

Tuy nhiên, công việc thực tế mà các luồng thực hiện là ngắn ngủi và bao gồm chờ đợi IO hoặc chờ đồng bộ hóa. Như Matthew đã đề cập trong câu trả lời của mình, trung bình tải được hệ điều hành lấy mẫu, do đó các nhiệm vụ có thời gian ngắn có thể bị bỏ lỡ.

Tôi đã thực hiện một chương trình Java tái tạo hành vi. Lớp Java sau đây tạo ra mức sử dụng CPU là 28% (650% xếp chồng) trên một trong các máy chủ của chúng tôi. Trong khi làm điều này, trung bình tải là khoảng 1,3. Chìa khóa ở đây là chế độ ngủ () bên trong luồng, không có tính toán tải là chính xác.

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();
    }

}

Tóm lại, lý thuyết là các luồng trong các ứng dụng của chúng ta nhàn rỗi rất nhiều và sau đó thực hiện công việc ngắn hạn, tại sao các tác vụ không được lấy mẫu chính xác bằng phép tính trung bình tải.


0

Tải trung bình là số lượng trung bình của các quá trình trong hàng đợi CPU. Nó là cụ thể cho từng hệ thống, bạn không thể nói rằng một LA nói chung là cao trên tất cả các hệ thống, và một hệ thống khác là thấp. Vì vậy, bạn có 12 lõi và để LA tăng đáng kể số lượng quy trình phải thực sự cao.

Một câu hỏi khác là biểu đồ "Sử dụng CPU" nghĩa là gì. Nếu nó được lấy từ SNMP, giống như vậy và việc triển khai SNMP của bạn là vậy net-snmp, thì chỉ cần xếp chồng tải CPU từ mỗi CPU trong số 12 CPU của bạn. Vì vậy, đối net-snmpvới tổng số lượng tải CPU là 1200%.

Nếu giả định của tôi là chính xác, thì việc sử dụng CPU đã không tăng đáng kể. Do đó, LA không tăng đáng kể.


Việc sử dụng cpu được lấy từ mpstat, allhàng. Tôi khá chắc chắn rằng nó là một mức trung bình trên tất cả các CPU, nó không được xếp chồng lên nhau. Ví dụ: khi sự cố xảy ra, top hiển thị mức sử dụng CPU 2000% cho một quy trình. Đó là sử dụng xếp chồng lên nhau.
K Erlandsson 12/2/2015

0

Kịch bản ở đây không đặc biệt bất ngờ mặc dù nó hơi bất thường. Những gì Xavier chạm vào, nhưng không phát triển nhiều, là mặc dù Linux (theo mặc định) và hầu hết các hương vị của Unix đều thực hiện đa tác vụ trước, trên một máy khỏe mạnh, các tác vụ sẽ hiếm khi được xử lý trước. Mỗi tác vụ được sắp xếp một lát thời gian để chiếm CPU, nó chỉ được xử lý trước nếu vượt quá thời gian này và có các tác vụ khác đang chờ để chạy (lưu ý rằng tải báo cáo số lượng quá trình trung bình cả trong CPU và chờ chạy) . Hầu hết thời gian, một quá trình sẽ mang lại thay vì bị gián đoạn.

(nói chung, bạn chỉ cần lo lắng về tải khi nó đóng số lượng CPU - tức là khi bộ lập lịch bắt đầu các tác vụ làm trống trước).

nếu CPU của chúng tôi bận 75% thời gian, chúng ta có nên thấy tải trung bình cao hơn không?

Tất cả là về mô hình hoạt động, rõ ràng việc sử dụng CPU tăng lên bởi một số tác vụ (rất có thể là một nhóm nhỏ) không có tác động bất lợi đến việc xử lý các tác vụ khác. Nếu bạn có thể cô lập các giao dịch đang được xử lý, tôi hy vọng bạn sẽ thấy một nhóm mới xuất hiện trong thời gian chậm lại, trong khi bộ tác vụ còn lại không bị ảnh hưởng.

cập nhật

Một tình huống phổ biến khi CPU cao có thể xảy ra mà không tăng tải lớn là khi một tác vụ kích hoạt một (hoặc một chuỗi) các tác vụ khác, ví dụ như khi nhận được yêu cầu mạng, trình xử lý sẽ chuyển yêu cầu đến một luồng riêng biệt, luồng riêng biệt sau đó thực hiện một số cuộc gọi không đồng bộ đến các quy trình khác .... việc lấy mẫu của runqueue khiến tải được báo cáo thấp hơn thực tế - nhưng nó không tăng tuyến tính với việc sử dụng CPU - chuỗi các tác vụ được kích hoạt sẽ không thể chạy được nếu không có sự kiện ban đầu và bởi vì chúng xảy ra (ít nhiều) theo tuần tự, hàng đợi chạy không bị thổi phồng.


OP ban đầu cung cấp các dấu hiệu cho thấy% CPU tổng hợp là "2000%" cho thấy có nhiều tác vụ sử dụng hết CPU, thay vì chỉ 1 quá trình bận rộn. Nếu nó là 2000% nhất quán trong một phút, thông thường bạn dự đoán tải sẽ là 20 giờ.
Matthew Ife

... trong một bình luận, không phải trong câu hỏi, và anh ta không chắc lắm về điều đó. Trong trường hợp không có tùy chọn 'TẤT CẢ', mpstat báo cáo tổng số% sử dụng không phải là trung bình. Nhưng điều đó không thay đổi câu trả lời - đó là về mô hình hoạt động.
symcbean

Tôi khẳng định 100% rằng CPU sử dụng mà chúng ta thấy trong biểu đồ là "mức trung bình trên mỗi CPU". Mpstat được chạy mà không có TẤT CẢ, nhưng chỉ bỏ qua thông tin trên mỗi CPU, allhàng vẫn hiển thị mức trung bình trên mỗi CPU. Tôi sẽ làm rõ câu hỏi.
K Erlandsson

Bạn có thể vui lòng giải thích yoru phần cuối một chút? Tôi không nắm bắt được ý của bạn, trong khi phần câu hỏi của tôi mà bạn trích dẫn là phần tôi gặp khó khăn nhất để hiểu.
K Erlandsson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.