ugrás a tartalomhoz

Multiuser webalkalmazás és az egyidejű adatbázis műveltetés.

s_volenszki · 2007. Ápr. 20. (P), 20.08
Sziasztok!

A címben már említett témát szeretném kivesézni, azaz többfelhasználós rendszerek adatbázis kezelése azonos időben. Foglalkoztam már többször ezzel a témával, és valójában már van egy eljárás, ami alapján figyel az adatbázis műveltető rutinom a módosításra kerülő rekord állapotára, de mégis, ki hogyan élte meg az ilyen és ehhez hasonló helyzeteket?

Csak azért hogy nyílt lapokkal játsszak elmondom én hogyan csináltam meg.
Ja! és nem ér hangosan nevetni! ;)

Egy teljesen egyszerű termék és darabszám adatbázisról van szó, amit az üzletkötők mobil internettel elérnek, így a nap bármelyik pillanatában friss raktári információval rendelkeznek.

Alapvetően az adatbázis műveletek tekintetében kizárólag a készlet csökkentés, és a készlet növelésnek van jelentősége, mert ugye:

Azonos időben módosításra meghívott rekordok közül az lesz a végleges, amelyiket majd időben később mentik.

Az első megoldásom nem volt túlságosan hosszú életű:

Adtam minden rekordnak egy állapotjelzőt, amelynek az értéke ha 0 akkor módosítható, ha 1 akkor éppen meg van nyitva módosításra. Amikor a kiválasztottam a rekordot, állapotjelző egyre vált, amikor a módosítás lezajlik (OK) vagy direkt módon meg van szakítva (Mégsem) akkor visszavált 0-ra. Ez baró volt, addig, amíg egy elegáns mozdulattal be nem zárták a folyamatot végrehajtó ablakot. Meg aztán volt olyan is, hogy éppen nyitva maradt az ablakocska néhány órára, és ugye akkor mindenki más vár az információra.

Az ablak bezárást, kezeltem egy AJAX kéréssel, ami az onUnload eseményre fut le, de voltak problémák az ignore_user_abort ellenére is. Sokszor maradt a rekord foglalt.

Ekkor kitaláltam a második megoldást:

Nem 0 és 1 állapotjelzőt használtam a rekord foglaltságának jelöléséhez, hanem időbélyeget, amit összehangoltam a végrehajtó ablakban egy timeout rutinnal. Pl.: a rekord kiolvasásakor az állapotjelzőt a (most+5perc) időbélyegre állítom, és az ablaknak adok egy 5perces timeoutot.

Így az eredeti példány (aki először olvassa azt a rekordot) számára van 5perc hogy dolgozzon a rekorddal. Ha lejár, az oldal újratölt, kiüti az időbélyeget 0-ra és kijelentkezik a kezelő felületről. Ezzel kivédtem az ottfelejtést, és az ablak bezárást is, mert legfeljebb 5 percre maradnak elérhetetlenek az adatok. Hihetetlen hogy az idő múlása micsoda előnyöket tud rejtegetni!

Ez már egy életképes eljárássá forrta ki magát. Jelzi a felhasználóknak a rekord foglaltságát, biztosít lehetőséget a rekord csak olvasható módban történő megnyitására és nem utolsó sorban felhasználó függetlenné tettem az adatok újra rendelkezésre állását.

Nagyjából ennyi lenne az én tapasztalatom a témában, és jól bírom a kritikát ha az építő!

s_volenszki
 
1

tranzakciók?

virág · 2007. Ápr. 21. (Szo), 08.29
Szia,

milyen adatbáziskezelő (gondolom MySQL). 5-ben egészen jól működnek már a tranzakciók! Ez a módszer, amit írsz számomra picit idegenül hangzik. Szerintem a tranzakciók helyes használata megoldja ezeket a gondokat, csak jól kell kezelni őket. Nekem picit fura amit írsz, de persze működhet, csak lehet, hogy ezt rá kellene bízni a DB-re, és nem az alkalmazásban hegeszteni :)
2

Igen, egyetértek!

s_volenszki · 2007. Ápr. 21. (Szo), 08.51
Valóban, amit én is érzek, hogy nem erőforrás barát az eljárás, és tökéletesen tisztában voltam azzal, hogy létezik erre gyári megoldás, hiszen egy mysql adatbázist nem tervezhetnek egy felhasználóra, de ahogyan azt írtam is, tapogatózok. Keresek a google-ben, de ha uudsz nekem javasolni tutorialt php+mysql tranzakció kezelésről szívesen fogadom!

Köszönöm a véleményt, üdv:
s_volenszki

szerk: Ja és szívesen olvasnék néhány gondolatot azzal kapcsolatban, hogy az adattáblák, rekordok olvashatósága, írhatósága hogyan változik, illetve hogyan változtatható tranzakió alatt!
3

Erre én is kíváncsi lennék, hogyan lenne lényegesen egyszer

zzrek · 2007. Ápr. 21. (Szo), 09.10
Erre én is kíváncsi lennék, hogyan lenne lényegesen egyszerűbb tranzakció kezeléssel?
Amennyit én sejtek hozzá:
A tranzakció arra való hogy bizonyos feltételek mellett változzanak meg az adatok, vagyis pl ha bizonyos adatok megváltoztak közben, akkor kivételkezeléssel érvénytelen lesz a művelet. De ez nem oldja meg azt a problémát, hogy csak x ideig dolgozhasson egy adatrészlettel egy user, ezt külön kell lekezelni, kb úgy, ahogy s_volenszki írta. Ha tranzakciót használna, minimális mértékben biztonságosabb lenne, de kb ugyanilyen elven kellene megoldani.
Vagy tévedek?
4

Heartbeat?

Wabbitseason · 2007. Ápr. 21. (Szo), 09.37
Mit szólsz egy olyan megoldáshoz, ahol szintén időbélyeggel zárolod az adatot, és a kliensoldalon mondjuk 1 percenként frissíted AJAX hívással az adott időbélyeget.

Ha a böngészőt bezárják vagy elnavigálnak az oldalról, netán megszakad a kapcsolat, akkor nem fut le az AJAXos "szívdobbanás", és az időbélyeg elavul mondjuk 3 perc alatt.

Ezzel a technikával nem szorítanád 5 percre a munkát, hiszen előfordulhat, hogy a jóembernek pár percre ott kell hagynia egy félig kitöltött űrlapot.
5

Tranzakciók helyett atomikus műveletek

vbence · 2007. Ápr. 21. (Szo), 09.41
A tranzakció nem hiszem, hogy megoldás itt. Pl: hogyan viszed át a folyamatban lévő tranzakciót egyik PHP futásból a másikba?

Ezzel szemben viszonylag egszerű módszer, ha az egyes változásokat kapod meg a klienstől. pl: Lenne egy eladtam és egy felvettem funkció. Ha elad, megnyomja a kis plusz gombot, és oda beírja, mennyit. A szerver pedig ennyivel növeli vagy csökkenti a készletet.
6

A problémát nem az egyidejű adat műveltetés jelenti, hanem.

s_volenszki · 2007. Ápr. 21. (Szo), 10.50
A problémát nem az egyidejű adat műveltetés jelenti, hanem az adatrekord aktualitása. Ha készletről beszélünk ugye, akkor a kiadáskor kliens oldalra letöltődik az aktuális készlet, és az addíg ott van amíg a csökkentés be nem következik. Ha a kliens oldalon vár a készlet, csökkentésre és közben más lecsökkenti ugyanannak a terméknek a készletét, akkor az úgymond lassabb kliens valótlan adatokkal dolgozik. Ez az alapvető oka az állapot jelölésnek.

Minta folyamat:

1. Adott termék készlet értéke ami (5db) letöltődik user_1-hez kliens oldalra.
2. Ugyanazon termék készlet értéke (5db) letöltődik user_2-höz kliens oldalra, anélkül hogy figyelmeztetnénk, valaki pillanatnyilag használja a terméket.
3. user_2 gyorsabb mint user_1 és kiadja mind az 5db-ot,
4. majd user_1 0 alá csökkenti a készletet, hiszen ő azt látta hogy a készlet 5db, és mire kiadja már nem is?

Az AJAX-os heartbeat jó megoldásnak hangzik, az időkorlát miatt eltöltődő oldal adatainak meg lehet csinálni egy un. munkamenet helyreállító rutint, ahol user a következő bejelentkezésnél visszakaphatja a formját az aktuális szerver oldali és az álltala félig bevitt kliens oldali adatokkal.

Kezd tetszeni a téma, kérlek szépen titeket, agyaljunk még!

s_volenszki
7

fordított logika

gex · 2007. Ápr. 21. (Szo), 10.57
4. majd user_1 0 alá csökkenti a készletet, hiszen ő azt látta hogy a készlet 5db, és mire kiadja már nem is?

eleve nem lenne szabad megengedni, hogy nulla alá csökkentse, hanem vissza kéne adni a hibát, hogy már nincs 5 darab raktáron (vagy esetleg lefoglalni a maradékot, és visszaírni, hogy ennyit sikerült, bocsi).

szerintem elegánsabb dolog lenne, ha ajax-szal bizonyos időnként frissítenéd a kliens oldalon lévő darabszámot, mert a korlátozás teljesen felesleges lehet pl olyan esetekben ahol valaki csak meg akarja nézni a készletet és nem fog egyetlen darabot sem rendelni, mégis 10 percig blokkolja a forgalmat.
8

Tudtam!

s_volenszki · 2007. Ápr. 21. (Szo), 11.04
Köszönöm...

Már amikor leírtam akkor tudtam, hogy a következő hozzászóló :) azt fogaj mondani, miért engedem 0 alá csökkeni a készletet.

Akkor most lefordítanám magyarra:

Ha az üzletkötő véres verejtékkel beküzdi magát bizalmi pozícióba és az értékesítés már csak a rendelkezésre álló készlet függvényében lesz sikeres, akkor nem megengedhető hogy amíg Ő kiajánlja a készletet, más kiadja alóla!

Még általánosabban: Ígéret szép szó...

s_volenszki

szerk:
Mellesleg a gondolattal egyetértek a felesleges foglaltsággal kapcsolatban, de mivel webalkalmazásról beszélünk, itt sokkal könnyebben irányítható a felhasználó, és a készélet elemzés read only módban rendelkezésre állhat!

szerk2:
Sajnos nem írtam le teljesen egyértelműen, de az oldal időkorláta nem kizárólag a betöltődéstől számol. Minden az oldalon bekövetkező egér, billenytű esemény lenullázza. Tehát a tényleges lejárat kiozárólag akkor következik be ha nem dolgoznak a form-mal!
9

Ki lockol már megint?

Wabbitseason · 2007. Ápr. 21. (Szo), 11.15
Ha sokan piszkálják az adatokat, érdemes lehet azt is letárolni a zárolásnál, hogy melyik user kérte ki az adott rekordot, így szükség esetén föl lehet hívni az illetőt, vagy ha táposabb a szoftver, akár azonnal megjelenő üzenetet is lehet neki küldeni.
10

Ez így is van.

s_volenszki · 2007. Ápr. 21. (Szo), 11.19
A jelenleg működő rutin, felhasználó névvel, sessid-vel és ip címmel együtt hozza létre az idő bélyeget.

s_volenszki
19

Simán mehet nulla alá.

Darkfish · 2007. Ápr. 22. (V), 10.20
Az én megoldásomnál (előfeltétel: a rendelést egyben kell leadni.) úgy működik, hogy egy táblába kiírom a változást, és hogy ki csinálta. pl:
ID ARU MENY
1 1 +3
2 1 -1
3 1 -2
4 1 -1

Namost ha az én ID-m 3, akkor összeadom a mozgást az én ID-mig (<=), ha nullánál nagyobb szám jön ki, akkor minden renben. Ha nem, akkor törlöm és és értesítem a megfelelő ID-jű felhasználót, hogy a lezárásra már nem tudtam mindent lefoglalni, nézze át a csökkentett listát és döntse el, hogy kell-e. Az ID-k helyett gondolom megy időbélyeggel is.

Az előnye az, hogy miután az életben sem az a jellemző, hogy az utolsó darabokért a neten harcolnak, ez relatív kevés erőforrással megoldható. Persze itt is használható a ésszerű minimum készletes figyelmeztetés.
11

Lock

vbence · 2007. Ápr. 21. (Szo), 11.53
Ez így inkább ügymeneti kérdés, mintsem technikai. Amit javaslok: ne legyen elég megnézni a készletet a lock-hoz. Legyen egy gomb: "én most ebből eladok, úgy hogy más ne tegye" és ekkor lockolódjon a dolog. Ezalatt más nem tud rányomni. Tehát a lockolás egy konkrét esemény legyen, aminek az üzeltkötő tudatában van. Miután kilép az ügyféltől, akkor pedig feloldja. Lehet mindenféle automatizmusokkal meg timeoute-al olajozni a dolgokat, a lényeg, hogy aki lockol tudatában legyen, hogy ő most lock-ol, és ne csupán a megnyitás / megnézés legyen.

Lehet fejleszteni, hogy nem az egész készletet lockolja. Ha tudjuk, hogy "senki sem vett még 3nél többet ebből", akkor mondjuk 6 elem befoglalása egy ésszerű korlát lehet, és a többiek addig a maradék készlet erejéig dolgozhatnak.
12

igen, a szándék kell hogy irányítson

s_volenszki · 2007. Ápr. 21. (Szo), 12.03
Tökéletesen egyet értek a gondolatoddal, sőt nagyon jó ötlet az egyszerre kiadható mennyiség korlátozása is!

Találtam valamit! Akit érdekel és jó angolból, nagyon sok tanulságot fog levonni belőle! Kizárólag elméleti az anyag (már ehhez a topichoz képest)!

Handling data concurrency violation

s_volenszki
13

kis kiegészítés

csla · 2007. Ápr. 21. (Szo), 18.44
Annyit érdemes még hozzátenni, hogy miután kiadta a saját lockját, olvassa is vissza, hogy tényleg a saját lockja került-e bejegyzésre, mert előfordulhat, hogy nagyjából egyszerre küldenek ketten lockot, és akkor azt még nem tudja a kliens, hogy vajon az ő lockja volt-e gyorsabb. Mert lehet, hogy amikor kiolvassa, hogy nincs lock, és rá akarja tenni a sajátját, akkor a kettő közötti "pillanatban" egy másik user lockja "beelőz"...

Szerk.: én konkrétan ezt úgy csinálom, hogy addig fut egy while ciklus a "fontos művelet" elkezdése előtt, amíg nem tudja visszaolvasni a saját lockját, vagy el nem telik az előzőleg kiadott lock lejárati ideje. Ha ez utóbbi van, vagy nincs is lock kiadva, akkor megpróbálja a saját lockját elhelyezni, ami után újból indul ez a while ciklus a korábbi feltétellel.
14

Nagyon sok LOCK

vbence · 2007. Ápr. 21. (Szo), 19.48
Már több féle lockról beszéltünk. Behozok mégegyet: a MySQL LOCK queryjét. Így egy oszthatatlan egységet képez az a néhány SQL lekérdezés, ami a feladathoz kell: kiolvassuk hogy szabad-e, létrehozzuk a "lock" elemet. Ha zárolod a táblákat, akkor a két művelet közé semmiképen nem furakodhat be egy azonos időben futó másik kérés.

Bocs, ha nehezen érthető, egy kis példa:

<?
  function zarol($termek_id) {
    $db->query("LOCK TABLES zar WRITE");
    $db->query("SELECT * FROM zar WHERE termek='$termek_id'");
    if (!$db->num_rows ()) {

      // mar mas zarolta a termeket
      $siker = false;

    } else {

      // nincs zarolva a termek, befoglaljuk
      $db->query("INSERT INTO zar (termek_id) VALUES('$termek_id')");
      $siker = true;

    }
    $db->query("UNLOCK TABLES");
    return $siker;
  }
?>
16

Re: Nagyon sok LOCK

csla · 2007. Ápr. 21. (Szo), 22.06
Végülis igen. :)
17

felesleges LOCK

Hodicska Gergely · 2007. Ápr. 22. (V), 10.01
Erre a célra tök felesleges a LOCK TABLE, ott a SELECT FOR UPDATE.


Üdv,
Felhő
15

működően életszerűtlen - gondolatok a kereskedelemről

sotetbarna · 2007. Ápr. 21. (Szo), 21.54
valahogy ez a folyamat olyan kifordított, nem?

üzletkötők egymás elől "lopják el" az árut, ahelyett, hogy valaki összefogná őket (mondjuk kereskedelmi vezető?)

és a kiszállítás ideje? mi van, ha valakinek jövő péntekre kell az áru, valakinek jövő hétfőre, és közben jövő szerdán megérkezik egy beszerzés? mondjuk a jövő pénteki szállítási igény fut be előbb, és az kiüti a tulajdonképpen teljesíthető hétfői igényt?

egy jól működő kereskedelem "tudja", hogy egy termékből - ha nem is két hónap múlva, de - a jövő héten mennyi fog elmenni. kalkulál minimumkészlettel, beszerzési és szállítási határidőkkel.

szóval csak azt akarom mondani, az igazán sikeres cégek nem így csinálják. a rendszer megreformálása meg nem a programozó dolga...
20

Adatzárolási startégia.

s_volenszki · 2007. Ápr. 22. (V), 15.55
Sziasztok!

Átolvastam azokat a dokumentumokat amiket találtam és amiket ajánlottatok (külön köszönöm Felhőnek!), és igazából tökéletesen helyére került ez a kérdéskör.

Mint minden rendszer tervezésnél, itt is az elsődleges feladat meghatározni a rendszer célját, majd ezek után kell felépíteni a cél eléréséhez legmegfelelőbb működést. Teljesen egyetértek sotetbarna hozzászólásával, és mivel most már tudom, hogy milyen logikai eljárások vannak adatkonkurencia kezelésre, azt is tudom, hogy ebben a helyzetben nem a pesszimista modelt kell választanom.

Köszönöm a gondolatokat, üdv:
s_volenszki
18

concurrency control

Hodicska Gergely · 2007. Ápr. 22. (V), 10.13
Keress rá googleban a következőkre: concurrency control, pessimistic locking, optimistic locking.
Például: http://www.agiledata.org/essays/concurrencyControl.html


Üdv,
Felhő