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_postgres
script 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 INSERT
e UPDATE
s 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 = off
se è 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_fsync
uno 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
UNLOGGED
tabelle 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_commit
per 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
LISTEN
e NOTIFY
per eseguire l'annullamento della cache utilizzando i trigger nelle tabelle PostgreSQL.
In caso di dubbi: http://www.postgresql.org/support/professional_support/
synchronous_commit = off
o uncommit_delay
?