{"id":35722,"date":"2019-10-31T22:05:58","date_gmt":"2019-10-31T19:05:58","guid":{"rendered":"https:\/\/prohoster.info\/blog\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\/"},"modified":"2019-10-31T22:05:58","modified_gmt":"2019-10-31T19:05:58","slug":"roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","status":"publish","type":"post","link":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","title":{"rendered":"RoadRunner: PHP nebylo navr\u017eeno, aby um\u00edralo, nebo Golang sp\u011bch\u00e1 na pomoc","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RoadRunner: PHP nebylo navr\u017eeno, aby um\u00edralo, nebo Golang sp\u011bch\u00e1 na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/d2a69318cf25caa8fb49efedb333d7f8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAhoj, Habr! V Badoo aktivn\u011b <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/badoo\/blog\/430722\/\">pracujeme na v\u00fdkonnosti PHP<\/a><\/noindex>, proto\u017ee m\u00e1me dost velk\u00fd syst\u00e9m na tomto jazyce a ot\u00e1zka v\u00fdkonnosti je ot\u00e1zkou \u00faspory pen\u011bz. P\u0159ed v\u00edce ne\u017e deseti lety jsme vytvo\u0159ili PHP-FPM, kter\u00e9 zpo\u010d\u00e1tku p\u0159edstavovalo sadu patch\u016f pro PHP, a pozd\u011bji se stalo sou\u010d\u00e1st\u00ed ofici\u00e1ln\u00ed distribuce.<\/p>\n<p>Za posledn\u00ed roky PHP zna\u010dn\u011b pokro\u010dilo: vylep\u0161il se garbage collector, zv\u00fd\u0161ila se \u00farove\u0148 stability \u2014 dnes na PHP lze bez v\u011bt\u0161\u00edch probl\u00e9m\u016f ps\u00e1t d\u00e9mony a dlouho b\u011b\u017e\u00edc\u00ed skripty. To umo\u017enilo Spiral Scout j\u00edt d\u00e1le: RoadRunner, na rozd\u00edl od PHP-FPM, ne\u010di\u0161t\u00ed pam\u011b\u0165 mezi po\u017eadavky, co\u017e p\u0159in\u00e1\u0161\u00ed dal\u0161\u00ed zisk ve v\u00fdkonnosti (i kdy\u017e tento p\u0159\u00edstup komplikuje proces v\u00fdvoje). V sou\u010dasnosti experimentujeme s t\u00edmto n\u00e1strojem, ale zat\u00edm nem\u00e1me v\u00fdsledky, kter\u00fdmi bychom se mohli pod\u011blit. Aby \u010dek\u00e1n\u00ed na n\u011b bylo z\u00e1bavn\u011bj\u0161\u00ed, <b>publikujeme p\u0159eklad ozn\u00e1men\u00ed RoadRunner od Spiral Scout.<\/b><\/p>\n<p>P\u0159\u00edstup popsan\u00fd v \u010dl\u00e1nku n\u00e1m je bl\u00edzk\u00fd: p\u0159i \u0159e\u0161en\u00ed na\u0161ich \u00fakol\u016f tak\u00e9 \u010dast\u011bji pou\u017e\u00edv\u00e1me kombinaci PHP a Go, co\u017e n\u00e1m p\u0159in\u00e1\u0161\u00ed v\u00fdhody obou jazyk\u016f, ani\u017e bychom se museli vzd\u00e1t jednoho na \u00fakor druh\u00e9ho.<\/p>\n<p>U\u017e\u00edvejte si!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>V posledn\u00edch deseti letech jsme vytv\u00e1\u0159eli aplikace jak pro spole\u010dnosti ze seznamu <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Fortune_Global_500\">Fortune 500<\/a><\/noindex>, tak pro podniky s publikem ne v\u00edce ne\u017e 500 u\u017eivatel\u016f. Po celou tuto dobu na\u0161i in\u017een\u00fd\u0159i p\u0159ev\u00e1\u017en\u011b vyv\u00edjeli backend p\u0159ev\u00e1\u017en\u011b v PHP. Ale p\u0159ed dv\u011bma lety n\u011bco siln\u011b ovlivnilo nejen v\u00fdkon na\u0161ich produkt\u016f, ale tak\u00e9 jejich \u0161k\u00e1lovatelnost \u2014 zavedli jsme Golang (Go) do na\u0161eho technologick\u00e9ho stacku.<\/p>\n<p>T\u00e9m\u011b\u0159 okam\u017eit\u011b jsme zjistili, \u017ee Go n\u00e1m umo\u017e\u0148uje vytv\u00e1\u0159et v\u011bt\u0161\u00ed aplikace se zv\u00fd\u0161en\u00edm v\u00fdkonu a\u017e 40kr\u00e1t. S jeho pomoc\u00ed jsme mohli roz\u0161i\u0159ovat existuj\u00edc\u00ed produkty napsan\u00e9 v PHP, zlep\u0161uj\u00edc\u00ed je kombinac\u00ed v\u00fdhod obou jazyk\u016f.<\/p>\n<p>Pov\u00edme v\u00e1m, jak kombinace Go a PHP pom\u00e1h\u00e1 \u0159e\u0161it skute\u010dn\u00e9 v\u00fdvojov\u00e9 \u00fakoly a jak se pro n\u00e1s stala n\u00e1strojem, kter\u00fd n\u00e1m m\u016f\u017ee uleh\u010dit \u010d\u00e1st probl\u00e9m\u016f spojen\u00fdch s <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/179399\/\">modelem \u201eum\u00edr\u00e1n\u00ed\u201c PHP<\/a><\/noindex>.<\/p>\n<h3>Va\u0161e ka\u017edodenn\u00ed prost\u0159ed\u00ed pro PHP v\u00fdvoj\u00e1\u0159e<\/h3>\n<p>\nNe\u017e za\u010dneme mluvit o tom, jak pomoc\u00ed Go o\u017eivit model \u201eum\u00edr\u00e1n\u00ed\u201c PHP, pod\u00edvejme se na va\u0161i standardn\u00ed PHP v\u00fdvoj\u00e1\u0159skou prost\u0159ed\u00ed.<\/p>\n<p>V\u011bt\u0161inu p\u0159\u00edpad\u016f spou\u0161t\u00edte aplikaci pomoc\u00ed kombinace webov\u00e9ho serveru nginx a PHP-FPM. Prvn\u00ed zpracov\u00e1v\u00e1 statick\u00e9 soubory a p\u0159esm\u011brov\u00e1v\u00e1 specifick\u00e9 dotazy na PHP-FPM, zat\u00edmco PHP-FPM vykon\u00e1v\u00e1 PHP k\u00f3d. Mo\u017en\u00e1 pou\u017e\u00edv\u00e1te m\u00e9n\u011b popul\u00e1rn\u00ed kombinaci Apache a mod_php. Ale i kdy\u017e to funguje trochu jinak, principy z\u016fst\u00e1vaj\u00ed stejn\u00e9.<\/p>\n<p>Pod\u00edvejme se, jak PHP-FPM vykon\u00e1v\u00e1 k\u00f3d aplikace. Kdy\u017e p\u0159ijde \u017e\u00e1dost, PHP-FPM inicializuje pod\u0159\u00edzen\u00fd PHP proces a detaily \u017e\u00e1dosti p\u0159ed\u00e1v\u00e1 jako sou\u010d\u00e1st jeho stavu (_GET, _POST, _SERVER atd.). <\/p>\n<p>Stav se b\u011bhem vykon\u00e1v\u00e1n\u00ed PHP skriptu nem\u016f\u017ee m\u011bnit, a proto lze z\u00edskat novou sadu vstupn\u00edch dat pouze jedn\u00edm zp\u016fsobem: vy\u010di\u0161t\u011bn\u00edm pam\u011bti procesu a jeho novou inicializac\u00ed.<\/p>\n<p>Tento model vykon\u00e1v\u00e1n\u00ed m\u00e1 mnoho v\u00fdhod. Nemus\u00edte se p\u0159\u00edli\u0161 ob\u00e1vat spot\u0159eby pam\u011bti, v\u0161echny procesy jsou zcela izolov\u00e1ny, a pokud jeden z nich \"um\u0159e\", bude automaticky znovu vytvo\u0159en, co\u017e nijak neovlivn\u00ed ostatn\u00ed procesy. Tento p\u0159\u00edstup m\u00e1 v\u0161ak tak\u00e9 nev\u00fdhody, kter\u00e9 se projevuj\u00ed p\u0159i pokusu o \u0161k\u00e1lov\u00e1n\u00ed aplikace.<\/p>\n<h3>Nev\u00fdhody a neefektivnost b\u011b\u017en\u00e9ho PHP prost\u0159ed\u00ed<\/h3>\n<p>\nPokud se zab\u00fdv\u00e1te profesion\u00e1ln\u00edm v\u00fdvojem v PHP, v\u00edte, \u010d\u00edm za\u010d\u00edt nov\u00fd projekt - v\u00fdb\u011brem frameworku. Ten p\u0159edstavuje knihovny pro vkl\u00e1d\u00e1n\u00ed z\u00e1vislost\u00ed, ORM, p\u0159eklady a \u0161ablony. A samoz\u0159ejm\u011b, v\u0161echny vstupn\u00ed u\u017eivatelsk\u00e9 \u00fadaje m\u016f\u017eete pohodln\u011b um\u00edstit do jednoho objektu (Symfony\/HttpFoundation nebo PSR-7). Frameworky jsou skv\u011bl\u00e9!<\/p>\n<p>Ale v\u0161echno m\u00e1 svou cenu. V jak\u00e9mkoli frameworku podnikov\u00e9 \u00farovn\u011b pro zpracov\u00e1n\u00ed jednoduch\u00e9ho u\u017eivatelsk\u00e9ho dotazu nebo dotazu k datab\u00e1zi mus\u00edte na\u010d\u00edst minim\u00e1ln\u011b des\u00edtky soubor\u016f, vytvo\u0159it \u0159adu t\u0159\u00edd a zpracovat n\u011bkolik konfigurac\u00ed. Ale nejhor\u0161\u00ed na tom je, \u017ee po vykon\u00e1n\u00ed ka\u017ed\u00e9ho \u00fakolu mus\u00edte v\u0161e vyresetovat a za\u010d\u00edt znovu: ve\u0161ker\u00fd k\u00f3d, kter\u00fd jste pr\u00e1v\u011b iniciovali, se st\u00e1v\u00e1 bezcenn\u00fdm, proto\u017ee u\u017e s n\u00edm nebudete schopni zpracovat dal\u0161\u00ed \u017e\u00e1dost. \u0158ekn\u011bte to jak\u00e9mukoli program\u00e1torovi, kter\u00fd p\u00ed\u0161e v jin\u00e9m jazyce, a uvid\u00edte na jeho tv\u00e1\u0159i zmaten\u00ed.<\/p>\n<p>PHP in\u017een\u00fd\u0159i l\u00e9ta hledali zp\u016fsoby, jak tento probl\u00e9m vy\u0159e\u0161it, pou\u017e\u00edvali promy\u0161len\u00e9 techniky \"leniv\u00e9\" na\u010d\u00edt\u00e1n\u00ed, mikroframerky, optimalizovan\u00e9 knihovny, cache atd. Ale nakonec je stejn\u011b t\u0159eba v\u0161echno aplikaci resetovat a za\u010d\u00edt znovu, znova a znova.<i> (Pozn\u00e1mka p\u0159ekladatele: \u010d\u00e1ste\u010dn\u011b tento probl\u00e9m vy\u0159e\u0161\u00ed vyd\u00e1n\u00ed <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.php.net\/rfc\/preload\">preload<\/a><\/noindex> PHP 7.4)<\/p>\n<h3>M\u016f\u017ee PHP s pomoc\u00ed Go zvl\u00e1dnout v\u00edce ne\u017e jeden po\u017eadavek?<\/h3>\n<p>\n<\/i>Jsou mo\u017en\u00e9 PHP skripty, kter\u00e9 p\u0159e\u017eij\u00ed d\u00e9le ne\u017e n\u011bkolik minut (dokonce hodiny nebo dny): nap\u0159\u00edklad cron \u00falohy, CSV parsery, zpracovatele front. V\u0161echny funguj\u00ed na stejn\u00e9m principu: vyt\u00e1hnou \u00fakol, provedou ho, \u010dekaj\u00ed na dal\u0161\u00ed. K\u00f3d neust\u00e1le z\u016fst\u00e1v\u00e1 v pam\u011bti, co\u017e \u0161et\u0159\u00ed cenn\u00e9 milisekundy, proto\u017ee na\u010d\u00edt\u00e1n\u00ed frameworku a aplikace vy\u017eaduje prov\u00e1d\u011bt spoustu dal\u0161\u00edch postup\u016f.<\/p>\n<p>Ale v\u00fdvoj dlouhov\u011bk\u00fdch skript\u016f nen\u00ed tak jednoduch\u00fd. Jak\u00e1koliv chyba zcela zabije proces, diagnostika \u00fanik\u016f pam\u011bti p\u0159iv\u00e1d\u00ed k \u0161\u00edlenstv\u00ed a debugging s F5 u\u017e nen\u00ed mo\u017en\u00e9.<\/p>\n<p>Situace se zlep\u0161ila s p\u0159\u00edchodem PHP 7: objevil se spolehliv\u00fd garbage collector, zpracov\u00e1n\u00ed chyb je snaz\u0161\u00ed a roz\u0161\u00ed\u0159en\u00ed j\u00e1dra jsou nyn\u00ed chr\u00e1n\u011bna p\u0159ed \u00faniky. Ale in\u017een\u00fd\u0159i st\u00e1le mus\u00ed opatrn\u011b zach\u00e1zet s pam\u011bt\u00ed a m\u00edt na pam\u011bti probl\u00e9my se stavem v k\u00f3du (existuje v\u016fbec jazyk, kde se t\u011bmto v\u011bcem nemus\u00ed v\u011bnovat?). A p\u0159esto je v PHP 7 m\u00e9n\u011b p\u0159ekvapen\u00ed.<\/p>\n<p>Lze vz\u00edt model pr\u00e1ce s dlouhov\u011bk\u00fdmi PHP skripty, p\u0159izp\u016fsobit jej pro banaln\u011bj\u0161\u00ed \u00fakoly, jako je zpracov\u00e1n\u00ed HTTP po\u017eadavk\u016f a t\u00edm se zbavit pot\u0159eby na\u010d\u00edtat v\u0161echno znovu p\u0159i ka\u017ed\u00e9m po\u017eadavku?<\/p>\n<p>Abychom tento \u00fakol vy\u0159e\u0161ili, bylo nejprve t\u0159eba implementovat serverovou aplikaci, schopnou p\u0159ij\u00edmat HTTP po\u017eadavky a postupn\u011b je p\u0159esm\u011brov\u00e1vat na PHP pracovn\u00edka, ani\u017e bychom jej poka\u017ed\u00e9 zabili.<\/p>\n<p>V\u011bd\u011bli jsme, \u017ee dok\u00e1\u017eeme napsat webov\u00fd server v \u010dist\u00e9m PHP (PHP-PM) nebo s vyu\u017eit\u00edm C-roz\u0161\u00ed\u0159en\u00ed (Swoole). A\u010dkoliv m\u00e1 ka\u017ed\u00fd zp\u016fsob sv\u00e9 v\u00fdhody, ob\u011b varianty n\u00e1s neuspokojily \u2014 tou\u017eili jsme po n\u011b\u010dem v\u00edc. Pot\u0159ebovali jsme nejen webov\u00fd server \u2014 pl\u00e1novali jsme z\u00edskat \u0159e\u0161en\u00ed, kter\u00e9 by n\u00e1s zbavilo probl\u00e9m\u016f spojen\u00fdch s \"t\u011b\u017ek\u00fdm startem\" v PHP, a kter\u00e9 by se dalo snadno p\u0159izp\u016fsobit a roz\u0161\u00ed\u0159it pro konkr\u00e9tn\u00ed aplikace. Jin\u00fdmi slovy, pot\u0159ebovali jsme aplika\u010dn\u00ed server.<\/p>\n<p>M\u016f\u017ee v tom pomoci Go? V\u011bd\u011bli jsme, \u017ee ano, proto\u017ee tento jazyk kompiluje aplikace do jednotliv\u00fdch bin\u00e1rn\u00edch soubor\u016f; je multiplatformn\u00ed; pou\u017e\u00edv\u00e1 vlastn\u00ed, velmi elegantn\u00ed model paraleln\u00edho zpracov\u00e1n\u00ed (concurrency) a knihovnu pro pr\u00e1ci s HTTP; a kone\u010dn\u011b, budou n\u00e1m k dispozici tis\u00edce open-source knihoven a integrac\u00ed.<\/p>\n<h3>Obt\u00ed\u017ee p\u0159i spojov\u00e1n\u00ed dvou programovac\u00edch jazyk\u016f<\/h3>\n<p>\nNejprve bylo nutn\u00e9 ur\u010dit, jak spolu budou komunikovat dv\u011b a v\u00edce aplikac\u00ed.<\/p>\n<p>Nap\u0159\u00edklad pomoc\u00ed<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deuill\/go-php\"> skv\u011bl\u00e9 knihovny<\/a><\/noindex> Alexe Pal\u00e4stra se dalo realizovat sd\u00edlen\u00ed pam\u011bti mezi procesy PHP a Go (analogicky jako mod_php v Apache). Ale tato knihovna m\u00e1 zvl\u00e1\u0161tnosti, kter\u00e9 omezuj\u00ed jej\u00ed pou\u017eit\u00ed k vy\u0159e\u0161en\u00ed na\u0161eho \u00fakolu.<\/p>\n<p>Rozhodli jsme se pou\u017e\u00edt jin\u00fd, roz\u0161\u00ed\u0159en\u011bj\u0161\u00ed p\u0159\u00edstup: vybudovat interakci mezi procesy prost\u0159ednictv\u00edm soket\u016f\/pipeliny. Tento p\u0159\u00edstup za posledn\u00ed desetilet\u00ed prok\u00e1zal svou spolehlivost a byl dob\u0159e optimalizov\u00e1n na \u00farovni opera\u010dn\u00edho syst\u00e9mu.<\/p>\n<p>Nejprve jsme vytvo\u0159ili jednoduch\u00fd bin\u00e1rn\u00ed protokol pro v\u00fdm\u011bnu dat mezi procesy a zpracov\u00e1n\u00ed chyb p\u0159i p\u0159enosu. V nejjednodu\u0161\u0161\u00ed podob\u011b je protokol tohoto typu podobn\u00fd <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Netstring\">netstring<\/a><\/noindex> s<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> hlavi\u010dce fixed-size paketu<\/a><\/noindex> (v na\u0161em p\u0159\u00edpad\u011b 17 byt\u016f), kter\u00e1 obsahuje informace o typu paketu, jeho velikosti a bin\u00e1rn\u00ed masku pro kontrolu integrity dat.<\/p>\n<p>Na stran\u011b PHP jsme pou\u017eili <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/php-src\/SocketRelay.php#L247\">funkci pack<\/a><\/noindex>, a na stran\u011b Go knihovnu<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> encoding\/binary<\/a><\/noindex>.<\/p>\n<p>Jednoho protokolu se n\u00e1m zd\u00e1lo m\u00e1lo \u2014 a p\u0159idali jsme mo\u017enost volat<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/codec.go\"> Go slu\u017eby net\/rpc p\u0159\u00edmo z PHP<\/a><\/noindex>. Pozd\u011bji n\u00e1m to velmi pomohlo ve v\u00fdvoji, proto\u017ee jsme mohli snadno integrovat Go knihovny do PHP aplikac\u00ed. V\u00fdsledek t\u00e9to pr\u00e1ce lze vid\u011bt nap\u0159\u00edklad v na\u0161em dal\u0161\u00edm open-source produktu<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\"> Goridge<\/a><\/noindex>.<\/p>\n<h3>Rozd\u011blen\u00ed \u00fakol\u016f mezi n\u011bkolika PHP pracovn\u00edky<\/h3>\n<p>\nPo implementaci mechanismu interakce jsme za\u010dali p\u0159em\u00fd\u0161let o tom, jak efektivn\u011bji p\u0159ed\u00e1vat \u00fakoly PHP proces\u016fm. Kdy\u017e p\u0159ijde \u00fakol, aplika\u010dn\u00ed server mus\u00ed vybrat voln\u00e9ho pracovn\u00edka, kter\u00fd jej vykon\u00e1. Pokud pracovn\u00edk\/proces skon\u010dil s chybou nebo \"zem\u0159el\", zbav\u00edme se ho a vytvo\u0159\u00edme nov\u00e9ho. A pokud pracovn\u00edk\/proces \u00fasp\u011b\u0161n\u011b dokon\u010dil pr\u00e1ci, vr\u00e1t\u00edme ho zp\u011bt do baz\u00e9nu dostupn\u00fdch pracovn\u00edk\u016f pro vykon\u00e1n\u00ed \u00fakol\u016f.<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP nebylo navr\u017eeno, aby um\u00edralo, nebo Golang sp\u011bch\u00e1 na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/fe94ef304e0327247973ddd15723285a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPro ukl\u00e1d\u00e1n\u00ed baz\u00e9nu aktivn\u00edch pracovn\u00edk\u016f jsme pou\u017eili<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/static_pool.go\"> bufferovan\u00fd kan\u00e1l<\/a><\/noindex>, k odstran\u011bn\u00ed neo\u010dek\u00e1van\u011b \"zem\u0159el\u00fdch\" pracovn\u00edk\u016f jsme p\u0159idali mechanismus sledov\u00e1n\u00ed chyb a stav\u016f pracovn\u00edk\u016f.<\/p>\n<p>V d\u016fsledku toho m\u00e1me funk\u010dn\u00ed PHP server, kter\u00fd je schopen zpracov\u00e1vat jak\u00e9koli dotazy, kter\u00e9 jsou p\u0159edlo\u017eeny bin\u00e1rn\u011b.<\/p>\n<p>Aby na\u0161e aplikace za\u010dala fungovat jako webov\u00fd server, museli jsme vybrat spolehliv\u00fd PHP standard pro reprezentaci jak\u00fdchkoli p\u0159\u00edchoz\u00edch HTTP dotaz\u016f. V na\u0161em p\u0159\u00edpad\u011b jednodu\u0161e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/service\/http\/request.go\">p\u0159evedeme<\/a><\/noindex> net\/http dotaz z Go do form\u00e1tu<noindex><a rel=\"nofollow\" href=\"https:\/\/www.php-fig.org\/psr\/psr-7\/meta\/\"> PSR-7<\/a><\/noindex>, aby byl kompatibiln\u00ed s v\u011bt\u0161inou dostupn\u00fdch dne\u0161n\u00edch PHP r\u00e1mc\u016f.<\/p>\n<p>Jeliko\u017e je PSR-7 pova\u017eov\u00e1n za nem\u011bnn\u00fd (n\u011bkdo by mohl \u0159\u00edci, \u017ee to technicky nen\u00ed pravda), musej\u00ed v\u00fdvoj\u00e1\u0159i ps\u00e1t aplikace, kter\u00e9 v z\u00e1sad\u011b nenakl\u00e1daj\u00ed s dotazem jako s glob\u00e1ln\u00ed entitou. To se skv\u011ble spojuje s konceptem dlouhotrvaj\u00edc\u00edch PHP proces\u016f. Na\u0161e kone\u010dn\u00e9 proveden\u00ed, kter\u00e9 je\u0161t\u011b nem\u00e1 n\u00e1zev, vypadalo takto:<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP nebylo navr\u017eeno, aby um\u00edralo, nebo Golang sp\u011bch\u00e1 na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/e3a3a1af1925dfc60b7f8fd256d1ae11.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>P\u0159edstavujeme RoadRunner \u2014<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> vysoce v\u00fdkonn\u00fd server PHP aplikac\u00ed<\/a><\/noindex><\/h3>\n<p>\nNa\u0161\u00edm prvn\u00edm testovac\u00edm \u00fakolem byl API backend, na kter\u00e9m se periodicky nepredikovateln\u00e9 vyskytovaly v\u00fdkyvy dotaz\u016f (mnohem \u010dast\u011bji ne\u017e obvykle). I kdy\u017e v\u011bt\u0161inou mo\u017enosti nginx sta\u010dily, pravideln\u011b jsme se setk\u00e1vali s chybou 502, proto\u017ee jsme nemohli dostate\u010dn\u011b rychle vyv\u00e1\u017eit syst\u00e9m pod o\u010dek\u00e1van\u00fdm n\u00e1r\u016fstem z\u00e1t\u011b\u017ee.<\/p>\n<p>Abychom nahradili toto \u0159e\u0161en\u00ed, na za\u010d\u00e1tku roku 2018 jsme nasadili n\u00e1\u0161 prvn\u00ed PHP\/Go server aplikac\u00ed. A hned jsme z\u00edskali \u00fa\u017easn\u00fd efekt! Nejen\u017ee jsme se zcela zbavili chyby 502, ale tak\u00e9 jsme mohli sn\u00ed\u017eit po\u010det server\u016f o dv\u011b t\u0159etiny, \u010d\u00edm\u017e jsme u\u0161et\u0159ili spoustu pen\u011bz a l\u00e9k\u016f na bolesti hlavy pro in\u017een\u00fdry a produktov\u00e9 mana\u017eery.<\/p>\n<p>V polovin\u011b roku jsme vylep\u0161ili na\u0161e \u0159e\u0161en\u00ed, zve\u0159ejnili ho na GitHubu pod licenc\u00ed MIT a pojmenovali <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\">RoadRunner<\/a><\/noindex>, co\u017e podtrhuje jeho neuv\u011b\u0159itelnou rychlost a efektivitu.<\/p>\n<h3>Jak m\u016f\u017ee RoadRunner zlep\u0161it v\u00e1\u0161 v\u00fdvojov\u00fd stack<\/h3>\n<p>\nPou\u017eit\u00ed<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> RoadRunner<\/a><\/noindex> n\u00e1m umo\u017enilo pou\u017e\u00edvat middleware net\/http na stran\u011b Go k prov\u00e1d\u011bn\u00ed JWT ov\u011b\u0159en\u00ed je\u0161t\u011b p\u0159ed t\u00edm, ne\u017e se po\u017eadavek dostane do PHP, a tak\u00e9 pro zpracov\u00e1n\u00ed WebSockets a glob\u00e1ln\u00ed agregaci stav\u016f do Promethea. <\/p>\n<p>D\u00edky vestav\u011bn\u00e9mu RPC lze otev\u00edrat API jak\u00fdchkoli Go knihoven pro PHP bez psan\u00ed roz\u0161i\u0159uj\u00edc\u00edch wrapper\u016f. Co je je\u0161t\u011b d\u016fle\u017eit\u011bj\u0161\u00ed, s RoadRunnerem lze nasazovat nov\u00e9 servery, kter\u00e9 se li\u0161\u00ed od HTTP. Jako p\u0159\u00edklad lze uv\u00e9st spu\u0161t\u011bn\u00ed PHP zpracovatel\u016f<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/wiki\/AWS-Lambda\"> AWS Lambda<\/a><\/noindex>, vytv\u00e1\u0159en\u00ed spolehliv\u00fdch zpracovatel\u016f front a dokonce i p\u0159id\u00e1v\u00e1n\u00ed<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/php-grpc\"> gRPC<\/a><\/noindex> do na\u0161ich aplikac\u00ed.<\/p>\n<p>S pomoc\u00ed komunit PHP a Go jsme zv\u00fd\u0161ili stabilitu \u0159e\u0161en\u00ed, v n\u011bkter\u00fdch testech jsme zv\u00fd\u0161ili v\u00fdkon aplikac\u00ed a\u017e 40kr\u00e1t, vylep\u0161ili jsme n\u00e1stroje pro lad\u011bn\u00ed, implementovali integraci s frameworkem Symfony a p\u0159idali podporu pro HTTPS, HTTP\/2, pluginy a PSR-17.<\/p>\n<h3>Z\u00e1v\u011br<\/h3>\n<p>\nN\u011bkte\u0159\u00ed lid\u00e9 jsou st\u00e1le uv\u011bzn\u011bni v zastaral\u00e9m pohledu na PHP jako na pomal\u00fd a objemn\u00fd jazyk, vhodn\u00fd pouze pro psan\u00ed plugin\u016f pro WordPress. Tito lid\u00e9 dokonce mohou \u0159\u00edct, \u017ee PHP m\u00e1 takov\u00e9 omezen\u00ed: kdy\u017e se aplikace stane dostate\u010dn\u011b velkou, mus\u00edte zvolit vysp\u011blej\u0161\u00ed jazyk a p\u0159epsat nahromad\u011bn\u00fd k\u00f3d, kter\u00fd m\u00e1te po mnoho let.<\/p>\n<p>Na to v\u0161echno bychom cht\u011bli odpov\u011bd\u011bt: zamyslete se znovu. Domn\u00edv\u00e1me se, \u017ee pouze vy si ur\u010dujete n\u011bjak\u00e1 omezen\u00ed pro PHP. M\u016f\u017eete str\u00e1vit cel\u00fd \u017eivot p\u0159echody z jednoho jazyka na druh\u00fd, abyste na\u0161li ide\u00e1ln\u00ed kombinaci pro va\u0161e pot\u0159eby, nebo m\u016f\u017eete za\u010d\u00edt vn\u00edmat jazyky jako n\u00e1stroje. Zd\u00e1nliv\u00e9 nev\u00fdhody jazyka jako PHP mohou b\u00fdt ve skute\u010dnosti p\u0159\u00ed\u010dinou jeho \u00fasp\u011bchu. A pokud ho spoj\u00edte s jin\u00fdm jazykem jako Go, vytvo\u0159\u00edte mnohem mocn\u011bj\u0161\u00ed produkty, ne\u017e kdybyste se omezili na pou\u017e\u00edv\u00e1n\u00ed jen jednoho jazyka.<\/p>\n<p>Pracov\u00e1n\u00edm se spojen\u00edm Go a PHP m\u016f\u017eeme \u0159\u00edci, \u017ee jsme si je zamilovali. Nepl\u00e1nujeme ob\u011btovat jeden ve prosp\u011bch druh\u00e9ho - naopak budeme hledat zp\u016fsoby, jak je\u0161t\u011b v\u00edce vyu\u017e\u00edt tuto dvojitou technologii.<\/p>\n<p><i>UPD: v\u00edt\u00e1me tv\u016frce RoadRunnera a spoluautora p\u016fvodn\u00edho \u010dl\u00e1nku - <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/lachezis\/\" class=\"user_link\">Lachezis<\/a><\/noindex><\/i><br \/>\n<br \/>Zdroj: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/badoo\/blog\/434272\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u0432 Badoo \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043d\u0430\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e PHP, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0430\u0441 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0430 \u044d\u0442\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u0438 \u0432\u043e\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u2014 \u044d\u0442\u043e \u0432\u043e\u043f\u0440\u043e\u0441 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u0434\u0435\u043d\u0435\u0433. \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0441\u044f\u0442\u0438 \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e PHP-FPM, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u0430\u0442\u0447\u0435\u0439 \u0434\u043b\u044f PHP, \u0430 \u043f\u043e\u0437\u0436\u0435 \u0432\u043e\u0448\u0451\u043b \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0443. \u0417\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0433\u043e\u0434\u044b PHP \u0441\u0438\u043b\u044c\u043d\u043e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26762,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35722","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"cs_CZ\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47RoadRunner: PHP \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d, \u0447\u0442\u043e\u0431\u044b \u0443\u043c\u0438\u0440\u0430\u0442\u044c, \u0438\u043b\u0438 Golang \u0441\u043f\u0435\u0448\u0438\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:05:58+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:05:58+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47RoadRunner: PHP nebyl vytvo\u0159en proto, aby um\u00edral, nebo jak Golang sp\u011bch\u00e1 na pomoc | ProHoster","description":"Ahoj, Habr!","canonical_url":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"cs_CZ","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47RoadRunner: PHP \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043d, \u0447\u0442\u043e\u0431\u044b \u0443\u043c\u0438\u0440\u0430\u0442\u044c, \u0438\u043b\u0438 Golang \u0441\u043f\u0435\u0448\u0438\u0442 \u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!","og:url":"https:\/\/prohoster.info\/cs\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:05:58+00:00","article:modified_time":"2019-10-31T19:05:58+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35722","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 00:30:57","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:57:45","updated":"2026-01-22 00:30:57","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/35722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/comments?post=35722"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/posts\/35722\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media\/26762"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/media?parent=35722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/categories?post=35722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/cs\/wp-json\/wp\/v2\/tags?post=35722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}