PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL funziona lentamente? Suggerimenti e trucchi per arrivare alla fonte

In qualità di amministratore di database PostgreSQL, ci sono le aspettative quotidiane per controllare i backup, applicare modifiche DDL, assicurarsi che i registri non contengano ERRORI che interrompono il gioco e rispondere alle chiamate in preda al panico di sviluppatori i cui rapporti vengono eseguiti il ​​doppio del normale e loro avere una riunione tra dieci minuti.

Anche con una buona comprensione dello stato di salute dei database gestiti, emergeranno sempre nuovi casi e nuovi problemi relativi alle prestazioni e al modo in cui il database "si sente". Che si tratti di un'e-mail in preda al panico o di un ticket aperto per "il database sembra lento", questa attività comune può generalmente essere seguita con alcuni passaggi per verificare se c'è o meno un problema con PostgreSQL e quale potrebbe essere.

Questa non è in alcun modo una guida esauriente, né i passaggi devono essere eseguiti in un ordine specifico. Ma è piuttosto una serie di passi iniziali che possono essere presi per aiutare a trovare rapidamente i criminali comuni, oltre a ottenere nuove informazioni su quale potrebbe essere il problema. Uno sviluppatore può sapere come agisce e come risponde l'applicazione, ma l'amministratore del database sa come agisce e come risponde il database all'applicazione e, insieme, è possibile individuare il problema.

NOTA: Le query da eseguire devono essere eseguite come superutente, come "postgres" o qualsiasi utente del database a cui sono state concesse le autorizzazioni di superutente. Gli utenti limitati verranno negati o i dati verranno omessi.

Fase 0:raccolta di informazioni

Ottieni quante più informazioni possibili da chi dice che il database sembra lento; query specifiche, applicazioni collegate, tempi di rallentamento delle prestazioni, ecc. Più informazioni forniscono, più facile sarà trovare il problema.

Passaggio 1:verifica pg_stat_activity

La richiesta può assumere molte forme diverse, ma se la "lentezza" è il problema generale, controllare pg_stat_activity è il primo passo per capire cosa sta succedendo. La vista pg_stat_activity (la documentazione per ogni colonna in questa vista può essere trovata qui) contiene una riga per ogni processo del server/connessione al database da un client. Ci sono alcune informazioni utili in questa visualizzazione che possono aiutare.

NOTA: È noto che pg_stat_activity cambia struttura nel tempo, perfezionando i dati che presenta. La comprensione delle colonne stesse aiuterà a creare query dinamicamente secondo necessità in futuro.

Le colonne degne di nota in pg_stat_activity sono:

  1. query:una colonna di testo che mostra la query che è attualmente in esecuzione, in attesa di essere eseguita o è stata eseguita l'ultima volta (a seconda dello stato). Questo può aiutare a identificare quali query/query segnalate da uno sviluppatore vengono eseguite lentamente.
  2. client_addr:l'indirizzo IP da cui hanno avuto origine questa connessione e questa query. Se vuoto (o Null), è originato da localhost.
  3. backend_start, xact_start, query_start:questi tre forniscono rispettivamente un timestamp di quando ciascuno è stato avviato. Backend_start rappresenta quando è stata stabilita la connessione al database, xact_start è quando è iniziata la transazione corrente e query_start è quando è iniziata la query corrente (o ultima).
  4. stato:lo stato della connessione al database. Attivo significa che sta attualmente eseguendo una query, "inattivo" significa che è in attesa di ulteriori input dal cliente, "inattivo in transazione" significa che è in attesa di ulteriori input dal cliente mentre è in attesa di una transazione aperta. (Ce ne sono altri, tuttavia la loro probabilità è rara, consulta la documentazione per maggiori informazioni).
  5. datname:il nome del database a cui è attualmente connessa la connessione. In più cluster di database, questo può aiutare a isolare le connessioni problematiche.
  6. wait_event_type e wait_event:queste colonne saranno nulle quando una query non è in attesa, ma se è in attesa conterranno informazioni sul motivo per cui la query è in attesa e l'esplorazione di pg_locks può identificare cosa sta aspettando. (PostgreSQL 9.5 e precedenti ha solo una colonna booleana chiamata 'waiting', true se wait, false in caso contrario.

1.1. La query è in attesa/bloccata?

Se è presente una o più query specifiche "lente" o "bloccate", verifica se sono in attesa del completamento di un'altra query. A causa del blocco delle relazioni, altre query possono bloccare una tabella e impedire ad altre query di accedere o modificare i dati fino al completamento della query o della transazione.

PostgreSQL 9.5 e precedenti:

SELECT * FROM pg_stat_activity WHERE waiting = TRUE;

PostgreSQL 9.6:

SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL;

PostgreSQL 10 e versioni successive (?):

SELECT * FROM pg_stat_activity WHERE wait_event IS NOT NULL AND backend_type = 'client backend';

I risultati di questa query mostreranno tutte le connessioni attualmente in attesa su un'altra connessione per rilasciare i blocchi su una relazione necessaria.

Se la query è bloccata da un'altra connessione, ci sono alcuni modi per scoprire cosa sono. In PostgreSQL 9.6 e versioni successive, la funzione pg_blocking_pids() consente l'immissione di un ID processo che è stato bloccato e restituirà un array di ID processo responsabili del blocco.

PostgreSQL 9.6 e versioni successive:

SELECT * FROM pg_stat_activity 
WHERE pid IN (SELECT pg_blocking_pids(<pid of blocked query>));

PostgreSQL 9.5 e precedenti:

SELECT blocked_locks.pid     AS blocked_pid,
         blocked_activity.usename  AS blocked_user,
         blocking_locks.pid     AS blocking_pid,
         blocking_activity.usename AS blocking_user,
         blocked_activity.query    AS blocked_statement,
         blocking_activity.query   AS current_statement_in_blocking_process
   FROM  pg_catalog.pg_locks         blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks 
        ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
   WHERE NOT blocked_locks.GRANTED;

(Disponibile dal wiki di PostgreSQL).

Queste query punteranno a qualsiasi cosa stia bloccando un PID specifico fornito. Con ciò, è possibile prendere la decisione di terminare la query o la connessione bloccante o lasciarla eseguire.

Passaggio 2 - Se le query sono in esecuzione, perché impiegano così tanto tempo?

2.1. Il pianificatore esegue le query in modo efficiente?

Se una query (o un insieme di query) in questione ha lo stato "attivo", allora è effettivamente in esecuzione. Se l'intera query non è disponibile in pg_stat_activity, recuperala dagli sviluppatori o dal log di postgresql e inizia a esplorare il pianificatore di query.

EXPLAIN SELECT * FROM postgres_stats.table_stats t JOIN hosts h ON (t.host_id = h.host_id) WHERE logged_date >= '2018-02-01' AND logged_date < '2018-02-04' AND t.india_romeo = 569;
Nested Loop  (cost=0.280..1328182.030 rows=2127135 width=335)
  ->  Index Scan using six on victor_oscar echo  (cost=0.280..8.290 rows=1 width=71)
          Index Cond: (india_romeo = 569)
  ->  Append  (cost=0.000..1306902.390 rows=2127135 width=264)
        ->  Seq Scan on india_echo romeo  (cost=0.000..0.000 rows=1 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on juliet victor_echo  (cost=0.000..437153.700 rows=711789 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on india_papa quebec_bravo  (cost=0.000..434936.960 rows=700197 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))
        ->  Seq Scan on two oscar  (cost=0.000..434811.720 rows=715148 width=264)
                Filter: ((logged_date >= '2018-02-01'::timestamp with time zone) AND (logged_date < '2018-02-04'::timestamp with time zone) AND (india_romeo = 569))

Questo esempio mostra un piano di query per un join di due tabelle che raggiunge anche una tabella partizionata. Stiamo cercando qualsiasi cosa che possa rallentare la query e in questo caso il pianificatore sta eseguendo diverse scansioni sequenziali sulle partizioni, suggerendo che mancano gli indici. L'aggiunta di indici a queste tabelle per la colonna "india_romeo" migliorerà immediatamente questa query.

Le cose da cercare sono scansioni sequenziali, loop nidificati, ordinamento costoso, ecc. La comprensione del pianificatore di query è fondamentale per assicurarsi che le query funzionino nel modo migliore possibile, per ulteriori informazioni è possibile leggere la documentazione ufficiale qui.

2.2. I tavoli coinvolti sono gonfi?

Se le query sono ancora lente senza che il pianificatore di query indichi qualcosa di ovvio, è il momento di controllare lo stato delle tabelle coinvolte. Sono troppo grandi? Sono gonfi?

SELECT n_live_tup, n_dead_tup from pg_stat_user_tables where relname = ‘mytable’;
n_live_tup  | n_dead_tup
------------+------------
      15677 |    8275431
(1 row)

Qui vediamo che ci sono molte volte più righe morte rispetto alle righe attive, il che significa che per trovare le righe corrette, il motore deve setacciare dati che non sono nemmeno rilevanti per trovare dati reali. Un vuoto/vuoto pieno su questo tavolo aumenterà notevolmente le prestazioni.

Fase 3:controlla i registri

Se il problema persiste, controlla i log per eventuali indizi.

Messaggi FATAL / ERRORE:

Cerca i messaggi che potrebbero causare problemi, come deadlock o lunghi tempi di attesa per ottenere un blocco.

Punti di controllo

Si spera che log_checkpoints sia impostato su on, che scriverà le informazioni sul checkpoint nei log. Esistono due tipi di checkpoint, a tempo ea richiesta (forzata). Se i checkpoint vengono forzati, i buffer sporchi in memoria devono essere scritti su disco prima di elaborare più query, il che può dare a un sistema di database una sensazione generale di "lentezza". L'aumento di checkpoint_segments o max_wal_size (a seconda della versione del database) darà al checkpointer più spazio con cui lavorare, oltre ad aiutare lo scrittore in background a prendere parte del carico di scrittura.

Fase 4 - Qual è lo stato del sistema host?

Se non ci sono indizi nel database stesso, forse l'host stesso è sovraccarico o presenta problemi. Qualsiasi cosa, da un canale IO sovraccaricato su disco, memoria in eccesso per lo scambio o persino un'unità guasta, nessuno di questi problemi sarebbe evidente con qualsiasi cosa abbiamo visto prima. Supponendo che il database sia in esecuzione su un sistema operativo *nix, ecco alcune cose che possono aiutare.

4.1. Carico del sistema

Usando "top", guarda la media del carico per l'host. Se il numero si avvicina o supera il numero di core nel sistema, potrebbero essere semplicemente troppe connessioni simultanee che colpiscono il database portandolo a una scansione per recuperare.

load average: 3.43, 5.25, 4.85

4.2. Memoria di sistema e SWAP

Usando "gratuito", controlla se SWAP è stato utilizzato. L'overflow di memoria nello SWAP in un ambiente di database PostgreSQL è estremamente negativo per le prestazioni e molti DBA elimineranno persino lo SWAP dagli host di database, poiché per molti è preferibile un errore di "memoria insufficiente" rispetto a un sistema lento.

Se viene utilizzato SWAP, un riavvio del sistema lo cancellerà e potrebbe essere necessario aumentare la memoria totale del sistema o riconfigurare l'utilizzo della memoria per PostgreSQL (come la riduzione di shared_buffers o work_mem).

[[email protected] ~]$ free -m
              total        used        free      shared  buff/cache   available
Mem:           7986         225        1297          12        6462        7473
Swap:          7987        2048        5939

4.3. Accesso al disco

PostgreSQL tenta di fare molto del suo lavoro in memoria e di distribuire la scrittura su disco per ridurre al minimo i colli di bottiglia, ma su un sistema sovraccarico con scritture pesanti, è facilmente possibile vedere letture e scritture pesanti rallentare l'intero sistema mentre recupera sulle richieste. Dischi più veloci, più dischi e canali IO sono alcuni modi per aumentare la quantità di lavoro che può essere svolto.

Strumenti come "iostat" o "iotop" possono aiutare a individuare se c'è un collo di bottiglia del disco e da dove potrebbe provenire.

4.4. Controlla i log

Se tutto il resto fallisce, o anche in caso contrario, i registri dovrebbero sempre essere controllati per vedere se il sistema segnala qualcosa che non va. Abbiamo già discusso del controllo di postgresql.logs, ma i registri di sistema possono fornire informazioni su problemi come dischi guasti, memoria difettosa, problemi di rete, ecc. Ognuno di questi problemi può causare un comportamento lento e imprevedibile del database, quindi una buona comprensione di perfetta salute può aiutare a trovare questi problemi.

Scarica il whitepaper oggi Gestione e automazione di PostgreSQL con ClusterControlScopri cosa devi sapere per distribuire, monitorare, gestire e ridimensionare PostgreSQLScarica il whitepaper

Passaggio 5 - Qualcosa ancora non ha senso?

Anche gli amministratori più esperti si imbatteranno in qualcosa di nuovo che non ha senso. È qui che la comunità globale di PostgreSQL può intervenire per dare una mano. Proprio come il passaggio n. 0, più informazioni chiare vengono fornite alla community, più facile può dare una mano.

5.1. Mailing list di PostgreSQL

Poiché PostgreSQL è sviluppato e gestito dalla comunità open source, ci sono migliaia di persone che parlano attraverso le mailing list per discutere innumerevoli argomenti tra cui funzionalità, errori e problemi di prestazioni. Le mailing list possono essere trovate qui, con pgsql-admin e pgsql-performance che sono le più importanti per cercare aiuto con problemi di prestazioni.

5.2. IRC

Freenode ospita diversi canali PostgreSQL con sviluppatori e amministratori in tutto il mondo e non è difficile trovare una persona utile per rintracciare da dove potrebbero provenire i problemi. Maggiori informazioni possono essere trovate sulla pagina IRC di PostgreSQL.