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