2015-07-28 3 views
15

Java non può utilizzare terabyte di RAM perché la pausa GC è troppo lunga (minuti). Con il recente aggiornamento del Go GC, mi chiedo se le sue pause GC siano abbastanza brevi da poter essere utilizzate con enormi quantità di RAM, come un paio di terabyte.Quanto è veloce andare 1.5 gc con terabyte di RAM?

Ci sono ancora dei punti di riferimento? Possiamo usare un linguaggio raccolto con questa molta RAM ora?

+3

Interessante domanda, potrebbe essere una scelta migliore per i golang-nuts, però. La dimensione del ram – inf

+1

non ha importanza. ram USAGE conta. se usi solo qualche concerto di quella ram, un ciclo GC deve solo occuparsi di quei pochi concerti. se si assegna la TB completa come blocco singolo, di nuovo è banale da gestire. "questo puntatore è ancora in uso?" –

+0

sì, ovviamente intendevo l'uso della ram :) –

risposta

11

tl; dr:

  • Non è possibile utilizzare TB di RAM con un unico processo Go al momento. Max è 512 GB su Linux e la maggior parte di quelli che ho visto è di 240 GB.
  • Con lo sfondo attuale GC, il carico di lavoro GC tende ad essere più importante di GC pause.
  • Si può capire il carico di lavoro GC come puntatori * tasso di assegnazione/RAM ricambio. Di app che utilizzano tonnellate di RAM, solo quelle con pochi puntatori o poca allocazione avranno un carico di lavoro GC basso.

Sono d'accordo con il commento di inf che enormi cumuli sono la pena di chiedere altre persone circa (o test). JimB rileva che gli heap di Go hanno un limite rigido di 512 GB al momento, e 240 GB è il più che ho visto testato.

Alcune cose che sappiamo su enormi cumuli, da the design document e the GopherCon 2015 slides:

  • Il 1.5 collettore non hanno lo scopo di tagliare GC lavoro, appena tagliato pause lavorando in background.
  • Il codice viene messo in pausa mentre il GC esegue la scansione dei puntatori sullo stack e nei globali.
  • Il 1.5 GC ha una breve pausa su un benchmark GC con circa 18GB mucchio, come mostrato dalla destra punto giallo lungo la parte inferiore this graph from the GopherCon talk:

    GC Pauses vs. Heap Size showing well GCs of 18GB at multiple seconds under old versions and under 1 second for 1.5

Folks esecuzione coppia le app di produzione che inizialmente presentavano pause di circa 300 ms sono state ridotte a ~4ms e ~20ms. Un'altra app ha riferito che il tempo del GC al 95 ° percentile è passato da 279ms to ~10ms.

Go 1.6 added polish and pushed some of the remaining work to the background. Come risultato, i test con cumuli fino a un po 'più di 200GB ha visto ancora un tempo di pausa massimo di 20 ms, come mostrato in a slide nei primi del 2016 State of Go talk:

Graph of 1.6 GC times, hitting 20ms around 180GB

La stessa applicazione che ha avuto 20ms tempi di pausa sotto 1.5 aveva 3-4ms pauses under 1.6, with about an 8GB heap and 150M allocations/minute.

Twitch, che utilizza Go per il proprio servizio di chat, ha segnalato che by Go 1.7 pause times had been reduced to 1ms with lots of running goroutines.

1.8 took stack scanning out of the stop-the-world phase, portando la maggior parte delle pause ben al di sotto di 1 ms, anche su grandi cumuli. Early numbers look good. Occasionalmente le applicazioni hanno ancora schemi di codice che rendono difficile la pausa di una goroutine, allungando in modo efficace la pausa per tutti gli altri thread, ma in generale è giusto dire che il lavoro di background del GC di solito è molto più importante di GC pause.


Alcune osservazioni di carattere generale in materia di raccolta dei rifiuti, non specifiche per Go:

riformulato, un'applicazione l'accesso a grandi quantità di memoria potrebbe ancora non avere un problema GC se ha solo alcune indicazioni (ad esempio, gestisce relativamente pochi grandi []byte buffer), e le collezioni accadere meno spesso se il tasso di allocazione è basso (ad es. perché hai applicato sync.Pool per riutilizzare la memoria ovunque eri a masticare nella RAM più velocemente).

Quindi, se siete alla ricerca di qualcosa che coinvolge un sacco di centinaia di GB che non è naturalmente GC-friendly, io suggerirei di prendere in considerazione qualsiasi

  1. scritta in C o come
  2. spostando il ingombranti dati fuori dal grafico dell'oggetto. Ad esempio, è possibile gestire i dati in un DB incorporato come bolt, inserirli in un servizio DB esterno o utilizzare qualcosa come groupcache o memcache se si desidera più di una cache di un DB
  3. in esecuzione un set di heap più piccolo ' d processi invece di uno grande
  4. solo con attenzione la prototipazione, il test e l'ottimizzazione per evitare problemi di memoria.
+0

Non Java, ma CLR, possiamo memorizzare centinaia di milioni di oggetti nella cache che alloca il byte []. L'approccio GC è lento, indipendentemente da come lo si fa. https://youtu.be/Dz_7hukyejQ –

+0

È interessante notare che la serializzazione efficiente offre prestazioni più veloci dell'assegnazione di "oggetti reali" in un heap. Forse in Java qualcun altro ha un approccio simile? https://github.com/aumcode/nfx/blob/master/Source/NFX/ApplicationModel/Pile/IPile.cs –

+0

Sì, sei sempre a posto se gestisci solo '[] byte's, come caso speciale di quelle osservazioni generali su GC. Ho provato a stendere quelle rughe, ma penso che non sia una risposta completa alla domanda posta solo per parlare di questo approccio. – twotwotwo