„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Golang: Wie Beobachtbarkeit und Profilerstellung eine nahezu nicht nachweisbare Drosselung aufdeckten

Golang: Wie Beobachtbarkeit und Profilerstellung eine nahezu nicht nachweisbare Drosselung aufdeckten

Veröffentlicht am 08.11.2024
Durchsuche:160

In einem persönlichen Projekt mit Go, das Informationen über finanzielle Vermögenswerte von Bovespa erhält.
Das System nutzt intensiv die Parallelität und Parallelität mit Goroutinen und aktualisiert alle 8 Sekunden Asset-Informationen (zusammen mit Geschäftsberechnungen).
Anfangs erschienen keine Fehler oder Warnungen, aber ich bemerkte, dass die Ausführung einiger Goroutinen länger dauerte als andere.

Um genauer zu sein: Während die p99-Zeit bei 0,03 ms lag, stieg sie an einigen Stellen auf 0,9 ms. Dies veranlasste mich, das Problem weiter zu untersuchen.

Ich habe festgestellt, dass ich einen Semaphor-Goroutine-Pool verwende, der auf der Grundlage der Variablen GOMAXPROCS erstellt wurde.
Mir wurde jedoch klar, dass es bei diesem Ansatz ein Problem gab.

Wenn wir die Variable GOMAXPROCS verwenden, erfasst sie die Anzahl der im Container verfügbaren Kerne nicht korrekt. Wenn der Container weniger verfügbare Kerne hat als die Gesamtzahl der VM, wird die Gesamtzahl der VM berücksichtigt. Beispielsweise verfügt meine VM über 8 verfügbare Kerne, der Container jedoch nur über 4. Dies führte dazu, dass 8 Goroutinen zur gleichzeitigen Ausführung erstellt wurden, was zu einer Drosselung führte.

Nach langer Recherche über Nacht habe ich eine von Uber entwickelte Bibliothek gefunden, die die Variable GOMAXPROCS automatisch effizienter anpasst, unabhängig davon, ob sie sich in einem Container befindet oder nicht. Diese Lösung erwies sich als äußerst stabil und effizient: automaxprocs

Golang: Como a observabilidade e profiling revelaram um throttling quase indetectável Über-gehen / automaxprocs

Stellen Sie GOMAXPROCS automatisch so ein, dass es dem CPU-Kontingent des Linux-Containers entspricht.

automaxprocs Golang: Como a observabilidade e profiling revelaram um throttling quase indetectável Golang: Como a observabilidade e profiling revelaram um throttling quase indetectável Golang: Como a observabilidade e profiling revelaram um throttling quase indetectável

GOMAXPROCS automatisch so einstellen, dass es dem CPU-Kontingent des Linux-Containers entspricht.

Installation

go get -u go.uber.org/automaxprocs

Schnellstart

import _ "go.uber.org/automaxprocs"

func main() {
  // Your application logic here.
}
Vollbildmodus aufrufen Vollbildmodus verlassen

Leistung

Daten, die vom internen Load Balancer von Uber gemessen wurden. Wir haben den Load Balancer mit 200 % CPU-Quote (d. h. 2 Kernen) ausgeführt:

GOMAXPROCS RPS P50 (ms) P99,9 (ms)
1 28.893,18 1,46 19,70
2 (entspricht dem Kontingent) 44.715,07 0,84 26,38
3 44.212,93 0,66 30.07
4 41.071,15 0,57 42,94
8 33.111,69 0,43 64,32
Standard (24) 22.191,40 0,45 76,19

Wenn GOMAXPROCS über das CPU-Kontingent hinaus erhöht wird, sehen wir, dass P50 leicht abnimmt, aber deutliche Steigerungen auf P99 zu verzeichnen sind. Wir sehen auch, dass auch die gesamten verarbeiteten RPS sinken.

Wenn GOMAXPROCS höher ist als das zugewiesene CPU-Kontingent, haben wir auch eine erhebliche Drosselung festgestellt:

$ cat /sys/fs/cgroup/cpu,cpuacct/system.slice/[...]/cpu.stat
nr_periods 42227334
nr_throttled 131923
throttled_time 88613212216618

Sobald GOMAXPROCS auf das CPU-Kontingent reduziert wurde, sahen wir keine CPU-Drosselung.

Auf GitHub ansehen
.

Nach der Implementierung der Verwendung dieser Bibliothek wurde das Problem behoben und die p99-Zeit blieb nun konstant bei 0,02 ms. Diese Erfahrung verdeutlichte die Bedeutung von Beobachtbarkeit und Profilierung in gleichzeitigen Systemen.

Das Folgende ist ein sehr einfaches Beispiel, das jedoch den Unterschied in der Leistung zeigt.

Mit dem nativen Test- und Benckmak-Paket von Go habe ich zwei Dateien erstellt:

benchmarking_with_enhancement_test.go:

package main

import (
    _ "go.uber.org/automaxprocs"
    "runtime"
    "sync"
    "testing"
)

// BenchmarkWithEnhancement Função com melhoria, para adicionar o indice do loop em um array de inteiro
func BenchmarkWithEnhancement(b *testing.B) {
    // Obtém o número de CPUs disponíveis
    numCPUs := runtime.NumCPU()
    // Define o máximo de CPUs para serem usadas pelo programa
    maxGoroutines := runtime.GOMAXPROCS(numCPUs)
    // Criação do semáforo
    semaphore := make(chan struct{}, maxGoroutines)

    var (
        // Espera para grupo de goroutines finalizar
        wg sync.WaitGroup
        // Propriade
        mu sync.Mutex
        // Lista para armazenar inteiros
        list []int
    )

    // Loop com mihão de indices
    for i := 0; i 



benchmarking_without_enhancement_test.go:

package main

import (
    "runtime"
    "sync"
    "testing"
)

// BenchmarkWithoutEnhancement Função sem a melhoria, para adicionar o indice do loop em um array de inteiro
func BenchmarkWithoutEnhancement(b *testing.B) {
    // Obtém o número de CPUs disponíveis
    numCPUs := runtime.NumCPU()
    // Define o máximo de CPUs para serem usadas pelo programa
    maxGoroutines := runtime.GOMAXPROCS(numCPUs)
    // Criação do semáforo
    semaphore := make(chan struct{}, maxGoroutines)

    var (
        // Espera para grupo de goroutines finalizar
        wg sync.WaitGroup
        // Propriade
        mu sync.Mutex
        // Lista para armazenar inteiros
        list []int
    )

    // Loop com mihão de indices
    for i := 0; i 



Der Unterschied zwischen ihnen besteht darin, dass man den Uber-Bibliotheksimport verwendet.

Beim Ausführen des Benchmarks unter der Annahme, dass 2 CPUs verwendet würden, war das Ergebnis:

Golang: Como a observabilidade e profiling revelaram um throttling quase indetectável

ns/op: Gibt einen Durchschnitt in Nanosekunden an, wie lange es dauert, einen bestimmten Vorgang auszuführen.

Beachten Sie, dass die insgesamt verfügbare CPU meiner CPU 8 Kerne beträgt, und das ist es, was die runtime.NumCPU()-Eigenschaft zurückgegeben hat. Wie beim Ausführen des Benchmarks habe ich jedoch definiert, dass nur zwei CPUs verwendet werden würden, und die Datei, die Automaxprocs nicht verwendet, hat definiert, dass die Ausführungsbeschränkung gleichzeitig 8 Goroutinen betragen würde, während die effizienteste 2 wäre, weil Auf diese Weise wird die Ausführung durch die Verwendung einer geringeren Zuweisung effizienter.

Die Bedeutung der Beobachtbarkeit und Profilerstellung unserer Anwendungen ist also klar.

Freigabeerklärung Dieser Artikel ist nachgedruckt unter: https://dev.to/mggcmatheus/golang-como-a-beservilidade-e-profiling-entelaram-um-throttling-quase-Indetectavel-1H5P?1 Wenn es eine Verletzung gibt, wenden Sie sich bitte an Studie_Golang, @163.com Löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3