Snažím se dostat PostgreSQL k agresivnímu automatickému vakuování mé databáze. Aktuálně jsem nakonfiguroval automatické vakuum takto:
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é!
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.
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.
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;
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.
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 |
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;