Konkurence mezi procesama – zamykání pomocí DB

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
reflex
Člen | 28
+
0
-

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
+
0
-

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)

David Matějka
Moderator | 6445
+
0
-

Napadá někoho proč ten druhý proces čeká

mozna to zpusobujou session

reflex
Člen | 28
+
0
-

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
+
0
-

@reflex jj, zkus si to spustit treba ve dvou prohlizecich, pripadne z cli, kde se nebudou mlatit session :)

reflex
Člen | 28
+
0
-

Diky moc matej21 doopravdy session, nevim proc by me to nenapadlo

RA
Člen | 6
+
0
-

Zdravim,

ted jsem resil podobny problem. Muze mi nekdo vysvetlit proc prip. jak do takovejch procesu zasahuje session?

David Matějka
Moderator | 6445
+
0
-

@RA jelikoz jeden proces otevre session, tak druhy proces musi cekat, dokud prvni proces session neuzavre, aby nedoslo k prepsani dat druhym procesem.

RA
Člen | 6
+
0
-

@matej21 Nerikam, ze to tak neni, ale WTF tak to otevru z jineho browseru a data jsou prepsana. Jako proti cemu je to pak ochrana? Mi to prijde, ze proti programatorum jedine :)

David Matějka
Moderator | 6445
+
0
-

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):

  1. na server prijde request 1
  2. r1 otevre session a precte kosik (prazdny)
  3. na server prijde request 2
  4. r2 otevre session a precte kosik (prazdny)
  5. r1 prida polozku 1 do kosiku a zapise do session (v kosiku je polozka 1)
  6. 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:

  1. na server prijde request 1
  2. r1 otevre session a precte kosik (prazdny)
  3. na server prijde request 2
  4. r2 chce otevrit session, ale to je zamknute, proto ceka…
  5. r1 prida polozku 1 do kosiku a zapise do session (v kosiku je polozka 1)
  6. r2 konecne otevre session a zjisti, ze je tam polozka 1
  7. 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)

RA
Člen | 6
+
-3
-

@matej21 Dik za info. Mozna by bylo fajn toto chovani zminit v dokumentaci. Nejsem v PHP moc zbehly, nevim kolik lidi s takovym chovanim pocita, ale je to podle mne celkem zasadna informace.

Filip Procházka
Moderator | 4668
+
+1
-

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ě :)