Session rekord lockolás MySQL-ben (innoDB)
Sziasztok!
Régi motoros vagyok az SQL területén, most mégis a segítségeteket kérném $subject témában.
Bizonyos kiegészítő session információkat a session rekordba szerializálva tárolok. Hogy valaki párhuzamos hívásokkal ne üthesse agyon ezeket, a kérés kiszolgálásának elején SHARED LOCK-ot teszek a rekordra. Ha viszont egy admin indít egy termék betöltést, az akár 30 percig is futhat. Ha közben egy másik böngésző ablakban is kattint, akkor mi történik? Frissítenem kéne az "utolsó használat ideje" mezőt a rekordban, amihez exkluzív lock kéne. Ekkor vár 30 percig? Vagy dead lock lesz, amikor a másik is a végén vissza akar írni a rekordba?
A dolog azért érdekes csak, mert a session kezelés háza táján a logban rendszeresen felbukkannak dead lock hibák, és ennek szeretnék a végére járni.
Előre is köszönöm a válaszokat!
Üdv:
Dávid
■ Régi motoros vagyok az SQL területén, most mégis a segítségeteket kérném $subject témában.
Bizonyos kiegészítő session információkat a session rekordba szerializálva tárolok. Hogy valaki párhuzamos hívásokkal ne üthesse agyon ezeket, a kérés kiszolgálásának elején SHARED LOCK-ot teszek a rekordra. Ha viszont egy admin indít egy termék betöltést, az akár 30 percig is futhat. Ha közben egy másik böngésző ablakban is kattint, akkor mi történik? Frissítenem kéne az "utolsó használat ideje" mezőt a rekordban, amihez exkluzív lock kéne. Ekkor vár 30 percig? Vagy dead lock lesz, amikor a másik is a végén vissza akar írni a rekordba?
A dolog azért érdekes csak, mert a session kezelés háza táján a logban rendszeresen felbukkannak dead lock hibák, és ennek szeretnék a végére járni.
Előre is köszönöm a válaszokat!
Üdv:
Dávid
Ha jól értelek, akkor a
Lockolsz egy rekordot, amivel lehetővé teszed, hogy másik tranzakció olvassa a rekordot, de nem írhatja.
Kattintás másik ablakban:
Egy másik tranzakcióban újra csinálsz egy shared lock-ot, és ezt a tranzakciót várhatóan hamarabb zárod, mint az elsőt, így a második tranzakciód várakozik az első lock feloldására, hogy végre tudja hajtani az írást. Eltelik az innodb lock wait timeout-ban meghatározott idő (50 sec szokik lenni), és a második tranzakció elhasal, mivel az első tranzakció még nem zárult le.
Ebből nem lesz a szó szoros értelemben vett deadlock szvsz. Azt érdemes figyelembe venned, hogy az innodb_lock_wait_timeout határozza meg, hogy meddig vár egy tranzakció egy lock feloldására.
Valahogy úgy...
Köszi a választ! Szerintem is valami ilyesmi történik, ami 2 kérdést vet fel:
1. Mitől lesz mégis dead lock a logban. :) (Úgy néz ki, hogy ezek szerint nem ettől, úgyhogy még gondolkozom.)
2. A session-ös példában fölvetett helyzetre milyen jó megoldás létezik?
Szerintem szebb lenne, ha exklizív lock-al fognám meg a session rekordot, de így sem, úgy sem tud addig kattintani, amíg a másik kérés le nem fut. Tud valaki erre jó megoldást?
Üdv:
Dávid
Exclusive lock esetén azt
Én csak akkor lockolnám a session rekordját, amikor feltétlenül szükséges: a visszaíráskor. A visszaírást pedig kezdeném azzal, hogy felolvasom újra a session rekordot egy másik változóba, és csak a változásokat írnám vissza. Ehhez lehet át kell alakítanod a session-kezelésedet kicsit.
Igen, az exkluzív lock ezt
Az általad javasolt megoldás nekem is eszembe jutott már, azért vetettem el mégis, mert jelenleg úgy működik a session kezelés, hogy az engedélyezett inaktivitási időnél régebbi inaktív session-ök kapnak egy inaktív flag-et, majd néhány perce múlva törlődnek. Ezért kell most végig fognom azt, amelyik dolgozik. Van jobb ötleted a session-ök kitakarítására? Hagyjak esetleg nekik több időd, mondjuk a lejárat után 1 nappal töröljem őket, feltéve, hogy nincs olyan hosszú batch processz?
Előre is köszi a tippeket!
Üdv:
Dávid
Batch
A batch folyamat indításakor zárod a sessiont, kiírod a felhasználónak, hogy a folyamat elindult, esetleg egy percenként frissülő oldalon kiírhatod neki, hogy mit csinál a folyamat éppen, csak meg kell oldani, hogy a folyamat valahova beírja ezt, ahonnan fel tudod olvasni a felhasználónak.
A session-t nem érdemes olyan munkafolyamatokba belevinni, amelyeknek potenciálisan később lesz vége, mint ahogy lejárna a session.
Viszont másik megoldás lehet az is, hogy amikor a batch folyamat elindul, akkor raksz a session-re egy flaget, ami kitolja a lejárati idejét, és jelzés a garbage collectornak, hogy ne takarítsa ki a sessiont, mert fut egy folyamat vele kapcsolatban. Talán ez egyszerűbb megoldás, mint az előző, és így nincs szükség arra, hogy fél órára lockolj egy rekordot, amit amúgy írnál-olvasnál.
Köszönöm a választ!
Egy elméleti kérdésem lenne még:
A vannak bizonyos adatok, melyet a session-be szerializálva tárolok. Ugyan az említett hosszú batch folyamat nem módosítja ezek egyikét sem, de elvileg akár módosíthatná is. Ebben az esetben nem járható az általad javasolt út, mert ha a folyamat végén (módosítás előtt) újra felolvasom a session adatokat, akkor inkonzisztens állapotba kerülhet a futó szál. Erre van valami ötleted?
Köszi!
Írd át a session handlered
Ezzel megoldod, hogy csak a változások kerülnek a DB-be.
Ezt tovább lehet bonyolítani/finomítani, hogy minden session adathoz még rendelsz egy timestampet is a session handleren belül, és csak azokat az adatokat frissíted, amelyeknek a timestampje régebbi, mint a változásod.
Bocs, azt hiszem
Mivel ez a probléma - szerintem - teljes általánosságban nem orvosolható máshogy, csak az erőforrás kizárólagos használatának biztosításával, ezért vetettem el az elején a 2 mentes session kezelést.
Arra lennék kíváncsi, hogy Neked van-e valamilyen ötleted ennek a - valószínűleg pusztán elméleti - problémának a megoldására?
Köszi! Üdv:
Dávid
Meglehetősen összetetté válik
Ilyen esetben a shared lock sem megfelelő megoldás, mert a második session a lock feloldása után (lock wait timeout nélkül) a saját adataival felülírná az adatokat, és nem merge-lné.
Általános megoldásra nekem sincs javaslatom.
Köszönöm a rám szánt időt!
További szép napot!
Dávid