Postgresql deadlocks
Tomas Vondra
tv na fuzzy.cz
Čtvrtek Březen 1 23:28:43 CET 2012
Ahoj,
tohle je hodně "postgresql specific" dotaz, možná by bylo lepší to řešit
spíš v http://groups.google.com/group/postgresql-cz ...
On 1.3.2012 15:12, Martin Tiršel wrote:
> Zdravim,
>
> mam nad Djangom a Postgresql postavenu aplikaciu a od vcera sa mi zacali
> (bez zmeny v aplikacii) objavovat deadlocky v PG. Doteraz to za niekolko
> mesiacov nenastalo, medzitym sa aplikacia prerabala a na novej verzii
> bezi niekolko tyzdnov. Doteraz nebol jediny problem s tymto. Od vcera
> kazdych niekolko minut, hoci aplikacia updatovana nebola, len pribudaju
> nove data v databaze.
Deadlocky souvisí s časováním a jejich pravděpodobnost často závisí
např. na objemu dat. Málo dat -> zámky jsou drženy jen krátce -> malá
pravděpodobnost že dojde k deadlocku. No a jak objem dat (nebo využití
aplikace) roste, zvyšuje se i jejich pravděpodobnost.
Tím nechci říct že to nemůže být chyba v PostgreSQL, ale že to že se
deadlocky původně neobjevovaly vůbec nemusí znamenat že je to nějakou
změnou v PostgreSQL (to je spíše nepravděpodobné, protože síla zámků se
v novějších verzích spíše snižuje).
> Vie ma niekto nasmerovat, na co by som sa mal zamerat, pripadne skusit
> upravit? Logy vyzeraju nejako takto:
>
> 2012-03-01 14:52:27 CET ERROR: deadlock detected
> 2012-03-01 14:52:27 CET DETAIL: Process 10372 waits for ShareLock on
> transaction 130251607; blocked by process 10370.
> Process 10370 waits for ShareLock on transaction 130251610; blocked
> by process 10372.
> Process 10372: UPDATE "advert_advert" SET "views" =
> "advert_advert"."views" + 1 WHERE "advert_advert"."id" = 1152
> Process 10370: UPDATE "advert_advert" SET "views" =
> "advert_advert"."views" + 1 WHERE "advert_advert"."id" = 1153
> 2012-03-01 14:52:27 CET HINT: See server log for query details.
> 2012-03-01 14:52:27 CET STATEMENT: UPDATE "advert_advert" SET "views" =
> "advert_advert"."views" + 1 WHERE "advert_advert"."id" = 1152
Pokud můžete, zaměřte se na pořadí v jakém měníte data. Problém je když
transakce mění data v různém pořadí (např. jedna transakce nejdříve
updatne 1152 a druhý 1153 zatím co druhá 1153 a až pak 1152).
> Medzitym su v logoch tieto zaznamy, ale to s tym zrejme nesuvisi:
>
> 2012-03-01 14:54:01 CET LOG: could not receive data from client:
> Connection reset by peer
> 2012-03-01 14:54:01 CET LOG: unexpected EOF on client connection
> 2012-03-01 14:54:02 CET LOG: could not receive data from client:
> Connection reset by peer
> 2012-03-01 14:54:02 CET LOG: unexpected EOF on client connection
> 2012-03-01 14:56:02 CET LOG: could not receive data from client:
> Connection reset by peer
> 2012-03-01 14:56:02 CET LOG: unexpected EOF on client connection
> 2012-03-01 14:56:02 CET LOG: could not receive data from client:
> Connection reset by peer
> 2012-03-01 14:56:02 CET LOG: unexpected EOF on client connection
Tohle většinou znamená že spadlo spojení (např. kvůli síťové chybě) nebo
klientská aplikace z nějakého neznámého důvodu spadla aniž by se
korektně odpojila (tj. buď je programátor čuně a nezavolal "close" nebo
aplikace např. spadla na segfault).
> Ak zadam tuto query (pripadne dalsie, ktore sa uvadzaju na
> http://wiki.postgresql.org/wiki/Lock_Monitoring pri rieseni problemo s
> uzamykanim):
>
> select relation::regclass, * from pg_locks where not granted;
>
> tak mi to ziadne zaznamy nevrati.
Problém je že tyhle dotazy ukazují "živá data" tj. jak to vypadá právě
teď - neumožňuje vám to nahlédnout jak to vypadalo v okamžiku deadlocku.
Osobně bych postupoval asi takto:
1) Základní review kódu - v jakém pořadí se ta data aktualizují (často
stačí např. na začátku setřídit data a pak je měnit v tomhle pořadí).
2) Snaha reprodukovat ten bug na jiném stroji - většinou se ví v rámci
jaké transakce to hází chybu, takže stačí např. udělat stress test s
velkým počtem klientů a ono k deadlocku dojde i častěji než na
produkčním systému. Jakmile máte reprodukovatelný testcase, je to
řádově jednodušší opravit (ať už je to aplikační chyba nebo chyba
přímo v PostgreSQL).
3) Pokud předchozí možnosti nepomáhají, nastupuje BRUTUS metoda,
spočívající v zapnutí logování všech příkazů. V okamžiku kdy dojde k
deadlocku je pak celkem jednoduché vydedukovat z toho kolidující
transakce pomocí PID (je třeba to doplnit do log_line_prefix). Tohle
ale může být na produkčním systému značná zátěž a současně to může
ovlivnit časování tak že k deadlockům nebude docházet.
T.
Další informace o konferenci Linux