pondělí 7. května 2018

Jak jsem hledat problém s uváznutím (deadlock) v aplikaci Návrh na vklad

ČÚZK vytvořil a provozuje www aplikací Návrh na vklad, která umožňuje uživatelů připravit formulář s návrhem na vklad do katastru nemovitostí. Její součástí jsou i webové služby, které pro generování návrhů využívají např. banky. Vývoj a provoz této aplikace mám na starost se svým týmem.

Při provozu jsme registrovali, že se občas vyskytuje chyba ORA-00060: deadlock detected while waiting for resource, což je problém s uváznutím, kdy se databázové transakce uzamknou proti sobě a ani jedna nemůže pokračovat dál.

Vytvořit deadlock je poměrně jednoduché. Stačí si otevřít dvě session a navodit například následující stav:
Krok Transakce 1 Transakce 2 Popis
    1 UPDATE platy SET plat=1000 WHERE zamestanec_id=1 Transakce 1 si v tabulce PLATY uzamkne záznam pro zaměstnance s ID 1
    2 UPDATE odmeny SET castka=2000 WHERE zamestanec_id=10 Transakce 2 si v tabulce ODMENY uzamkne záznam pro zaměstnance s ID 10
    3 UPDATE odmeny SET castka=500 WHERE zamestanec_id=10 Transakce 1 se pokouší v tabulce ODMENY uzamknout záznam pro zaměstnance s ID 10, což se ji nedaří, protože zámek drží transakce 2 a transakce 1 tedy musí čekat na dokončení transakce 2.
    4 UPDATE platy SET plat=300 WHERE zamestanec_id=1 Transakce 2 se pokouší v tabulce PLATY uzamknout záznam pro zaměstnance s ID 1, což se ji nedaří, protože zámek drží transakce 1 a transakce 2 tedy musí čekat na dokončení transakce 1.

V tento okamžik jsou obě transakce zacyklené. Transakce 1 čeká na dokončení transakce 2, ale ta zase čeká na dokončení transakce 1 a problém s uváznutím je na světě:

(obrázek z http://oracledbpro.blogspot.com/)

Oracle tento stav pomocí backgroud procesu DIAx detekuje, provede roolback příkazu, který ho způsobil a vyhlásí chybu ORA-00060: deadlock detected while waiting for resource.

Malá odbočka. Ohledně deadlocku v Oracle panuje několik mýtů, které je vhodné vyjasnit:
  • Oracle neprovede kill žádné session,
  • Oracle provede rollback příkazu, ale neprovede rollback celé transakce,
  • Oracle background proces PMON (Process Monitor) neuvolní předchozí zámky.
Deadlock se nemusí týkat jen řádků tabulce. Je to jeden ze synchronizačních problému a takto se může uzamknout prakticky cokoli. Hodně se to řeší v operačních systémech a je to velmi zajímavá problematika.

Zpět k naší aplikaci. Chyba ORA-00060 se nám občas vyskytovala v situaci, kdy uživatel, nebo automatický proces, mazal návrh na vklad. Vyskytovala se poměrně zřídka, ale časem začala narůstat na několik výskytů denně. 99 % bylo vyvoláno z automatického procesu, bez vlivu na uživatele, který chybu ani nepoznal.

Pokud se problém s deadlockem vyskytuje v aplikaci, tak je jeho příčina nejčastěji buď chyba v návrhu aplikace nebo chyba v datovém modelu. Většinou se špatně hledá.

Naše aplikace má jednoduchý datový model, který se skládá z cca 70 tabulek. Chyba se vyskytovala při mazání jedné z tabulek NEMOVITOSTI, STAVBY nebo PARCELY. Datový model této části vypadá zhruba takto:
část datového modelu


Při kontrole mazací procedury jsem nenarazil na problém, tak jsem se zaměřil na datový model. Ten jsem prošel, ale také mě nic do oka netrklo, tak jsem musel zkoumat dál. Oracle při výskytu chyby zapíše událost do alert logu (píši se zde všechny důležité události, která v databázi vznikly) a vytvoří trace soubor:
ukázka alert logu

ukázka trace (mívá jednotky až stovky MB)


Otevřel jsem trace a viděl, že problém v tomto případě vznikl při mazání záznamů z tabulky STAVBY:
mazané tabulky

Znovu jsem prověřil danou část modelu, ale vše vypadalo OK. Pátral jsem tedy dál. V trace je graf deadlocku:

Z něj jde vyčíst, že je problém v resource se jménem TM-003f719d-00000000 (viz (1)), kdy transakce má zámek typu SX a čeká na typ SSX. Zámek typu SX, na rozdíl od SSX, může získat pouze jedna transakce. Podle toho, že se nečekalo na uzamknutí řádků (viz (2)), bylo jasné, že se jednalo o problém přímo s uzamknutím celého databázovém objektu (tabulka, index, ...). Jak ho ale zjistit? 
Struktura jména resource TM-003f719d-00000000 mi nic neříkala a nedokázal jsem odvodit, z čeho je složena. Oracle má sice metadata o svých objektech, ale jsou to ID typu NUMBER (sloupec OBJECT_ID), takže tudy cesta nevedla:
pohled DBA_OBJECTS 

Po dalším pátrání na Oracle Metalinku se mi podařilo dohledat dokument Doc ID 62365.1, ve kterém se píše:
dokument Doc ID 62365.1

Takže TM je typ zámku a 003f719d je ID objektu, ale v HEX formátu (pozn.: také mě to mohlo napadnout :-) ). Převedl jsem tedy 003f719d do desítkové soustavy (4157853) a podíval se do metadat, kterému databázovému objektu patří:
identifikace objeku

Problém tedy vznikl při pokusu o uzamknutí tabulky PARCELY_PARCELY.  Při kontrola dalších trace se vždy jednalo pouze o tuto tabulku. Struktura tabulky je jednoduchá, její účel je pouze vazba mezi původními a nově vznikajícími parcelami. Má jen dva sloupce VZNIKAJICI_PARCELY_ID a PUVODNI_PARCELY_ID a oba se přes cizí klíče (FK) odkazují do tabulky PARCELY. Proč se ale zamykala celá? 
Podíval jsem se na indexy a bylo jasno. Tabulka měla sice složený index nad oběma sloupci, ale ne nad sloupcem PUVODNI_PARCELY_ID:
indexy na tabulce PARCELY_PARCELY

To je sice v pořádku pro logiku aplikace, protože se k tabulce vždy přistupuje i přes VZNIKAJICI_PARCELY_ID, ale problém vznikne, když se má mazat záznam v tabulce PARCELY (kde se maže i při mazání STAVBY nebo NEMOVITOSTI). Oracle se musí v ten okamžik podívat do tabulky PARCELY_PARCELY, zda tam nejsou záznamy, které by mazání bránily. Pokud se kontroluje obsah sloupce VZNIKAJICI_PARCELY_ID, tak použije index a je to OK. Ale pokud se kontroluje obsah sloupce PUVODNI_PARCELY_ID, tak se díky chybějícímu indexu uzamkne celá tabulka, což je problém. Aplikace sama o sobě index na tom sloupci nepotřebuje, ale Oracle už ano. 

Řešení bylo jednoduché - vytvoření nového indexu nad sloupcem PUVODNI_PARCELY_ID. Oracle tak při kontrole FK využije index, uzamkne pouze dané záznamy a nikoli celou tabulku. Tohle pracovníkovi při návrhu databáze nedošlo a bývá to poměrně častá chyba. Po vytvoření indexu chyba zmizela, jako mávnutím kouzelného proutku. Problém byl vyřešen a tím mé pátrání skončilo. 

Na závěr bych chtěl dodat, že by z toho mohl plynout závěr, že by se měl na každý sloupec, který obsahuje FK, udělat index a byl by pokoj. Mělo by tedy stačit zkontrolovat, např. jednoduchým dotazem do metadat Oracle, zda každý takový sloupec index má. To ale není dobrý přístup. Sice se vyhnete těmto problémům, ale budete nutit Oracle tento index udržovat, což stojí nějaké zdroje (disk, I/O, CPU). Je to třeba posuzovat případ od případu. Pokud se například odkazujete na číselníkovou položku, která se nemaže (číselníkové položky se typicky jen zneplatní), tak index potřeba není, protože tam žádná kontrola neprobíhá.


čtvrtek 28. prosince 2017

Recenze audioknihy „Peter May – Pán ohně“

Kniha tvoří první díl série Čínské thrillery, kterou jsem se rozhodl poslechnout. Aktuálně jsou ve formě audioknihy zpracovány první dva díly.



Kniha vypráví příběh americké soudní lékařky Margaret Campbelové, která se z osobních důvodů rozhodne jet na 6 týdnů do Číny, kde má přednášet na vysoké škole. V Číně se seznámí s čerstvě povýšeným detektivem Li, se kterým následně vyšetřují podivnou vraždu.
Přemýšlím, co o knize dobrého napsat, abych jen neprskal. Možná bych za malý klad vyzvedl mírné uvedení do života v Číně, tedy pokud se mu dá nějak věřit. To bohužel neposoudím. Bohužel nic dalšího pozitivního mě na knize nenapadá a útlocitnější povahy varuji před dalším čtením, protože si nebudu brát servítky.

OK, jdeme na to. Představte si hrdinku, která chce zapomenout na své životní komplikace a tak odjede do Číny. Na nic se nepřipraví, nepřečte si ani pokyny, jak to v Číně chodí a jak by se měla chovat, aby se vyvarovala problémům. Po příjezdu dělá jeden problém za druhým a chová se tak, že se posluchač občas diví, jak svého vzdělání mohla dosáhnout. Nemyslím teď z odborného hlediska, kde naopak působí jako supermanka, ale z hlediska chování a nějakého pudu sebezáchovy. Neuvědomuje si, že je v Číně, kde to chodí jinak a je velmi překvapena, že jí mohou třeba zkrátit vízum, když se úřadům znelíbí, nebo že je jako Američanka pod drobnohledem místních úřadů. Občas se prostě chová jako nesvéprávná a naivní osoba.

O vlastní zápletce je také škoda hovořit. Z počátku vypadá trochu zajímavě, ale pak tomu autor bohužel nasadí korunu v podobě nevyhnutelné apokalypsy a konce světa. To byl okamžik, kdy jsem přemýšlel, že s knihou seknu a smažu ji. Pak ale převážila zvědavost, jak se z toho autor nakonec vykroutí, protože to je první díl z celé série, takže to musí minimálně s hlavními hrdiny dopadnout dobře. Tak jsem statečně poslouchal až do konce.

Zajímá vás, jak to celé dopadlo? Pokud se nechcete připravit o překvapení, tak přesto můžete klidně číst dále, protože mě to zajímá také. Hlavní zločin byl sice objasněn, ale jak dopadne ona avizovaná apokalypsa vyjasněno není a také není zřejmé, co se stalo s hlavními hrdiny (bez spoileru bohužel nemohu být detailnější). Jejich příběh není uzavřen a chybí mi dořešení všech skutečností, které se staly. Když jsem četl recenze na další díl, tak jsem z nich pochopil, že se autor nějakého vysvětlování zřejmě raději vzdal (nečetl/neslyšel jsem ho, nemohu to potvrdit, ale nemám po tomto zážitku sílu to zjišťovat). To rozhodnutí vlastně celkem chápu, protože dostat se z této šlamastyky se ctí, nejde.

Na druhou stranu musím ale uznat, že kniha může sloužit i jako červená knihovna, což je vlastně přidaná hodnota :-).

Audio verzi namluvila dvojice Martin Myšička a Jana Plodková. Přednes je slabší a osobně preferuji spíše vypravěčský styl. Není to ale zase úplná tragédie.

Série má 5 dílů a jak jsem již psal, do audioverze jsou převedeny první dva díly. To je přesně o 2 díly více, než by bylo vhodné. S knihou nedoporučuji ztrácet čas, na trhu je spousta zajímavějších detektivek (například Honicí psi).