Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Tutorial: ottimizzazione di un'app Go

In questo tutorial, eseguirai il deployment di un'applicazione Go intenzionalmente inefficiente, configurata per raccogliere dati del profilo. Puoi utilizzare l'interfaccia di Profiler per visualizzare i dati del profilo e identificare potenziali ottimizzazioni. Successivamente, modifichi l'applicazione, ne esegui il deployment e valuti l'effetto della modifica.

Prima di iniziare

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Nella pagina del selettore dei progetti in Google Cloud Console, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  3. Nella pagina del selettore dei progetti in Google Cloud Console, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  4. Per attivare l'API Cloud Profiler per il tuo progetto, nel riquadro di navigazione di Google Cloud Console, fai clic su Profiler oppure utilizza il pulsante seguente:

    Vai a Profiler

  5. Per aprire Cloud Shell, nella barra degli strumenti di Google Cloud Console, fai clic su Attiva Cloud Shell:

    Attiva Cloud Shell.

    Dopo qualche istante, si apre una sessione di Cloud Shell in Google Cloud Console:

    Sessione Cloud Shell.

Applicazione di esempio

L'obiettivo principale è massimizzare il numero di query al secondo che il server è in grado di elaborare. Un obiettivo secondario è ridurre l'utilizzo della memoria eliminando le allocazioni di memoria non necessarie.

Il server, utilizzando un framework gRPC, riceve una parola o una frase, quindi restituisce il numero di volte in cui la parola o la frase compare nelle opere di Shakespeare.

Il numero medio di query al secondo che il server è in grado di gestire determina il test del carico. Per ogni round di test viene chiamato un simulatore di client e richiesto di eseguire 20 query sequenziali. Al termine di un round, vengono visualizzati il numero di query inviate dal simulatore di client, il tempo trascorso e il numero medio di query al secondo.

Il codice del server è intenzionalmente inefficiente.

Esecuzione dell'applicazione di esempio

Scarica ed esegui l'applicazione di esempio:

  1. In Cloud Shell, esegui questi comandi:

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    cd golang-samples/profiler/shakesapp
    
  2. Esegui l'applicazione con la versione impostata su 1 e il numero di round impostato su 15:

    go run . -version 1 -num_rounds 15
    

    Dopo uno o due minuti, vengono visualizzati i dati del profilo. I dati del profilo sono simili al seguente esempio:

    Grafico a fiamme iniziale per l'utilizzo del tempo di CPU.

    Nello screenshot, tieni presente che l'opzione Tipo di profilo è impostata su CPU time. Ciò indica che i dati sull'utilizzo della CPU sono visualizzati nel grafico a fiamme.

    L'output di esempio stampato in Cloud Shell è mostrato di seguito:

    $ go run . -version 1 -num_rounds 15
    2020/08/27 17:27:34 Simulating client requests, round 1
    2020/08/27 17:27:34 Stackdriver Profiler Go Agent version: 20200618
    2020/08/27 17:27:34 profiler has started
    2020/08/27 17:27:34 creating a new profile via profiler service
    2020/08/27 17:27:51 Simulated 20 requests in 17.3s, rate of 1.156069 reqs / sec
    2020/08/27 17:27:51 Simulating client requests, round 2
    2020/08/27 17:28:10 Simulated 20 requests in 19.02s, rate of 1.051525 reqs / sec
    2020/08/27 17:28:10 Simulating client requests, round 3
    2020/08/27 17:28:29 Simulated 20 requests in 18.71s, rate of 1.068947 reqs / sec
    ...
    2020/08/27 17:44:32 Simulating client requests, round 14
    2020/08/27 17:46:04 Simulated 20 requests in 1m32.23s, rate of 0.216849 reqs / sec
    2020/08/27 17:46:04 Simulating client requests, round 15
    2020/08/27 17:47:52 Simulated 20 requests in 1m48.03s, rate of 0.185134 reqs / sec
    

    L'output di Cloud Shell mostra il tempo trascorso per ciascuna iterazione e la frequenza media delle richieste. All'avvio dell'applicazione, la voce "Simulato 20 richieste in 17,3 s, frequenza di 1,156069 req / sec"; indica che il server è in esecuzione circa 1 richiesta al secondo. Nell'ultimo round, la voce "Simulato 20 richieste in 1 m48,03 s, frequenza di 0,185134 req / sec"; indica che il server è in esecuzione circa 1 richiesta ogni 5 secondi.

Utilizzo dei profili tempo di CPU per massimizzare le query al secondo

Un approccio per massimizzare il numero di query al secondo è identificare i metodi con uso intensivo della CPU e ottimizzare le relative implementazioni. In questa sezione verranno utilizzati i profili di tempo della CPU per identificare un metodo ad alta intensità della CPU nel server.

Identificazione dell'utilizzo del tempo di CPU

Il frame principale del grafico a fiamme elenca il tempo totale di CPU utilizzato dall'applicazione nell'intervallo di raccolta di 10 secondi:

Visualizzazione espansa della cornice principale del grafico a fiamme.

In questo esempio, il servizio ha utilizzato 2.37 s. Quando il sistema è in esecuzione su un singolo core, l'utilizzo del tempo di CPU, pari a 2,37 secondi, corrisponde al 23,7% di utilizzo del core. Per ulteriori informazioni, consulta la sezione Tipi di profilazione disponibili.

Modifica dell'applicazione

Valutazione della modifica

Per valutare la modifica, procedi nel seguente modo:

  1. Esegui l'applicazione con la versione dell'applicazione impostata su 2:

    go run . -version 2 -num_rounds 40
    

    Una sezione successiva mostra che, con l'ottimizzazione, il tempo necessario per eseguire un singolo round è molto inferiore rispetto a quello dell'applicazione non modificata. Per assicurare che l'applicazione venga eseguita per un tempo sufficiente a raccogliere e caricare i profili, il numero di round viene aumentato.

  2. Attendi il completamento dell'applicazione, quindi visualizza i dati del profilo per questa versione dell'applicazione:

    • Fai clic su NOW per caricare i dati del profilo più recenti. Per ulteriori informazioni, consulta la sezione Intervallo di tempo.
    • Nel menu Versione, seleziona 2.

Ad esempio, il grafico a fiamme è mostrato come segue:

Grafico a fiamme che mostra l'utilizzo del tempo di CPU della versione 2.

In questa cifra, il frame principale mostra un valore pari a 7.8 s. In seguito alla modifica della funzione di corrispondenza delle stringhe, il tempo di CPU utilizzato dall'applicazione è aumentato da 2,37 secondi a 7,8 secondi oppure l'applicazione è passata dall'utilizzo del 23,7% di un core CPU all'utilizzo del 78% di un core CPU.

La larghezza frame è una misura proporzionale dell'utilizzo del tempo di CPU. In questo esempio, la larghezza del frame per GetMatchCount indica che la funzione utilizza circa il 49% di tutto il tempo di CPU utilizzato dall'applicazione. Nel grafico a fiamme originale, lo stesso frame corrispondeva a circa il 72% della larghezza del grafico. Per visualizzare l'esatto utilizzo del tempo di CPU, puoi utilizzare la descrizione comando del frame o l'elenco di funzioni di messa a fuoco:

Elenco delle funzioni in primo piano che mostra l'utilizzo del tempo di CPU della versione 2.

L'output in Cloud Shell mostra che la versione modificata sta completando circa 5,8 richieste al secondo:

$ go run . -version 2 -num_rounds 40
2020/08/27 18:21:40 Simulating client requests, round 1
2020/08/27 18:21:40 Stackdriver Profiler Go Agent version: 20200618
2020/08/27 18:21:40 profiler has started
2020/08/27 18:21:40 creating a new profile via profiler service
2020/08/27 18:21:44 Simulated 20 requests in 3.67s, rate of 5.449591 reqs / sec
2020/08/27 18:21:44 Simulating client requests, round 2
2020/08/27 18:21:47 Simulated 20 requests in 3.72s, rate of 5.376344 reqs / sec
2020/08/27 18:21:47 Simulating client requests, round 3
2020/08/27 18:21:51 Simulated 20 requests in 3.58s, rate of 5.586592 reqs / sec
...
2020/08/27 18:23:51 Simulating client requests, round 39
2020/08/27 18:23:54 Simulated 20 requests in 3.46s, rate of 5.780347 reqs / sec
2020/08/27 18:23:54 Simulating client requests, round 40
2020/08/27 18:23:58 Simulated 20 requests in 3.4s, rate of 5.882353 reqs / sec

Il cambiamento minimo dell'applicazione ha avuto due effetti diversi:

  • Il numero di richieste al secondo è aumentato da meno di 1 al secondo a 5,8 al secondo.

  • Il tempo di CPU per richiesta, calcolato dividendo l'utilizzo della CPU per il numero di richieste al secondo, è diminuito al 13,4% dal 23,7%.

    Tieni presente che il tempo di CPU per richiesta è diminuito anche se l'utilizzo del tempo di CPU è aumentato da 2,37 secondi, che corrisponde all'utilizzo del 23,7% di un singolo core CPU, a 7,8 secondi o al 78% di un core CPU.

Utilizzo dei profili heap allocati per migliorare l'utilizzo delle risorse

Questa sezione illustra come utilizzare i profili heap e heap per identificare un metodo ad alta intensità di allocazione nell'applicazione:

  • I profili heap mostrano la quantità di memoria allocata nell'heap del programma nel momento in cui viene raccolto.

  • I profili heap allocati mostrano la quantità totale di memoria allocata nell'heap del programma durante l'intervallo in cui il profilo è stato raccolto. Se dividi questi valori per 10 secondi, ovvero l'intervallo di raccolta del profilo, puoi interpretarli come tassi di allocazione.

Attivazione della raccolta di profili heap

  1. Esegui l'applicazione con la versione dell'applicazione impostata su 3 e abilita la raccolta di heap e i profili heap allocati.

    go run . -version 3 -num_rounds 40 -heap -heap_alloc
    
  2. Attendi il completamento dell'applicazione, quindi visualizza i dati del profilo per questa versione dell'applicazione:

    • Fai clic su NOW per caricare i dati del profilo più recenti.
    • Nel menu Versione, seleziona 3.
    • Nel menu Tipo di profiler, seleziona heap allocato.

    Ad esempio, il grafico a fiamme è mostrato come segue:

    Grafico a fiamme dei profili heap allocati per la versione 3.

Identificazione del tasso di allocazione heap

Il frame principale mostra la quantità totale di heap assegnata nei dieci secondi di raccolta del profilo, calcolata in media per tutti i profili. In questo esempio, il frame principale mostra che, in media, sono stati allocati 1,535 GiB di memoria.

Modifica dell'applicazione

Valutazione della modifica

Per valutare la modifica, procedi nel seguente modo:

  1. Esegui l'applicazione con la versione dell'applicazione impostata su 4:

    go run . -version 4 -num_rounds 60 -heap -heap_alloc
    
  2. Attendi il completamento dell'applicazione, quindi visualizza i dati del profilo per questa versione dell'applicazione:

    • Fai clic su NOW per caricare i dati del profilo più recenti.
    • Nel menu Versione, seleziona 4.
    • Nel menu Tipo di profiler, seleziona heap allocato.
  3. Per quantificare l'effetto della modifica di readFiles sulla percentuale di allocazione heap, confronta i profili heap allocati per la versione 4 con quelli raccolti per 3:

    Confronto dei profili heap allocati tra le versioni 4 e 3.

    La descrizione comando del frame principale mostra che, con la versione 4, la quantità di memoria media allocata durante la raccolta del profilo è diminuita di 1,301 GiB, rispetto alla versione 3. La descrizione comando per readFiles.func1 mostra una diminuzione di 1,045 GiB:

    Confronto del file readread' descrizione comando per il tipo di profilo heap allocato.

  4. Per quantificare l'effetto sulla garbage collection, configura un confronto dei profili di tempo della CPU. Nello screenshot seguente, viene applicato un filtro per mostrare gli stack per il raccoglitore di rifiuti Go runtime.gcBgMarkWorker.*. Lo screenshot mostra che l'utilizzo della CPU per la garbage collection è ridotto al 4,97% dal 16,8%.

    Confronto dell'utilizzo del tempo di CPU del processo di garbage collection in background dalla v4 alla v3.

  5. Per determinare se esiste un impatto sulla modifica sul numero di richieste al secondo gestite dall'applicazione, visualizza l'output in Cloud Shell. In questo esempio, la versione 4 completa fino a 15 richieste al secondo, notevolmente superiore alle 5,8 richieste al secondo della versione 3:

    $ go run . -version 4 -num_rounds 60 -heap -heap_alloc
    2020/08/27 21:51:42 Simulating client requests, round 1
    2020/08/27 21:51:42 Stackdriver Profiler Go Agent version: 20200618
    2020/08/27 21:51:42 profiler has started
    2020/08/27 21:51:42 creating a new profile via profiler service
    2020/08/27 21:51:44 Simulated 20 requests in 1.47s, rate of 13.605442 reqs / sec
    2020/08/27 21:51:44 Simulating client requests, round 2
    2020/08/27 21:51:45 Simulated 20 requests in 1.3s, rate of 15.384615 reqs / sec
    2020/08/27 21:51:45 Simulating client requests, round 3
    2020/08/27 21:51:46 Simulated 20 requests in 1.31s, rate of 15.267176 reqs / sec
    ...
    

    L'aumento delle query al secondo pubblicate dall'applicazione potrebbe essere dovuto al minor tempo da dedicare alla garbage collection.

  • Puoi ottenere una visione più completa dell'effetto della modifica su readFiles visualizzando i profili heap. Un confronto dei profili heap per la versione 4 e la versione 3 mostra che l'utilizzo heap è diminuito a 18,47 MiB da 70,95 MiB:

    Confronto dell'utilizzo dell'heap per la versione 4 a quella 3.

Riepilogo

In questa guida rapida, sono stati utilizzati il tempo di CPU e i profili heap allocati per identificare le potenziali ottimizzazioni di un'applicazione. L'obiettivo era massimizzare il numero di richieste al secondo ed eliminare le allocazioni inutili.

  • Utilizzando i profili tempo CPU, è stata identificata una funzione con uso intensivo della CPU. Dopo aver applicato una semplice modifica, la percentuale di richiesta del server è aumentata a 5,8 al secondo, in aumento da circa 1 al secondo.

  • Utilizzando profili heap allocati, la funzione shakesapp/server.go readFiles è stata identificata come tariffa con allocazione elevata. Dopo l'ottimizzazione di readFiles, la percentuale di richiesta del server è aumentata a 15 richieste al secondo e la quantità media di memoria allocata durante la raccolta del profilo di 10 secondi è diminuita di 1,301 GiB.

Passaggi successivi

Per informazioni sull'esecuzione dell'agente Cloud Profiler, consulta: