Konkurence mezi procesama – zamykání pomocí DB
- reflex
- Člen | 28
Dobrý den vespolek,
po delší době na svůj miniprojekt používám Nette a chtěl bych se zeptat jestli někoho napadá jak řešit konkurenci, respektive má skript, který nechci, aby se spouštěl ve více procesech najednou.
Momentálně to řeším tabulkou v DB s unikátním kličem a zamykáním.
Tabulka má unikátní sloupec lock_key, a timestamp expire.
public function createLock() {
try {
$this->database->beginTransaction();
$this->database->query('DELETE FROM `lock` WHERE `expire` <= NOW()');
$this->database->query('INSERT INTO `lock`', array(
'lock_key' => self::LOCK_KEY,
'expire' => new \Nette\Database\SqlLiteral('DATE_ADD(NOW(), INTERVAL 5 MINUTE)')
));
$this->database->commit();
} catch(\Exception $e) {
return 0;
}
return 1;
}
Za vytvářením zámku mám sleep.
Pustím po sobě ve 2 tabech a funguje to tak.
1 proces zamkne → udělá co potřebuje → odemkne
2 proces ceka na prvni proces → zamkne → udela co potrebuje → odemkne.
Napadá někoho proč ten druhý proces čeká, respektive jak se lépe vypořádat s konkurencí?
Jo a nekoukejte, že odchytávám vše tedy pohřebiště bugů.
Editoval reflex (8. 7. 2014 13:18)
- Caine
- Člen | 216
Nebylo by lepsi zamykani pres soubory flock()
, da se pak udelat
i neblokujici lock, tedy kdyz nemuzu ziskat lock, necekam na odemceni, ale
proste bezim dal.. Pouzivame to napr u cronu, kde neni jasny, jak dlouho se
bude vykonavat a nahodou by mohlo dojit ke kolizi, kdy se spusti akce, aniz by
se predchozi dokoncila..
Pouzivame neco takovyho.
Editoval Caine (8. 7. 2014 13:51)
- reflex
- Člen | 28
Caine napsal(a):
Nebylo by lepsi zamykani pres soubory
flock()
, da se pak udelat i neblokujici lock, tedy kdyz nemuzu ziskat lock, necekam na odemceni, ale proste bezim dal.. Pouzivame to napr u cronu, kde neni jasny, jak dlouho se bude vykonavat a nahodou by mohlo dojit ke kolizi, kdy se spusti akce, aniz by se predchozi dokoncila..Pouzivame neco takovyho.
Na flock jsem koukal a po tomhle nezdaru použiju ten, jen mě fakt zajímá proč to nejde :]
Add Matej21: Myslíš php session? To by mě vůbec nenapadlo :]
- David Matějka
- Moderator | 6445
@reflex jj, zkus si to spustit treba ve dvou prohlizecich, pripadne z cli, kde se nebudou mlatit session :)
- David Matějka
- Moderator | 6445
@RA jelikoz jeden proces otevre session, tak druhy proces musi cekat, dokud prvni proces session neuzavre, aby nedoslo k prepsani dat druhym procesem.
- David Matějka
- Moderator | 6445
WTF tak to otevru z jineho browseru a data jsou prepsana
nechapu, co tim myslis.
PHP proste zabranuje, aby jeden session zaznam nemohl byt 2× otevren pro
zapis ve stejnou chvili. Dam ti priklad, co by se stalo, kdyby tomu tak nebylo..
Mam nakupni kosik, ktery je ulozeny v session. Uzivatel si prida 2 ruzny
polozky do kosiku (treba z vypisu nejakyho zbozi). Takze se odeslou 2 requesty
(a uzivatel klika rychleji, nez se staci zpracovat prvni request)
a stalo by se tohle (tedy kdyby se to nezamknulo):
- na server prijde request 1
- r1 otevre session a precte kosik (prazdny)
- na server prijde request 2
- r2 otevre session a precte kosik (prazdny)
- r1 prida polozku 1 do kosiku a zapise do session (v kosiku je polozka 1)
- r2 prida polozku 2 do kosiku a zapise do session, v kosku tedy bude polozka 2, protoze kdyz otevrel session, nic tam nebylo
a tohle se stane, kdyz se session lockne:
- na server prijde request 1
- r1 otevre session a precte kosik (prazdny)
- na server prijde request 2
- r2 chce otevrit session, ale to je zamknute, proto ceka…
- r1 prida polozku 1 do kosiku a zapise do session (v kosiku je polozka 1)
- r2 konecne otevre session a zjisti, ze je tam polozka 1
- r2 prida polozku 2 do kosiku a zapise do session. V kosiku tedy budou obe polozky
Pokud mas nejaky narocnejsi request a se session pak nepracujes a nechces tak, aby blokovalo dalsi request, muzes ji uzavrit
Editoval matej21 (12. 11. 2014 0:05)
- Filip Procházka
- Moderator | 4668
Když použiješ RabbitMQ a workery, tak ti může neustále běžet jeden script, který bude čekat na to až mu řekneš že má něco udělat a díky tomu že práci přiděluje RabbitMQ, tak se ti nestane, že by jeden úkol vykonávaly dva workery zároveň. A nebo prostě pustíš jenom jeden, pokud nechceš aby nikdy vykonávali byť třeba dva různé úkoly v jeden moment.
Tenhle přístup používáme na generování reportů, které trvá třeba i 6 minut a díky tomu že tam běží jenom jeden script, tak není možné aby nám někdo shodil web tím, že v administraci tu stránku začně refreshovat jak pominutej, maximálně dá do fronty hodně úkolů, ale to ničemu nevadí, protože se vykonají postupně :)