Persistentní připojení
Školení, která pořádám
Persistentní připojení je způsob, jak řešit relativní pomalost připojování k databázi, ke kterému typicky dochází při otevření každé stránky každým návštěvníkem webu. Funguje to tak, že PHP si pro každý proces udržuje úložiště otevřených připojení a pokud se někdo chce k databázovému serveru připojit se stejnými přihlašovacími údaji, tak použije existující otevřené připojení a nezdržuje vytvářením nového. Potud to vypadá geniálně, menší problém ale vzniká při konfiguraci tohoto mechanismu.
Pro definování maximálního počtu připojení na jeden proces se v PHP používá direktiva mysql.max_persistent s výchozí hodnotou nekonečno. Počet procesů se např. v Apache nastavuje direktivou MaxClients s výchozí hodnotou 256. Počet povolených připojení k MySQL se nastavuje direktivou max_connections s výchozí hodnotou 100. Je vidět, že při výchozím nastavení to zkrátka nemůže fungovat, protože k MySQL se může zkoušet připojit najednou 256 klientů jenom z PHP (a další třeba z příkazové řádky), což je více, než povolených 100. To ale platí i pro neperzistentní připojení, takže direktivu max_connections je lepší tak jako tak zvýšit – to naštěstí ničemu nevadí.
Pokud se k databázovému serveru připojujeme vždy pod stejnými přihlašovacími údaji, tak problémy s perzistentními připojeními naštěstí v podstatě končí. Pokud se ale přihlašujeme s různými údaji, tak je nutné max_connections nastavit tak, aby byla větší než počet různých přihlašovacích údajů * MaxClients. A pokud je počet různých přihlašovacích údajů vysoký (už např. 10), tak je nutné max_connections nastavit na hodnotu, která už může výkon serveru výrazně zhoršovat.
Zdánlivě by tento problém mohlo řešit nastavení PHP direktivy mysql.max_persistent. Tato direktiva je ale bohužel v podstatě nepoužitelná, protože při dosažení maximálního počtu připojení PHP suše oznámí chybu „Too many open persistent links“, místo aby z úložiště odstranilo např. nejstarší konexi.
Pokud se tedy k databázovému serveru připojují všechny skripty na celém serveru vždy pod stejnými přihlašovacími údaji, tak persistentní konexe ničemu nevadí. Dlužno podotknout, že skutečné zrychlení poskytují pouze v případě, kdy databáze běží na jiném stroji než webový server. V ostatních případech je lepší se perzistentním připojením raději vyhnout nebo je úplně zakázat direktivou mysql.allow_persistent.
S perzistentními připojeními je spojen také problém se zamykáním tabulek. Pokud zamknete tabulku a zapomenete ji odemknout (nebo před odemknutím dojde k fatální chybě nebo přerušení skriptu uživatelem), odemkne se automaticky při ukončení připojení k databázi. Za normálních okolností to je zároveň se skončením skriptu, při perzistentních připojeních to ale není nikdy. Proto je v takových případech potřeba dávat veliký pozor:
<?php
ignore_user_abort(true); // alespoň tak - zabrání přerušení skriptu uživatelem
register_shutdown_function(create_function('', 'mysql_query("UNLOCK TABLES");')); // spolehlivější - odemknutí při jakémkoliv ukončení skriptu
mysql_query("LOCK TABLES uzivatele WRITE");
?>
V některých případech může být nebezpečné také to, že připojení zdědí i nastavení MySQL proměnných a vytvořené dočasné tabulky.
Přijďte si o tomto tématu popovídat na školení Výkonnost webových aplikací.
Diskuse
tak zamykani tabulek jsem jeste v praxi pouzivat nevidel....
docela dobry clanek :) gj
"People who aren't thoroughly familiar with the way web servers work and distribute the load may mistake persistent connects for what they're not. In particular, they do not give you an ability to open 'user sessions' on the same link, they do not give you an ability to build up a transaction efficiently, and they don't do a whole lot of other things. In fact, to be extremely clear about the subject, persistent connections don't give you any functionality that wasn't possible with their non-persistent brothers."
V tom clanku chybi spousta veci, doporucil bych jako primarni cteni FM: http://www.php.net/manual/en/features.persistent-connections.php
Souhlasit se da v podstate s dvema vecma:
"Pokud se ale přihlašujeme s různými údaji, tak je nutné max_connections nastavit tak, aby byla větší než počet různých přihlašovacích údajů * MaxClients." (Ovsem chybi uvedeno, za kterych podminek toto plati)
a
"V ostatních případech je lepší se perzistentním připojením raději vyhnout nebo je úplně zakázat direktivou mysql.allow_persistent."
A takova recnicka otazka, na kterou si kazdy muze odpovedet sam: proc treba u takovy vylepseny MySQL extenze (mysqli) jsem nenasel podporu pro pconnecty? Jsem slepej nebo tam proste neni?
Takhle je diskusní příspěvek skoro k ničemu. Musíš napsat, co v článku chybí nebo co je v něm špatně.
Odkazem na odpovídající stránku PHP dokumentace článek začíná.
sorry, podivej se na cas, kdy jsem to psal a ver, ze jsem nad tim stravil skoro hodinu (nj, neumim psat moc rychle ;P), nakonec jsem to zeditoval do podoby, ktera tu je.
treba jsem se nedocetl jednu vec, ze p-spojeni je zavisly nejenom na stejnym l/p, ale i na stejnym PID obsluhujiciho procesu (kvuli tomu, jak takovy webovy servery fungujou) -- tim padem, ze v klasickejch webovejch app, tak jak je zname, jsou p-spojeni v podstate k nicemu, protoze kazdej pozadavek na jeden a ten samej skript obsluhuje jinej proces s jinym PID. Nakonec tedy skoncime tak, ze bude otevrenejch X stejnejch spojeni na SQL server.
p-spojeni nejdou zavrit. (aha, to tam je uvedeno u odemykani tabulek, ale dost skryte)
"je nutné max_connections nastavit na hodnotu, která už může výkon serveru výrazně zhoršovat."
duvod, vytvori se novy procesy preforkovanim nebo se jen proste zabiraji file descriptors?
z tohohle clanku mi pripada, ze p-spojeni jsou v podstate dobrej napad. Je tomu bohuzel obracene (opakuji, mluvim o klasickej skriptech na shared hostingach a pod shared hostingem myslim stav, kdy na jednom serveru bezi vic jak jedna aplikace/web, coz predpokladam je stav popisovany v clanku taky, neni nikde uvedeno jinak)
co se stane, kdyz bude vycerpan pocet maximalnich spojeni, vsechny spojeni bude mit zabrany Apache a bude se chtit prihlasit superuser, aby ty spojeni killnul? Prihlasi se? Neprihlasi se?
To by mohlo stacit -- mam 6 odstavcu, stejne jako clanek, tudiz tak ;)
zvyrazneni *pro kazdy proces* nepomaha ;) toho jsem si vsiml uz predtim. Ta prvni cast ty vety (Funguje to tak, že PHP si pro každý proces udržuje úložiště otevřených připojení) sice plati, pokud si domyslime dulezitou vec a to ze to uloziste je pro kazdy proces jine. Druha cast (pokud se někdo chce k databázovému serveru připojit se stejnými přihlašovacími údaji, tak použije existující otevřené připojení a nezdržuje vytvářením nového) je na tom hur. Totiz nekdo neni jen tak nekdo, ale ten stejny proces, ktery to spojeni otevrel jiz drive a ma ho ve svem ulozisti. Proto jsou p-spojeni v podstate k nicemu, nase skripty budou obsluhovat ruzny procesy, a jako naschval ne ty, ktery uz spojeni otevrely ;)
Andrew:
Tak jak vidím, postupem času se mění Jakubův názor na tento způsob připojení.
Když jsem mu před nějakým tím rokem odevzdával práci na praktikum z PHP, tak jsme vedli menší diskusi na toto téma. Tehdy jsem persistentní připojení nepoužíval a Jakub mi doporučil ho využít. Jenže admin na servru, který jsem používal, pravděpodobně kvůli výše uvedeným problémům raději zvolil cestu tento typ spojení zakázat. Mno a Jakub se tomu tehdy velmi divil, co to je za admina. ;-)
Máš úplnou pravdu - o problémech spojených s persistentním připojením jsem nevěděl, dokud jsem je nepoznal na vlastní kůži. Nejsmutnější na tom je, že by se to dalo napsat tak, aby to bylo schopné fungování, ale bohužel to tak není.
Můj současný postoj je ten, že ve skriptech pconnect používat klidně lze (pokud je řešen problém se zamykanými tabulkami), ale na víceuživatelských serverech je lepší, když je správce zakáže - místo persistentních spojení se pak použijí normální.
Floyd:
Pro spaze:
Pokud server vyčerpá počet spojení, tak jediný, kdo se dokáže přihlásit je root. Je pro něj vždy vyhrazeno JEDNO spojení k MySQL serveru.
Dík za doplnění, já vím, ale ostatní by nemuseli.
Diskuse je zrušena z důvodu spamu.