Come determinare il punto ottimale tra la dimensione del pool e le connessioni al database in PostgreSQL


14

Stiamo riscontrando problemi nella gestione del traffico durante le ore di punta verso il nostro server di database. Stiamo cercando di migliorare l'hardware (vedi questa domanda su quel lato delle cose ) ma vogliamo anche lavorare sulla configurazione del pool e sull'ottimizzazione del server.

L'applicazione a cui stiamo lavorando è un gioco multiplayer a turni per smartphone, in cui il backend è costituito da Rails con unicorno e PostgreSQL 9.1 come database. Al momento abbiamo 600.000 utenti registrati e poiché lo stato del gioco è memorizzato nel database, ogni paio di secondi vengono eseguite diverse migliaia di scritture. Abbiamo analizzato i file di registro da PostgreSQL utilizzando PgBadger e durante le ore critiche ne otteniamo molti

FATAL: remaining connection slots are reserved for non-replication superuser connections

La soluzione ingenua per contrastare questo problema sarebbe quella di aumentare max_connections (che attualmente è 100) in postgresql.conf . Ho letto http://wiki.postgresql.org/wiki/Number_Of_Database_Connections che indica che questa potrebbe non essere la cosa giusta da fare. Nel suddetto articolo si riferisce alla ricerca del punto ottimale tra max_connections e dimensioni della piscina .

Cosa si può fare per trovare questo punto debole? Esistono buoni strumenti per misurare le prestazioni I / O per diversi valori di max_connections e dimensioni del pool ?

La nostra configurazione attuale è di 4 server di gioco, ognuno con 16 lavoratori unicorno e una dimensione del pool di 5.

Ecco le impostazioni postgres non predefinite che stiamo usando:

version                      | PostgreSQL 9.1.5 on x86_64-unknown-linux-gnu,compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
checkpoint_completion_target | 0.9
checkpoint_segments          | 60
checkpoint_timeout           | 6min
client_encoding              | UTF8
effective_cache_size         | 2GB
lc_collate                   | en_US.UTF-8
lc_ctype                     | en_US.UTF-8
log_destination              | csvlog
log_directory                | pg_log
log_filename                 | postgresql-%Y-%m-%d_%H%M%S.log
log_line_prefix              | %t
log_min_duration_statement   | 200ms
log_rotation_age             | 1d
log_rotation_size            | 10MB
logging_collector            | on
max_connections              | 100
max_stack_depth              | 2MB
server_encoding              | UTF8
shared_buffers               | 1GB
ssl                          | on
TimeZone                     | localtime
wal_buffers                  | 16MB
work_mem                     | 8MB

Sei la persona che ha chiesto informazioni al riguardo sulla mailing list nelle ultime settimane? In tal caso, aggiungerò backlink a quella discussione. Inoltre: qual è l'hardware e la configurazione del server DB ? wiki.postgresql.org/wiki/Slow_Query_Questions . Includi impostazioni non predefinite: wiki.postgresql.org/wiki/Server_Configuration . Hai letto wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ? Lavori in batch in transazioni più grandi ove possibile? Usi un livello di memorizzazione nella cache e, in tal caso, cosa? Stai usando synchronous_commit = offo un commit_delay?
Craig Ringer,

Quindi hai un totale di 20 connessioni al server PostgreSQL? 5 per server di gioco? Con quei 5 conn da ciascun server di gioco condivisi tra 16 lavoratori unicorno?
Craig Ringer,

Oh, stai registrando query lente? In tal caso, quali sono i tuoi punti caldi? Semplice INSERTs? Com'è il tuo schema: è partizionato? Qual è la explain analyzedomanda di alcune query di esempio? Quanto sono frequenti i tuoi checkpoint e quanto tempo impiegano? (vedi le opzioni di registrazione del checkpoint). E seriamente, qual è la tua versione di PostgreSQL ? (Aggiornamento: sembra che tu elenchi il tuo hardware qui: dba.stackexchange.com/questions/28061/… )
Craig Ringer

Ad ogni modo, per l'ottimizzazione specifica delle dimensioni del pool, le uniche risposte reali sono impostare una misurazione robusta del carico e della velocità del server DB, quindi iniziare a regolare su e giù fino a trovare il punto ottimale.
Craig Ringer,

@CraigRinger No, non sono quella persona. Ma grazie per i backlink! Ho letto Ottimizzare il tuo server PostgreSQL e ho seguito alcuni dei suggerimenti citati. Ora ho incluso le impostazioni non predefinite. Ora stiamo cercando di effettuare transazioni e test più grandisynchronous_commit = off
lorgartzor,

Risposte:


14

La risposta breve qui è "tentativi ed errori guidati dal monitoraggio e dalle metriche delle prestazioni".

Ci sono alcune regole generali che dovrebbero aiutarti a trovare l'area vaga da cui iniziare, ma sono molto generali. Le linee guida generali "numero di CPU più numero di dischi indipendenti" sono spesso citate, ma è solo un punto di partenza incredibilmente approssimativo.

Quello che devi veramente fare è mettere a punto metriche prestazionali solide per la tua applicazione. Inizia a registrare le statistiche.

Non c'è molto nel modo di strumenti integrati per questo. Ci sono cose come lo check_postgresscript nagios , la registrazione dei contatori delle prestazioni del sistema Cacti, il raccoglitore di statistiche PostgreSQL, ecc ... ma non c'è molto che metta tutto insieme. Purtroppo, dovrai farlo da solo. Per il lato PostgreSQL, vedere il monitoraggio nel manuale PostgreSQL. Esistono alcune opzioni di terze parti, come Postgres Enterprise Monitor di EnterpriseDB .

Per le metriche a livello di applicazione menzionate qui vorrai registrarle in strutture di dati condivise o in un DB esterno non durevole come Redis e aggregarle mentre le registri o prima di scriverle nel tuo DB PostgreSQL. Cercare di accedere direttamente a Pg distorcerà le tue misurazioni con il sovraccarico creato registrando le misurazioni e peggiorando il problema.

L'opzione più semplice è probabilmente un singleton in ogni server di app che usi per registrare le statistiche dell'applicazione. Probabilmente vuoi mantenere un min, max, n, total e mean in costante aggiornamento; in questo modo non è necessario memorizzare ogni punto stat, ma solo gli aggregati. Questo singleton è in grado di scrivere le sue statistiche aggregate su Pg ogni x minuti, un tasso abbastanza basso da ridurre l'impatto delle prestazioni.

Iniziare con:

  • Qual è la latenza della richiesta? In altre parole, quanto tempo impiega l'app a ricevere una richiesta dal client fino a quando non risponde al client. Registra questo in forma aggregata per un periodo di tempo, piuttosto che come singoli record. Raggruppalo per tipo di richiesta; ad esempio, per pagina.

  • Qual è il ritardo di accesso al database per ogni query o tipo di query eseguita dall'app? Quanto tempo impiega la richiesta al DB di informazioni / memorizzazione delle informazioni fino a quando non viene eseguita e può passare all'attività successiva? Ancora una volta, aggregare queste statistiche nell'applicazione e scrivere solo le informazioni aggregate nel DB.

  • Qual è il tuo rendimento? In ogni dato x minuti, quante query di ogni classe principale eseguita dalla tua app vengono gestite dal DB?

  • Per lo stesso intervallo di tempo di x minuti, quante richieste del cliente c'erano?

  • Campionando ogni pochi secondi e aggregando le stesse finestre x minuti nel DB, quante connessioni DB c'erano? Quanti di loro erano inattivi? Quanti erano attivi? Negli inserti? Aggiornamenti? seleziona? eliminazioni? Quante transazioni c'erano in quel periodo? Vedi la documentazione del raccoglitore di statistiche

  • Di nuovo campionando e aggregando nello stesso intervallo di tempo, quali erano le metriche delle prestazioni del sistema host? Quante letture e quanti scrivono IO / secondo su disco? Megabyte al secondo di letture e scritture su disco? Utilizzo della CPU? Carico medio? Utilizzo della RAM?

Ora puoi iniziare a conoscere le prestazioni della tua app correlando i dati, rappresentandoli graficamente, ecc. Inizierai a vedere schemi, a trovare colli di bottiglia.

Si potrebbe imparare che il sistema sia in bottiglia a collo su INSERTe UPDATEs a tassi di transazione elevati, nonostante piuttosto basso di I / O su disco in megabyte al secondo. Questo suggerirebbe che è necessario migliorare le prestazioni di scaricamento del disco con un controller RAID con memorizzazione nella cache con riscrittura a batteria o alcuni SSD di alta qualità con protezione dell'alimentazione. Puoi anche utilizzare synchronous_commit = offse è OK perdere alcune transazioni in caso di arresto anomalo del server e / o a commit_delay, per eliminare parte del carico di sincronizzazione.

Quando si rappresentano graficamente le transazioni al secondo rispetto al numero di connessioni simultanee e si corregge la velocità di richiesta variabile che l'applicazione sta vedendo, si sarà in grado di farsi un'idea di dove si trova il punto ottimale della velocità effettiva.

Se non si dispone di spazio di archiviazione a svuotamento rapido (BBU RAID o SSD durevoli) non si desidera più di un numero abbastanza piccolo di connessioni di scrittura attiva, forse al massimo il doppio del numero di dischi disponibili, probabilmente inferiore a seconda della disposizione RAID , prestazioni del disco, ecc. In questo caso non vale nemmeno tentativi ed errori; basta aggiornare il sottosistema di archiviazione a uno con svuotamenti rapidi del disco .

Cerca pg_test_fsyncuno strumento che ti aiuti a determinare se questo potrebbe essere un problema per te. La maggior parte dei pacchetti PostgreSQL installa questo strumento come parte di contrib, quindi non è necessario compilarlo. Se si ottengono meno di un paio di migliaia di operazioni al secondo, pg_test_fsyncè necessario aggiornare urgentemente il sistema di archiviazione. Il mio laptop dotato di SSD riceve 5000-7000. La mia workstation al lavoro con un array RAID 10 a 4 dischi di dischi SATA a 7200 rpm e write-through (senza cache di scrittura) ottiene circa 80 ops / secondo in f_datasync, fino a 20 ops / secondo per fsync(); è centinaia di volte più lento . Confronta: laptop con ssd vs workstation con write-through (non write-caching) RAID 10. L'SSD di questo laptop è economico e non mi fido necessariamente di svuotare la cache di scrittura in caso di interruzione dell'alimentazione; Conservo buoni backup e non li userei per i dati a cui tengo. Gli SSD di buona qualità funzionano altrettanto bene se non meglio e sono resistenti alla scrittura.

Nel caso della tua domanda, ti consiglio vivamente di esaminare:

  • Un buon sottosistema di archiviazione con vampate veloci. Non posso sottolineare abbastanza. SSD power-fail-safe di buona qualità e / o un controller RAID con cache di riscrittura con protezione dell'alimentazione.
  • Utilizzando le UNLOGGEDtabelle per i dati che puoi permetterti di perdere. Aggregalo periodicamente in tabelle registrate. Ad esempio, mantieni i giochi in corso in tabelle non blog e scrivi i punteggi in normali tabelle durature.
  • Utilizzo di un commit_delay(meno utile con archiviazione a flusso rapido - suggerimento)
  • Disattivazione synchronous_commitper transazioni che puoi permetterti di perdere (meno utile con archiviazione a flusso rapido - suggerimento suggerimento)
  • Tabelle di partizionamento, in particolare tabelle in cui i dati "invecchiano" e vengono ripuliti. Invece di eliminare da una tabella partizionata, rilasciare una partizione.
  • Indici parziali
  • Riduzione del numero di indici creati. Ogni indice ha un costo di scrittura.
  • Lavorare in batch in transazioni più grandi
  • Utilizzo di repliche hot standby di sola lettura per rimuovere il carico di lettura dal DB principale
  • Utilizzo di un livello di memorizzazione nella cache come memcached o redis per i dati che cambiano meno spesso o possono permettersi di essere obsoleti. È possibile utilizzare LISTENe NOTIFYper eseguire l'annullamento della cache utilizzando i trigger nelle tabelle PostgreSQL.

In caso di dubbi: http://www.postgresql.org/support/professional_support/

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.