it-swarm-eu.dev

Agresivní autovakum on PostgreSQL

Snažím se dostat PostgreSQL k agresivnímu automatickému vakuování mé databáze. Aktuálně jsem nakonfiguroval automatické vakuum takto:

  • autovacuum_vacuum_cost_delay = 0 #Vypněte vakuum založené na nákladech
  • autovacuum_vacuum_cost_limit = 10000 #Max hodnota
  • autovacuum_vacuum_threshold = 50 # Výchozí hodnota
  • autovacuum_vacuum_scale_factor = 0,2 # Výchozí hodnota

Všiml jsem si, že automatické vakuum se nastartuje pouze tehdy, když není databáze pod zatížením, takže se dostanu do situací, kde je mnohem více mrtvých tuplů než živých n-tic. Příklad naleznete v přiloženém snímku obrazovky. Jedna ze stolů má 23 živých n-licek, ale 16845 mrtvých n-tic čeká na vakuum. To je šílené!

Lots of Dead Tuples

Automatické vakuum se spustí, když testovací běh skončí a databázový server je nečinný, což není to, co chci, protože bych chtěl, aby se automatické vakuum nastartovalo pokaždé, když počet mrtvých tuplů přesáhne 20% živých tuplů + 50, protože databáze byla nakonfigurováno. Automatické vakuum, když je server nečinný, je pro mě zbytečné, protože se očekává, že produkční server zasáhne 1 000 s aktualizací/s po dlouhou dobu, což je důvod, proč musím automatické vakuum spustit, i když je server zatížen.

Chybí mi něco? Jak mohu vynutit automatické vakuum, aby běželo, zatímco je server pod velkým zatížením?

Aktualizace

Může to být problém zamykání? Dotyčné tabulky jsou souhrnné tabulky, které jsou naplněny pomocí spouštěcího prvku po vložení. Tyto tabulky jsou uzamčeny v režimu SHARE ROW EXCLUSIVE, aby se zabránilo souběžným zápisům na stejný řádek.

42
CadentOrange

Eelke má téměř jistotu, že vaše zamykání blokuje autovakum. Autovacuum je navrženo tak, aby úmyslně umožnilo činnost uživatele. Pokud jsou tyto tabulky zamčené, autovacuum je nemůže vysát.

Pro potomstvo jsem však chtěl uvést příklad nastavení pro hyperagresivní autovakum, protože nastavení, která jste dali, to neudělají úplně. Uvědomte si však, že zvýšení agresivity autovacuumu váš problém pravděpodobně nevyřeší. Také si všimněte, že výchozí nastavení autovacuum je založeno na běhu přes 200 testovacích běhů pomocí DBT2 hledajících optimální kombinaci nastavení, takže výchozí hodnoty by měly být považovány za dobré, pokud nemáte solidní důvod přemýšlet jinak, nebo pokud vaše databáze není výrazně mimo. mainstream pro OLTP databáze) (např. malá databáze, která získává 10 000 aktualizací za sekundu, nebo 3TB datový sklad).

Nejprve zapněte protokolování, abyste mohli zkontrolovat, zda autovacuum dělá to, co si myslíte, že je:

log_autovacuum_min_duration = 0

Pak uděláme více pracovníků autovaku a necháme je častěji kontrolovat tabulky:

autovacuum_max_workers = 6
autovacuum_naptime = 15s

Snižme prahové hodnoty pro automatické vakuum a automatickou analýzu, které se spustí dříve:

autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1

autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05 

Pak udělejme autovakum méně přerušitelným, takže se dokončí rychleji, ale za cenu většího dopadu na souběžnou aktivitu uživatelů:

autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

K dispozici je váš úplný program pro obecně agresivní autovakum, což by mohlo být vhodné pro malou databázi, která má velmi vysokou míru aktualizací, ale může mít příliš velký dopad na souběžnou aktivitu uživatelů.

Také si všimněte, že autovacuum parametry lze upravit na tabulku , což je téměř vždy lepší odpověď pro potřebu upravit chování autovacuum .

Opět platí, že je nepravděpodobné, že vyřeší váš skutečný problém.

40
Josh Berkus

Abychom zjistili, které tabulky se vůbec hodí pro autovacuum, lze použít následující dotaz (na základě http://www.postgresql.org/docs/current/static/routine-vacuuming.html ). Všimněte si však, že dotaz nehledá konkrétní nastavení tabulky:

 SELECT psut.relname,
     to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
     to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
     to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
     to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
     to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
         + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
            * pg_class.reltuples), '9G999G999G999') AS av_threshold,
     CASE
         WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
             + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
                * pg_class.reltuples) < psut.n_dead_tup
         THEN '*'
         ELSE ''
     END AS expect_av
 FROM pg_stat_user_tables psut
     JOIN pg_class on psut.relid = pg_class.oid
 ORDER BY 1;
36
pygrac

Ano, jedná se o zamykání. Podle tohoto stránka (nenaplněné) potřebuje VACUUM přístup SDÍLAT UPDATE EXCLUSIVE, který je blokován úrovní zámku, kterou používáte.

Jste si jisti, že potřebujete tento zámek? PostgreSQL je kompatibilní s ACID, takže souběžné zápisy ve většině případů nepředstavují problém, protože PostgreSQL zruší jednu z transakcí, pokud dojde k porušení serializace.

Řádky můžete uzamknout také pomocí VYBRAT PRO UPDATE k uzamčení řádků namísto celé tabulky.

Další alternativou bez blokování by bylo použití transakce úroveň izolace serializovatelné. To by však mohlo mít vliv na výkon ostatních transakcí a měli byste být připraveni na další selhání serializace.

11
Eelke

Pravděpodobně pomůže zvýšení počtu autovakuových procesů a zkrácení doby čekání. Zde je konfigurace pro PostgreSQL 9.1, kterou používám na serveru, který ukládá informace o záloze a v důsledku toho získává hodně aktivity vložení.

http://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html

autovacuum_max_workers = 6              # max number of autovacuum subprocesses
autovacuum_naptime = 10         # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms     # default vacuum cost delay for

Pokusím se také snížit hodnotu cost_delay, aby bylo vakuování agresivnější.

Mohu také vyzkoušet autovacuuming pomocí pgbench.

http://wiki.postgresql.org/wiki/Pgbenchtesting

Příklad s vysokým argumentem:

Vytvořte databázi bench_replication

pgbench -i -p 5433 bench_replication

Spustit pgbench

pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication

Zkontrolujte stav autovakuování

psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
 schemaname |     relname      |        last_autovacuum        
------------+------------------+-------------------------------
 public     | pgbench_branches | 2012-07-18 18:15:34.494932+02
 public     | pgbench_history  | 
 public     | pgbench_tellers  | 2012-07-18 18:14:06.526437+02
 public     | pgbench_accounts | 
6
Craig Efrein

Existující skript „kvalifikovat se na autovakumulaci“ je velmi užitečný, ale (jak bylo správně uvedeno) chyběly specifické možnosti tabulky. Zde je upravená verze, která tyto možnosti zohledňuje:

WITH rel_set AS
(
    SELECT
        oid,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
        END AS rel_av_vac_threshold,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
        END AS rel_av_vac_scale_factor
    FROM pg_class
) 
SELECT
    PSUT.relname,
    to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI')     AS last_vacuum,
    to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
    to_char(C.reltuples, '9G999G999G999')               AS n_tup,
    to_char(PSUT.n_dead_tup, '9G999G999G999')           AS dead_tup,
    to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
    CASE
        WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
        THEN '*'
    ELSE ''
    END AS expect_av
FROM
    pg_stat_user_tables PSUT
    JOIN pg_class C
        ON PSUT.relid = C.oid
    JOIN rel_set RS
        ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
6
Vadim Zingertal