sql >> Databáze >  >> RDS >> PostgreSQL

Když autovakuum nevysává

Před pár týdny jsem vysvětlil základy autovakuového ladění. Na konci tohoto příspěvku jsem slíbil, že se brzy podívám na problémy s vysáváním. No, trvalo to trochu déle, než jsem plánoval, ale je to tady.

Pro rychlou rekapitulaci autovacuum je proces na pozadí, který čistí mrtvé řádky, např. staré smazané verze řádků. Čištění můžete také provést ručně spuštěním VACUUM , ale autovacuum dělá to automaticky v závislosti na množství mrtvých řádků v tabulce ve správný okamžik – ne příliš často, ale dostatečně často, aby udrželo množství „odpadu“ pod kontrolou.

Obecně řečeno, autovacuum nemůže běžet příliš často – čištění se provádí až po dosažení určitého počtu nahromaděných mrtvých řádků v tabulce. Může se však z různých důvodů zpozdit, což má za následek, že tabulky a indexy budou větší, než je žádoucí. A to je přesně téma tohoto příspěvku. Jací jsou tedy běžní viníci a jak je identifikovat?

Omezování

Jak je vysvětleno v Základech ladění, autovacuum pracovníci jsou omezeni, aby vykonali pouze určité množství práce za časový interval. Výchozí limity jsou poměrně nízké – asi 4 MB/s pro zápis, 8 MB/s pro čtení. To je vhodné pro malé stroje jako Raspberry Pi nebo malé servery z doby před 10 lety, ale současné stroje jsou mnohem výkonnější (jak z hlediska CPU, tak I/O) a zpracovávají mnohem více dat.

Představte si, že máte několik velkých stolů a několik malých. Pokud všechny tři autovacuum pracovníci začnou uklízet velké stoly, žádný z malých stolů nebude vysát bez ohledu na množství mrtvých řad, které se nahromadí. Identifikace není nijak zvlášť obtížná, za předpokladu, že máte dostatečné sledování. Hledejte období, kdy jsou všechna autovacuum pracovníci jsou zaneprázdněni, zatímco stoly nejsou vysávány, přestože hromadí mnoho mrtvých řad.

Všechny potřebné informace jsou v pg_stat_activity (počet autovacuum pracovní procesy) a pg_stat_all_tables (last_autovacuum a n_dead_tup ).

Zvýšení počtu autovacuum pracovníků není řešením, protože celkové množství práce zůstává stejné. Můžete zadat limity omezení pro jednotlivé tabulky, přičemž daného pracovníka z celkového limitu vyloučíte, ale stále to nezaručuje, že v případě potřeby budou k dispozici pracovníci.

Správným řešením je vyladění omezení pomocí limitů přiměřených s ohledem na konfiguraci hardwaru a vzorce pracovní zátěže. Některá základní doporučení ohledně omezení jsou zmíněna v předchozím příspěvku. (Je zřejmé, že pokud můžete snížit množství mrtvých řádků generovaných v databázi, bylo by to ideální řešení.)

Od tohoto bodu budeme předpokládat, že problém není omezování, tj. že autovacuum pracovníci nejsou nasyceni po dlouhou dobu a že úklid je spuštěn na všech stolech bez nepřiměřených prodlev.

Dlouhé transakce

Takže pokud je stůl pravidelně vysáván, určitě se na něm nemůže nashromáždit mnoho mrtvých řádků, že? Bohužel ne. Řádky nejsou ve skutečnosti „odstranitelné“ ihned po smazání, ale pouze v případě, že neexistují žádné transakce, které by je mohly vidět. Přesné chování závisí na tom, co (dělají) ostatní transakce a na úrovni serializace, ale obecně:

ČTĚTE ODPOVĚDĚNO

  • vyčištění bloku spuštěných dotazů
  • nečinné transakce blokují vyčištění pouze v případě, že provedly zápis
  • nečinné transakce (bez jakýchkoli zápisů) nezablokují čištění (ale není dobrým zvykem je udržovat)

SERIALIZOVATELNÉ

  • vyčištění bloku spuštěných dotazů
  • Čištění bloku nečinných transakcí (i když prováděly pouze čtení)

V praxi je to samozřejmě jemnější, ale vysvětlení všech různých bitů by vyžadovalo nejprve vysvětlit, jak XID a snímky fungují, a to není cílem tohoto příspěvku. Co byste si z toho měli skutečně odnést je, že dlouhé transakce jsou špatný nápad, zvláště pokud by tyto transakce mohly způsobit zápisy.

Samozřejmě existují naprosto oprávněné důvody, proč možná budete muset uchovávat transakce po dlouhou dobu (např. pokud potřebujete zajistit ACID pro všechny změny). Dejte si ale pozor, aby se to zbytečně nestalo, kupř. kvůli špatnému návrhu aplikace.

Poněkud neočekávaným důsledkem toho je vysoké využití CPU a I/O kvůli autovacuum běhat znovu a znovu, aniž by se vyčistily mrtvé řady (nebo jen několik z nich). Kvůli tomu jsou stoly stále způsobilé k vyčištění v příštím kole, což způsobí více škody než užitku.

Jak to zjistit? Nejprve musíte sledovat dlouhotrvající transakce, zejména ty nečinné. Vše, co musíte udělat, je načíst data z pg_stat_activity . Definice pohledu se s verzí PostgreSQL trochu mění, takže to možná budete muset trochu upravit:

SELECT xact_start, state FROM pg_stat_activity;

-- count 'idle' transactions longer than 15 minutes (since BEGIN)
SELECT COUNT(*) FROM pg_stat_activity
 WHERE state = 'idle in transaction'
  AND (now() - xact_start) > interval '15 minutes'

-- count transactions 'idle' for more than 5 minutes
SELECT COUNT(*) FROM pg_stat_activity
 WHERE state = 'idle in transaction'
  AND (now() - state_change) > interval '5 minutes'

Můžete také jednoduše použít některý stávající monitorovací plugin, např. check_postgres.pl. Ty již zahrnují tento typ kontroly zdravého rozumu. Budete se muset rozhodnout, jaká je přiměřená doba trvání transakce/dotazu, která je specifická pro aplikaci.

Od PostgreSQL 9.6 můžete také použít idle_in_transaction_session_timeout takže transakce nečinné příliš dlouho jsou automaticky ukončeny. Podobně pro dlouhé dotazy existuje statement_timeout .

Další užitečnou věcí je VACUUM VERBOSE což vám ve skutečnosti řekne, kolik mrtvých řad se ještě nepodařilo odstranit:

db=# VACUUM verbose z;
INFO:  vacuuming "public.z"
INFO:  "z": found 0 removable, 66797 nonremovable row versions in 443 out of 443 pages
DETAIL:  12308 dead row versions cannot be removed yet.
...

Neřekne vám, který backend brání vyčištění, ale je to docela jasné znamení toho, co se děje.

Poznámka: . Tyto informace nemůžete snadno získat z autovacuum protože je přihlášen pouze pomocí DEBUG2 ve výchozím nastavení (a určitě nechcete s touto úrovní protokolu běžet v produkci).

Dlouhé dotazy v pohotovostních režimech

Předpokládejme, že tabulky jsou vysávány včas, ale neodstraňují se mrtvé n-tice, což vede k nadýmání tabulek a indexů. Sledujete pg_stat_activity a neexistují žádné dlouhodobé transakce. V čem by mohl být problém?

Pokud máte streamovací repliku, je pravděpodobné, že problém může být tam. Pokud replika používá hot_standby_feedback=on , dotazy na replice fungují v podstatě jako transakce na primární, včetně čištění blokování. Samozřejmě hot_standby_feedback=on se používá přesně při spouštění dlouhých dotazů (např. analytické a BI úlohy) na repliky, aby se zabránilo zrušení kvůli konfliktům replikace.

Bohužel si budete muset vybrat – buď ponechat hot_standby_feedback=on a přijmout zpoždění při čištění nebo se vypořádat se zrušenými dotazy. Můžete také použít max_standby_streaming_delay abyste omezili dopad, i když to zcela nezabrání zrušením (takže stále musíte opakovat dotazy).

Ve skutečnosti je nyní třetí možnost – logická replikace. Namísto použití replikace fyzického streamování pro repliku BI můžete změny zkopírovat pomocí nové logické replikace, která je k dispozici v PostgreSQL 10. Logická replikace uvolňuje spojení mezi primární a replikou a činí clustery většinou nezávislými (jsou čištěny nezávisle, atd.).

To řeší dva problémy spojené s replikací fyzického streamování – zpožděné čištění primárních nebo zrušených dotazů na repliku BI. Pro repliky sloužící účelům DR však zůstává správnou volbou streamingová replikace. Ale tyto repliky nespouštějí (nebo by neměly být) dlouhé dotazy.

Poznámka: I když jsem zmínil, že logická replikace bude dostupná v PostgreSQL 10, významná část infrastruktury byla dostupná v předchozích verzích (zejména PostgreSQL 9.6). Takže to možná budete moci udělat i na starších verzích (to jsme udělali pro některé naše zákazníky), ale PostgreSQL 10 to udělá mnohem pohodlnější a pohodlnější.

Potíže s autoanalyze

Detail, který vám může uniknout, je autovacuum pracovníci ve skutečnosti plní dva různé úkoly. Nejprve čištění (jako byste spouštěli VACUUM ), ale také shromažďování statistik (jako byste spouštěli ANALYZE ). A obě díly jsou omezeny pomocí autovacuum_cost_limit .

Velký rozdíl je ale ve zpracování transakcí. Kdykoli VACUUM část dosáhne autovacuum_cost_limit , pracovník uvolní snímek a na chvíli usne. ANALYZE musí však běžet v jediném snímku/transakci, což dělá čištění bloku.

Toto je elegantní způsob, jak se střelit do nohy, zvláště pokud také děláte něco z tohoto:

  • zvýšit default_statistics_target k vytvoření přesnějších statistik z větších vzorků
  • nižší autovacuum_analyze_scale_factor shromažďovat statistiky častěji

Nezamýšleným důsledkem je samozřejmě to, že ANALYZE bude probíhat častěji, bude trvat mnohem déle a bude (na rozdíl od VACUUM část) zabránit čištění. Řešení je obvykle poměrně jednoduché – nesnižujte autovacuum_analyze_scale_factor příliš mnoho. Spuštění ANALYZE pokaždé, když 10 % změn v tabulce bude ve většině případů více než dost.

n_dead_tup

Poslední věc, kterou bych rád zmínil, je o změnách v pg_stat_all_tables.n_dead_tup hodnoty. Můžete si myslet, že hodnota je jednoduchý čítač, který se zvýší vždy, když se vytvoří nová mrtvá n-tice, a sníží se, když se vyčistí. Ale ve skutečnosti je to pouze odhad počtu mrtvých n-tic, který aktualizuje ANALYZE . U malých tabulek (méně než 240 MB) to opravdu není velký rozdíl, protože ANALYZE čte celou tabulku a tak je docela přesná. U velkých tabulek se však může dost změnit v závislosti na tom, jaká podmnožina tabulky je vzorkována. A snížení autovacuum_vacuum_scale_factor dělá to více náhodné.

Buďte tedy opatrní při prohlížení n_dead_tup v monitorovacím systému. Náhlé poklesy nebo zvýšení hodnoty mohou být jednoduše způsobeny ANALYZE přepočítávání jiného odhadu, a ne kvůli skutečnému vyčištění a/nebo novým mrtvým n-ticím, které se objevují v tabulce.

Shrnutí

Abych to shrnul do několika jednoduchých bodů:

  • autovacuum může fungovat pouze v případě, že neexistují žádné transakce, které by mohly potřebovat mrtvé n-tice.
  • Dlouhotrvající dotazy blokují čištění. Zvažte použití statement_timeout k omezení škod.
  • Dlouho trvající transakce může blokovat čištění. Přesné chování závisí na věcech, jako je úroveň izolace nebo co se stalo v transakci. Sledujte je a pokud je to možné, ukončete je.
  • Dlouhotrvající dotazy na repliky pomocí hot_standby_feedback=on může také blokovat čištění.
  • autoanalyze je také přiškrcen, ale na rozdíl od VACUUM část uchovává jeden snímek (a tím blokuje čištění).
  • n_dead_tup je pouze odhad spravovaný ANALYZE , takže počítejte s určitou fluktuací (zejména na velkých stolech).

  1. Určení, zda jsou pole Data v Oracle typu Number

  2. Odstranění událostí z protokolu pošty databáze SQL Server (T-SQL)

  3. Použijte XEvent Profiler k zachycení dotazů na SQL Server

  4. postgresql - počet (žádné hodnoty null) každého sloupce v tabulce