Deadlocking - mis see on ja kuidas sellest üle saab
30.12.2007 | Gunnar
Andmebaasis tekkivad deadlock‘id on tihti teemaks millele süsteemide arendamisel olulist rõhku ei panda. Tegemist on aga pimesi oma õue maetud maamiiniga, millele varem või hiljem keegi peale astub. Süsteemi aluspõhja muutused, mille algul tegemata jäetud kodutöö võib kaasa tuua, võib osutuda päris karmiks tegemiseks.
Mis on deadlock ja kuidas see tekib?
Deadlocking on situatsioon, kus kaks või enam protsessi on endale lukustanud mõne objekti ning püüavad panna lukku ka seda objekti, mis on juba mõne teise protsessi käes. Tekib olukord, kus kaks protsessi ootavad teineteise taga objektide vabanemist, et saaks oma tegemistega edasi liikuda.
Deadlock‘i tekkimise korral kontrollib näiteks MS SQL Server, millise protsessi transaktsioon on rollback‘i tegemise mõttes kõige vähem kulukas ning sellele protsessile tehaksegi rollback. Vastava protsessi algatanud kasutajale näidatakse peale rollback‘i vastavat veateadet.
Deadlock‘id tulevad tihti kunagi hiljem
Minu kogemus erinevate ülevõetud süsteemidega näitab seda, et kõige altimad on deadlock‘idele süsteemid, mille loomisel pole deadlock‘ide tekkimise võimalusi üldse kaalutud. Paljude arendajate suhtumine on selline: kui süsteem töötab minu masinas ja käputäie andmetega, siis järelikult töötab ta valutult ka serveris. Serveri peal on küll kordi rohkem kasutajaid, kuid serveril on ka kordi rohkem ressurse. Seega - kõik on ju okay. Tegelikult ei ole. Kohe kuidagi ei ole.
Üks halvimaid vigu, mida ma olen kohanud, on optimeerimata päringud. Jah, tõesti, need toimivad väga kiiresti, kui andmeid on vähe. Kuid andmeid tuleb pidevalt juurde ja juurde. Need protsessid, mis enne võtsid aega tühise murdosa sekundist, võivad nüüd aega võtta kauem. Protsessid võtavad nüüd aega kauem ja tõenäosus, et need ajateljel kattuvad, on palju suurem. Ja nii need hädad hakkavad.
Kui algul saame kenasti hakkama sel teel, et optimeerime ära aeglased päringud ning hea õnne korral saame mõnede protseduuride alt korjata kokku liigsed tegevused ning panna need eraldi protseduurina öösel jooksma, siis ühel hetkel ei aita enam seegi. Andmeid tuleb juurde ja juurde ning kõik päringud ja muutused võtavad samade serveri ressurside juures järjest enam aega.
Kuidas deadlock‘ide vastu võidelda?
Head rakendused, mis arvestavad deadlock‘ide tekkega, ei näita probleemi algul välja. Kui deadlock tekib, siis püüab rakendus vastava vea kinni, ootab hetke ning püüab protseduuri korrata. Suure tõenäosusega võib see nüüd õnnestuda. Lõputuid proovimiste tsükleid ei tohi siiski kirjutada, sest viimasel piiril töötava serveri suretakse see kiiresti ära. Peale mingit arvu proovimisi tuleb kasutajale siiski veateade anda. See on üks efektiivsemaid meetode deadlock‘ide vastu võitlemisel.
Et paremini oleks aru saada, kuidas see nõks toimib, siis püüan leida hea selgituse. Eespool ütlesin, et rakendus “ootab hetke” ja siis proovib uuesti. Kõige efektiivsem on selle hetke pikkus võtta juhuslike arvude generaatori käest. Alumine piir näiteks 300ms ja ülemine piir 700ms. Loomulikult pole need numbrid siin konkreetne soovitus, vaid lihtsalt näide. Optimaalseim ajaline lõik sõltub suuresti tehnilise keskkonna ressursidest ja käivitatava protseduuri keerukusest ning sellest, mida ja kuidas seal protseduuris tehakse. Seega ei aita meid alati ka see, kui rakendus kasutab üldist mehanismi tolle hetke ajalise kestvuse leidmiseks.
Milliseid ennetavaid tegevusi saaks teha?
Pole just kõige mõttekam käituda nii, et valmistumegi kohe deadlock‘ide tekkimiseks ja võtame neid kui peatselt saabuvat paratamatust. On terve rivi asju, mida saame teha selleks, et nende tekkimise tõenäosust vähendada. Järgnevalt mõned soovitused.
- Veendu, et andmebaas oleks on korrektselt normaliseeritud. Normaliseerimata andmebaasid on tihtipeale altid kõiksugustele jõudluse probleemidele. Kõige haigemad saavutised, mida ma näinud olen, teevad tabelite vahel join‘e kasutades väljade võrdlemisel stringifunktsioone ning tabelite ridade arvud on olnud seejuures suhteliselt suured.
- Ära anna transaktsiooni keskel kontrolli kasutajale. Veebirakendustes seda probleemi enamasti ei teki, kuid töölauarakenduste korral on selliste probleemide esinemine alati võimalik. Protsess, mida kasutaja läbi viib, jagatakse kenasti sammudeks. Esimese sammu järel algab transaktsioon ja see lõpetatakse peale viimast kasutaja tehtud liigutust. Vahepeal aga küsitakse kasutaja käest andmeid. Tekib väga halb situatsioon, kus kasutajatel on protsessid pooleli ning nad on läinud näiteks lõunale. Objektid on transaktsioonide poolt kenasti lukus ning need, kes tahavad programmi kasutada, on püsti hädas. Et sellist asja ei juhtuks, siis tasub kasutaja käest küsida kõik andmed ära alguses ning seejärel viia transaktsioon järjest läbi.
- Väldi kursorite kasutamist. Kursorid, mida kasutatakse andmebaasi protseduurides on väga ressursinõudlikud. Neid on mõttekas kasutada ainult siis, kui enam midagi muud üle ei jää. MS SQL Serveri peal on mõttekas kasutada staatilisi kursoreid kuivõrd need on kõige säästlikumad. Keyset ja dünaamilised kursorid nõuavad rohkem, dünaamilised seejuures kõige rohkem, sest need peegeldavad andmetesse reaalajas tehtud muudatusi.
- Hoia transaktsioonid nii lühikesed kui võimalik. Mida lühem on transaktsioon, seda lühemat aega see kestab ja seda lühemat aega hoitakse objekte lukus. Oma olemuselt on transaktsioon kogum andmebaasi päringuid, mis moodustavad phe tööühiku ja mida tuleb käsitleda ühtse tervikuna - kui üks päring ebaõnnestub, tuleb tühistada kõik. Mida enam sellest kontseptsioonist eemalduda, seda suuremad ja laialivalguvamad tulevad transaktsioonid ning seda mahukamaks nad muutuvad.
- Muuda lukustuste ajad võimalikult lühikeseks. Kõik operatsiooni, mis lukustavad andmebaasi objekte, on mõttekas luua sellised, et objektid lukustatakse võimalikult hilja ja vabastatakse võimalikult vara. Sel juhul väheneb deadlock‘ide tekkimise tõenäosus tugevalt.
Täiendavad materjalid
- Reducing SQL Server Deadlocks
Hea artikkel Brad McGeHee sulest. Hea ülevaade deadlock’idest ja nende vastu võitlemisest. Artikkel annab häid soovitusi MS SQL Server’i valguses, kuid sisaldab ka palju üldiseid soovitusi. - SQL Server 2005 Books Online
Deadlocking
Detecting and Ending Deadlocks
Minimizing Deadlocks - How to Cope with Deadlocks
Mõned soovitused deadlock’idega tegelemiseks MySQL ja InnoDB jaoks. - Bart Duncan’s SQL Weblog
Deadlock Troubleshooting, Part 1
Deadlock Troubleshooting, Part 2
Deadlock Troubleshooting, Part 3
Ja nagu alati mu tehniliste kirjutistega - täiendage mind, kui midagi siit puudu jäi või kui teate mõnda head nõksu, mida teistelegi soovitada.

30.12.2007 kell 22:28
Ehk oleks baaside kõrval kasulik ka concurrencyst laiemalt ja threadide deadlockidest rääkida?
Ootan huviga järgmiseid kirjatükke.
30.12.2007 kell 23:10
Tänan hea nõuande eest. Kindlasti on tegemist teemaga, millest palju ei millegi pärast ei räägita.
31.12.2007 kell 01:17
Tihtipeale on siiski odavam neid aegajalt tulevaid deadlokke lihtsalt killida…
Arendamine/lappimine on kuradi kallis.
31.12.2007 kell 02:06
Oleneb muidugi kui palju seda killimist on. Seni karmim juhtum, mis ma näinud olen, on süsteem, kus on aastas kaks-kolm korda kuu aega paras hunnik rahvast peal ja seal vist admin saab aastas kolm kuud kokku deadlocke killida
03.01.2008 kell 12:26
Siin räägitakse natuke juttu Web servicitest, threadidest ja deadlockist.
http://blogs.msdn.com/tess/archive/2007/12/18/case-study-asp-net-deadlock-calling-webservices.aspx