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

Gestire il blocco in PostgreSQL

Postgres contiene un orizzonte degli eventi in movimento, che è in effetti di circa 2 miliardi di transazioni prima o dopo l'ID transazione corrente. Le transazioni fino a 2 miliardi in anticipo o più di 2 miliardi in ritardo rispetto all'ID transazione corrente sono considerate future e saranno quindi invisibili alle transazioni correnti.

Postgres evita questa catastrofica perdita di dati contrassegnando in modo speciale le vecchie righe in modo che, indipendentemente da dove si trovino in relazione all'ID transazione corrente, saranno visibili.

Il congelamento è questo processo di marcatura delle vecchie tuple live (cioè le righe del database) in modo che non vengano investite dall'orizzonte degli eventi in movimento che altrimenti le farebbe sembrare in futuro. Ciò è in contrasto con l'aspirazione, che è la liberazione dello spazio consumato dalle vecchie tuple morte che non sono più visibili a nessuna transazione.

Entrambi i processi sono gestiti dal vuoto.

Esistono diverse impostazioni che regolano il modo in cui viene eseguito il congelamento.

Innanzitutto, vacuum_freeze_min_age determina se una tupla verrà congelata o meno mentre il vuoto sta già guardando una pagina per vedere se ha tuple morte che possono essere ripulite. Tuple più vecchie di vacuum_freeze_min_age sarà congelato in questo caso. Impostare questo valore basso significa che ci sarà meno lavoro da fare in seguito, ma con il possibile costo di uno sforzo aggiuntivo sia nella CPU che nell'attività IO o WAL. In genere probabilmente si desidera impostare almeno alcune ore di transazioni. Diciamo che ti aspetti di eseguire fino a 2000 transazioni al secondo a una velocità sostenuta. 2000 TPS corrispondono a 7,2 milioni di transazioni all'ora. Quindi un'impostazione abbastanza aggressiva per questo caso potrebbe essere dire 20 m. L'impostazione predefinita è 50 m. Allo stesso modo per vacuum_multixact_freeze_min_age . Nota che i contatori transaction_id e multixid sono indipendenti:devi tenerne traccia di entrambi.

In secondo luogo, ci sono vacuum_freeze_table_age e vacuum_multixact_freeze_table_age . Queste impostazioni determinano quando l'autovacuum non esaminerà solo le pagine che potrebbero avere righe morte, ma qualsiasi pagina che potrebbe avere righe non bloccate. Le impostazioni predefinite per queste impostazioni sono 150 m. Se hai ridotto vacuum_freeze_min_age abbastanza, in molti casi questo vuoto più aggressivo avrà poco o nessun lavoro da fare. In ogni caso, questo processo non è così impegnativo come una volta, poiché le versioni moderne di Postgres (9.6 e successive) mantengono una mappa delle pagine in cui tutte le tuple sono bloccate e visitano solo quelle pagine che non sono tutte bloccate. Ciò significa che non si tratta più di una scansione completa della tabella.

Infine c'è autovacuum_freeze_max_age . Se l'ultima volta che la tabella è stata scansionata completamente alla ricerca di righe non bloccate è stata più di così tante transazioni fa, l'autovacuum avvierà un vuoto anti-avvolgimento sul tavolo. Il valore predefinito è 200 m. Allo stesso modo per autovacuum_multixact_freeze_max_age per cui il valore predefinito è 400 m. Questo è qualcosa che vuoi davvero evitare. Ci sono due cose che si possono fare. In primo luogo, è molto comune aumentare queste impostazioni a qualcosa come 1 miliardo, per avere più margine, specialmente su sistemi che consumano pesanti transazioni. Potresti farne di più ma vuoi avere molto spazio di transazione tra la tua tupla più vecchia e l'orizzonte degli eventi. In secondo luogo, è importante monitorare i sistemi e intraprendere azioni correttive prima che i database si imbattano in questo. Questa azione correttiva spesso include l'aspirazione manuale.

Un problema che può verificarsi è dove hai DDL che provoca l'annullamento del normale (cioè non anti-avvolgimento) autovacuum. Se lo fai abbastanza, alla fine otterrai un vuoto anti-avvolgimento forzato e qualsiasi DDL si metterà in coda dietro il processo di vuoto, e questo a sua volta blocca qualsiasi ulteriore DML. In questa fase la tua tabella è effettivamente illeggibile fino al termine del vuoto. Ciò dipende dal modello di utilizzo del database, ma questa non è solo una possibilità teorica e le distribuzioni e i DBA di Postgres devono tenerne conto.

Il monitoraggio del cluster di database è fondamentale per gestirlo. In particolare è necessario monitorare il datfrozenxid e datminmxid di ogni database nel cluster e, se questi diventano troppo vecchi, intraprendere un'azione correttiva prima che sia necessario un vuoto anti-avvolgimento. Spesso il problema è con una o poche tabelle nel database. Quali sono i problemi possono essere scoperti esaminando il relfrozenxid e relminmxid delle tabelle nel database. Il age() e mxid_age() le funzioni sono utili per scoprire rispettivamente l'età degli ID transazione e dei contatori multixid.

Il congelamento non è qualcosa che puoi evitare, è un'attività di manutenzione essenziale in Postgres che deve essere gestita attivamente.