Widersprüchliche Kubernetes-CPU-Auslastung und Docker-Container-Metriken

9

Wir haben kürzlich unsere Produktionsumgebung auf Kubernetes umgestellt. Ich möchte CPU-Limits für die Container erzwingen. Ich erhalte widersprüchliche CPU-Metriken, die nicht zusammenpassen. Hier ist mein Setup:

  • DataDog-Agenten, die als ausgeführt werden Daemonset
  • Bestehende Anwendungen werden ohne CPU-Limits ausgeführt
  • Bei den fraglichen Containern handelt es sich um Ruby-Anwendungen mit mehreren Threads
  • Zwei Metriken: kubernetes.cpu.usage.{avg,max}unddocker.cpu.usage
  • c4.xlarge Clusterknoten (4 vCPUs oder 4000 m in Kubernetes-Begriffen)

kubernetes.cpu.usage.maxmeldet ~ 600m für die betreffenden Container. docker.cpu.usagemeldet ~ 60%. Daraus folgt, dass ein CPU-Limit von 1000 m im normalen Betrieb mehr als ausreichend Kapazität wäre.

Ich habe das Limit auf 1000m gesetzt. Dann docker.container.throttlessteigt deutlich kubernetes.cpu.usage.maxund docker.cpu.usagebleibt dabei gleich. Während dieser Zeit fällt das System auf die Knie. Das ergibt für mich keinen Sinn.

Ich habe Docker-Statistiken recherchiert. Es scheint, dass docker stats(und die zugrunde liegende API) die Last gemäß den CPU-Kernen normalisieren . In meinem Fall kommen also docker.cpu.usage60% (4000 m * 0,60) in Kubernetes-Begriffen auf 2400 m. Dies korreliert jedoch nicht mit Kubernetes-Nummern. Ich habe ein weiteres Experiment durchgeführt, um meine Hypothese zu testen, dass die Kubernetes-Zahlen falsch sind. Ich habe das Limit auf 2600 m festgelegt (für zusätzliche Kopffreiheit). Dies führte zu keinen Drosseln. Kubernetes stellte jedoch fest, dass sich die CPU-Auslastung nicht geändert hat. Das verwirrt mich.

Meine Fragen sind also:

  • Fühlt sich das wie ein Fehler in Kubernetes an (oder etwas im Stapel?)
  • Ist mein Verständnis richtig?

Meine Folgefrage bezieht sich darauf, wie die CPU für Ruby-Anwendungen richtig bestimmt wird. Ein Container verwendet Puma. Dies ist ein Multithread-Webserver mit einer konfigurierbaren Anzahl von Threads. HTTP-Anforderungen werden von einem der Threads verarbeitet. Die zweite Anwendung ist ein Thrift-Server, der den Thread-Server verwendet. Jede eingehende TCP-Verbindung wird von einem eigenen Thread verarbeitet. Der Thread wird beendet, wenn die Verbindung geschlossen wird. Ruby als GIL (Global Interpreter Lock), sodass jeweils nur ein Thread Ruby-Code ausführen kann. Dies ermöglicht mehrere Threads, die E / A und ähnliches ausführen.

Ich denke, der beste Ansatz besteht darin, die Anzahl der in jeder Anwendung ausgeführten Threads zu begrenzen und die CPU-Grenzwerte von Kubernetes basierend auf der Anzahl der Threads zu approximieren. Die Prozesse sind nicht verzweigt, sodass die Gesamtauslastung der CPU schwerer vorherzusagen ist.

Die Frage hier ist: Wie kann man die CPU-Auslastung und die Grenzwerte für diese Anwendungen richtig vorhersagen?

Ahawkins
quelle
Haben Sie einen 1-CPU-Knoten und einen 2-CPU-Knoten ausprobiert, um zu sehen, wie die Anzahl korreliert (oder nicht)?
Tensibai

Antworten:

4

Mehrere Dinge hier:

  1. Sie sind auf AWS ec2, daher berechnet alles, was Sie auf Ihrer Instanz zum Messen der CPU tun, die CPU auf Hypervisor-Ebene und nicht auf Instanzebene. Führen Sie dazu einen Auslastungstest durch und überprüfen Sie die iostat -ct 1- und CPU-Auslastung in Cloudwatch. Die CPU-Auslastung in Cloudwatch ist immer um 10 bis 20% höher als von iostat angegeben. Dies liegt daran, dass iostat die CPU-Auslastung auf Hypervisor-Ebene angibt.

  2. Als Docker, um zu sehen, wie Kubernetes und Docker-Metriken verglichen werden, empfehle ich, die Container mit --cpuset = 1 oder einer beliebigen Zahl auszuführen, damit alle Container nur eine einzige vCPU verwenden können.

  3. Auch in AWS 1 CPU = 2vcpu. Es wird auf 2 hyperthreaded. Sie können dies möglicherweise bei der Berechnung berücksichtigen.

  4. Die beste Metrik, um die CPU-Auslastung für eine bestimmte Anwendung zu ermitteln, ist die Verwendung von htop und die Korrelation mit Ihren Cloudwatch-Metriken.

  5. Ich habe auch beobachtet, dass sich Docker-Daemons manchmal an eine der virtuellen CPUs anheften. Wenn Sie sie daher auf 1000 m reduzieren, wird das gesamte Setup möglicherweise langsam, da die Reduzierung auf einem der vpcus erfolgt. Sie können mpstat verwenden, um Details dazu zu erhalten.

  6. Schließlich können Sie auf Host-Ebene Docker an eine einzelne CPU anheften und mehr beobachten.

Hoffe das bringt dich etwas näher. Aktualisieren Sie mich, wenn Sie bereits eine Lösung gefunden haben.

Lakshayk
quelle