{"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\/pl\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh","title":{"rendered":"RoadRunner: PHP nie jest stworzony, aby umiera\u0107, a Golang spieszy na pomoc","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RoadRunner: PHP nie jest stworzony, aby umiera\u0107, a Golang spieszy na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/d2a69318cf25caa8fb49efedb333d7f8.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCze\u015b\u0107, Habr! W Badoo intensywnie <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/badoo\/blog\/430722\/\">pracujemy nad wydajno\u015bci\u0105 PHP<\/a><\/noindex>, poniewa\u017c mamy do\u015b\u0107 du\u017c\u0105 system\u0119 opart\u0105 na tym j\u0119zyku, a wydajno\u015b\u0107 to kwestia oszcz\u0119dno\u015bci pieni\u0119dzy. Ponad dziesi\u0119\u0107 lat temu stworzyli\u015bmy PHP-FPM, kt\u00f3ry pocz\u0105tkowo by\u0142 zestawem poprawek dla PHP, a p\u00f3\u017aniej sta\u0142 si\u0119 cz\u0119\u015bci\u0105 oficjalnej dystrybucji.<\/p>\n<p>W ci\u0105gu ostatnich lat PHP znacznie si\u0119 rozwin\u0119\u0142o: poprawi\u0142o si\u0119 zarz\u0105dzanie pami\u0119ci\u0105, zwi\u0119kszy\u0142a si\u0119 stabilno\u015b\u0107 - teraz na PHP mo\u017cna bez wi\u0119kszych problem\u00f3w pisa\u0107 demony i d\u0142ugoterminowe skrypty. To pozwoli\u0142o Spiral Scout p\u00f3j\u015b\u0107 dalej: RoadRunner, w przeciwie\u0144stwie do PHP-FPM, nie oczyszcza pami\u0119ci mi\u0119dzy \u017c\u0105daniami, co daje dodatkowy zysk w wydajno\u015bci (cho\u0107 to podej\u015bcie komplikuje proces rozwoju). Obecnie eksperymentujemy z tym narz\u0119dziem, ale na razie nie mamy wynik\u00f3w, kt\u00f3rymi mogliby\u015bmy si\u0119 podzieli\u0107. Aby czekanie na nie by\u0142o przyjemniejsze, <b>publikujemy t\u0142umaczenie zapowiedzi RoadRunnera od Spiral Scout.<\/b><\/p>\n<p>Podej\u015bcie przedstawione w artykule jest nam bliskie: przy rozwi\u0105zywaniu naszych zada\u0144 r\u00f3wnie\u017c najcz\u0119\u015bciej u\u017cywamy po\u0142\u0105czenia PHP i Go, czerpi\u0105c korzy\u015bci z obu j\u0119zyk\u00f3w i nie rezygnuj\u0105c z jednego na rzecz drugiego.<\/p>\n<p>Mi\u0142ej lektury!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>W ci\u0105gu ostatnich dziesi\u0119ciu lat tworzyli\u015bmy aplikacje zar\u00f3wno dla firm z listy <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Fortune_Global_500\">Fortune 500<\/a><\/noindex>, jak i dla biznesu z audytorium licz\u0105cym nie wi\u0119cej ni\u017c 500 u\u017cytkownik\u00f3w. Przez ca\u0142y ten czas nasi in\u017cynierowie rozwijali backend g\u0142\u00f3wnie w PHP. Jednak dwa lata temu co\u015b mocno wp\u0142yn\u0119\u0142o nie tylko na wydajno\u015b\u0107 naszych produkt\u00f3w, ale tak\u017ce na ich skalowalno\u015b\u0107 - wprowadzili\u015bmy Golang (Go) do naszego staku technologii.<\/p>\n<p>Prawie od razu odkryli\u015bmy, \u017ce Go pozwala nam tworzy\u0107 wi\u0119ksze aplikacje z wzrostem wydajno\u015bci si\u0119gaj\u0105cym 40 razy. Dzi\u0119ki niemu mogli\u015bmy rozwija\u0107 istniej\u0105ce produkty napisane w PHP, poprawiaj\u0105c je dzi\u0119ki po\u0142\u0105czeniu zalet obu j\u0119zyk\u00f3w.<\/p>\n<p>Opowiemy, jak po\u0142\u0105czenie Go i PHP pomaga rozwi\u0105zywa\u0107 rzeczywiste problemy w programowaniu i jak sta\u0142o si\u0119 dla nas narz\u0119dziem, kt\u00f3re mo\u017ce pom\u00f3c w cz\u0119\u015bci problem\u00f3w zwi\u0105zanych z <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/179399\/\">modelem 'umieraj\u0105cego' PHP<\/a><\/noindex>.<\/p>\n<h3>Twoje codzienne \u015brodowisko PHP-dewelopera<\/h3>\n<p>\nZanim opowiemy, jak za pomoc\u0105 Go mo\u017cna o\u017cywi\u0107 model 'umieraj\u0105cego' PHP, przyjrzyjmy si\u0119 twojemu standardowemu \u015brodowisku PHP-dewelopera.<\/p>\n<p>W wi\u0119kszo\u015bci przypadk\u00f3w uruchamiasz aplikacj\u0119 za pomoc\u0105 kombinacji serwera WWW nginx i serwera PHP-FPM. Pierwszy obs\u0142uguje pliki statyczne i przekazuje specyficzne zapytania do PHP-FPM, a sam PHP-FPM wykonuje kod PHP. Mo\u017cliwe, \u017ce u\u017cywasz mniej popularnego po\u0142\u0105czenia Apache i mod_php. Cho\u0107 dzia\u0142a to nieco inaczej, zasady pozostaj\u0105 te same.<\/p>\n<p>Przyjrzyjmy si\u0119, jak PHP-FPM wykonuje kod aplikacji. Gdy przychodzi zapytanie, PHP-FPM inicjuje podrz\u0119dny proces PHP i przekazuje szczeg\u00f3\u0142y zapytania jako cz\u0119\u015b\u0107 jego stanu (_GET, _POST, _SERVER itd.). <\/p>\n<p>Stan nie mo\u017ce si\u0119 zmienia\u0107 w trakcie wykonywania skryptu PHP, zatem nowy zestaw danych wej\u015bciowych mo\u017cna uzyska\u0107 tylko w jeden spos\u00f3b: czyszcz\u0105c pami\u0119\u0107 procesu i inicjuj\u0105c go od nowa.<\/p>\n<p>Taki model wykonania ma wiele zalet. Nie musisz si\u0119 zbytnio martwi\u0107 o zu\u017cycie pami\u0119ci, wszystkie procesy s\u0105 ca\u0142kowicie izolowane, a je\u015bli jeden z nich \"umiera\", zostanie automatycznie odtworzony, co nie wp\u0142ynie na pozosta\u0142e procesy. Ale podej\u015bcie to ma te\u017c wady, kt\u00f3re ujawniaj\u0105 si\u0119 podczas pr\u00f3by skalowania aplikacji.<\/p>\n<h3>Wady i nieefektywno\u015b\u0107 standardowego \u015brodowiska PHP<\/h3>\n<p>\nJe\u015bli zajmujesz si\u0119 profesjonalnym programowaniem w PHP, wiesz, od czego zacz\u0105\u0107 nowy projekt \u2014 od wyboru frameworka. To biblioteki do wstrzykiwania zale\u017cno\u015bci, ORM-y, t\u0142umaczenia i szablony. Oczywi\u015bcie wszystkie wej\u015bciowe dane od u\u017cytkownik\u00f3w mo\u017cna wygodnie umie\u015bci\u0107 w jednym obiekcie (Symfony\/HttpFoundation lub PSR-7). Frameworki s\u0105 \u015bwietne!<\/p>\n<p>Ale wszystko ma swoj\u0105 cen\u0119. W ka\u017cdym frameworku na poziomie enterprise do obs\u0142ugi prostego zapytania u\u017cytkownika lub dost\u0119pu do bazy danych trzeba za\u0142adowa\u0107 co najmniej dziesi\u0105tki plik\u00f3w, stworzy\u0107 liczne klasy i przeanalizowa\u0107 kilka konfiguracji. Najgorsze jest to, \u017ce po wykonaniu ka\u017cdej czynno\u015bci musisz wszystko zresetowa\u0107 i zacz\u0105\u0107 od nowa: ca\u0142y w\u0142a\u015bnie zainicjowany przez ciebie kod staje si\u0119 bezu\u017cyteczny, nie mo\u017cesz za jego pomoc\u0105 obs\u0142u\u017cy\u0107 kolejnego zapytania. Powiedz o tym kt\u00f3remu\u015b programi\u015bcie, kt\u00f3ry pisze w innym j\u0119zyku \u2014 a zobaczysz zdziwienie na jego twarzy.<\/p>\n<p>Programi\u015bci PHP przez lata szukali sposob\u00f3w na rozwi\u0105zanie tego problemu, wykorzystuj\u0105c przemy\u015blane metody \u00bbleniwego\u00ab \u0142adowania, mikroforki, zoptymalizowane biblioteki, pami\u0119\u0107 podr\u0119czn\u0105 itd. Jednak w ko\u0144cu nadal trzeba zresetowa\u0107 ca\u0142\u0105 aplikacj\u0119 i zaczyna\u0107 od nowa, raz po raz.<i> (Nota t\u0142umacza: cz\u0119\u015bciowo problem ten zostanie rozwi\u0105zany wraz z pojawieniem si\u0119 <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.php.net\/rfc\/preload\">preload<\/a><\/noindex> w PHP 7.4)<\/p>\n<h3>Czy PHP z pomoc\u0105 Go mo\u017ce obs\u0142u\u017cy\u0107 wi\u0119cej ni\u017c jedno \u017c\u0105danie?<\/h3>\n<p>\n<\/i>Mo\u017cna napisa\u0107 skrypty PHP, kt\u00f3re przetrwaj\u0105 d\u0142u\u017cej ni\u017c kilka minut (a\u017c do godzin lub dni): na przyk\u0142ad zadania cron, parsowanie CSV, przetwarzanie kolejek. Wszystkie one dzia\u0142aj\u0105 zgodnie z tym samym schematem: pobieraj\u0105 zadanie, wykonuj\u0105 je, czekaj\u0105 na nast\u0119pne. Kod pozostaje w pami\u0119ci, oszcz\u0119dzaj\u0105c cenne milisekundy, poniewa\u017c za\u0142adowanie frameworka i aplikacji wymaga wykonania wielu dodatkowych czynno\u015bci.<\/p>\n<p>Jednak opracowanie skrypt\u00f3w d\u0142ugo\u017cyj\u0105cych nie jest takie proste. Ka\u017cdy b\u0142\u0105d ca\u0142kowicie zabija proces, diagnostyka wyciek\u00f3w pami\u0119ci doprowadza do sza\u0142u, a korzystanie z debugowania F5 jest ju\u017c niemo\u017cliwe.<\/p>\n<p>Sytuacja poprawi\u0142a si\u0119 wraz z wydaniem PHP 7: pojawi\u0142 si\u0119 niezawodny zbieracz \u015bmieci, \u0142atwiej jest obs\u0142ugiwa\u0107 b\u0142\u0119dy, a rozszerzenia rdzenia s\u0105 teraz chronione przed wyciekami. Prawda, in\u017cynierowie nadal musz\u0105 ostro\u017cnie obchodzi\u0107 si\u0119 z pami\u0119ci\u0105 i pami\u0119ta\u0107 o problemach z stanem w kodzie (czy istnieje j\u0119zyk, w kt\u00f3rym mo\u017cna by nie zwraca\u0107 na to uwagi?). Mimo wszystko w PHP 7 czeka nas mniej niespodzianek.<\/p>\n<p>Czy mo\u017cna wzi\u0105\u0107 model pracy z d\u0142ugo\u017cyj\u0105cymi skryptami PHP, dostosowa\u0107 go do bardziej trywialnych zada\u0144, takich jak obs\u0142uga \u017c\u0105da\u0144 HTTP i tym samym pozby\u0107 si\u0119 potrzeby \u0142adowania wszystkiego od nowa przy ka\u017cdym \u017c\u0105daniu?<\/p>\n<p>Aby rozwi\u0105za\u0107 ten problem, najpierw trzeba by\u0142o zaimplementowa\u0107 aplikacj\u0119 serwerow\u0105, kt\u00f3ra mog\u0142aby przyjmowa\u0107 \u017c\u0105dania HTTP i przekazywa\u0107 je jeden po drugim do pracownika PHP, nie zabijaj\u0105c go za ka\u017cdym razem.<\/p>\n<p>Wiedzieli\u015bmy, \u017ce mo\u017cemy stworzy\u0107 serwer internetowy w czystym PHP (PHP-PM) lub przy u\u017cyciu rozszerzenia C (Swoole). I cho\u0107 ka\u017cda metoda ma swoje zalety, \u017cadna z nich nas nie satysfakcjonowa\u0142a \u2013 oczekiwali\u015bmy czego\u015b wi\u0119cej. Potrzebowali\u015bmy nie tylko serwera internetowego \u2013 planowali\u015bmy uzyska\u0107 rozwi\u0105zanie, kt\u00f3re uwolni\u0142oby nas od problem\u00f3w zwi\u0105zanych z \"ci\u0119\u017ckim startem\" w PHP, a jednocze\u015bnie by\u0142oby \u0142atwe do dostosowania i rozbudowy wed\u0142ug konkretnych aplikacji. To znaczy, potrzebny by\u0142 nam serwer aplikacji.<\/p>\n<p>Czy Go mo\u017ce w tym pom\u00f3c? Wiedzieli\u015bmy, \u017ce mo\u017ce, poniewa\u017c ten j\u0119zyk kompiluje aplikacje do pojedynczych plik\u00f3w binarnych; jest wieloplatformowy; wykorzystuje w\u0142asny, bardzo elegancki model wsp\u00f3\u0142bie\u017cno\u015bci (concurrency) oraz bibliotek\u0119 do obs\u0142ugi HTTP; i w ko\u0144cu b\u0119dziemy mieli dost\u0119p do tysi\u0119cy bibliotek open-source i integracji.<\/p>\n<h3>Trudno\u015bci w integracji dw\u00f3ch j\u0119zyk\u00f3w programowania<\/h3>\n<p>\nPrzede wszystkim trzeba by\u0142o okre\u015bli\u0107, jak dwa lub wi\u0119cej aplikacji b\u0119d\u0105 komunikowa\u0107 si\u0119 ze sob\u0105.<\/p>\n<p>Na przyk\u0142ad, za pomoc\u0105<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deuill\/go-php\"> wspania\u0142ej biblioteki<\/a><\/noindex> Aleksa Palaeustrasa mo\u017cna by\u0142o zrealizowa\u0107 wsp\u00f3\u0142dzielenie pami\u0119ci mi\u0119dzy procesami PHP i Go (analogicznie do mod_php w Apache). Jednak ta biblioteka ma swoje cechy, kt\u00f3re ograniczaj\u0105 jej zastosowanie w rozwi\u0105zaniu naszego problemu.<\/p>\n<p>Postanowili\u015bmy zastosowa\u0107 inne, bardziej rozpowszechnione podej\u015bcie: zbudowa\u0107 interakcj\u0119 mi\u0119dzy procesami przez gniazda\/pipeline. To podej\u015bcie w ci\u0105gu ostatnich kilku dziesi\u0119cioleci udowodni\u0142o swoj\u0105 niezawodno\u015b\u0107 i zosta\u0142o dobrze zoptymalizowane na poziomie systemu operacyjnego.<\/p>\n<p>Na pocz\u0105tek stworzyli\u015bmy prosty protok\u00f3\u0142 binarny do wymiany danych mi\u0119dzy procesami i obs\u0142ugi b\u0142\u0119d\u00f3w transmisji. W najprostszej formie protok\u00f3\u0142 tego rodzaju przypomina <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Netstring\">netstring<\/a><\/noindex> z<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> z nag\u0142\u00f3wkiem o sta\u0142ej wielko\u015bci<\/a><\/noindex> (w naszym przypadku 17 bajt\u00f3w), kt\u00f3ry zawiera informacje o typie pakietu, jego rozmiarze oraz dw\u00f3jkowej masce do sprawdzania integralno\u015bci danych.<\/p>\n<p>Po stronie PHP u\u017cyli\u015bmy <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/php-src\/SocketRelay.php#L247\">funkcji pack<\/a><\/noindex>, a po stronie Go \u2013 biblioteki<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/prefix.go\"> encoding\/binary<\/a><\/noindex>.<\/p>\n<p>Jednego protoko\u0142u uznali\u015bmy za niewystarczaj\u0105ce \u2013 dodali\u015bmy mo\u017cliwo\u015b\u0107 wywo\u0142ywania<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\/blob\/master\/codec.go\"> us\u0142ug Go net\/rpc bezpo\u015brednio z PHP<\/a><\/noindex>. P\u00f3\u017aniej bardzo nam to pomog\u0142o w rozwoju, poniewa\u017c mogli\u015bmy \u0142atwo integrowa\u0107 biblioteki Go w aplikacjach PHP. Wynik tej pracy mo\u017cna zobaczy\u0107, na przyk\u0142ad, w naszym innym produkcie open-source<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/goridge\"> Goridge<\/a><\/noindex>.<\/p>\n<h3>Rozdzielanie zada\u0144 pomi\u0119dzy kilka pracownik\u00f3w PHP<\/h3>\n<p>\nPo wdro\u017ceniu mechanizmu interakcji zacz\u0119li\u015bmy my\u015ble\u0107, jak najbardziej efektywnie przekazywa\u0107 zadania procesom PHP. Kiedy przychodzi zadanie, serwer aplikacji musi wybra\u0107 wolnego pracownika do jego wykonania. Je\u015bli pracownik\/proces zako\u0144czy\u0142 prac\u0119 z b\u0142\u0119dem lub 'umar\u0142', pozbywamy si\u0119 go i tworzymy nowego w zamian. A je\u015bli pracownik\/proces zako\u0144czy\u0142 zadanie pomy\u015blnie, zwracamy go do puli dost\u0119pnych pracownik\u00f3w.<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP nie jest stworzony, aby umiera\u0107, a Golang spieszy na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/fe94ef304e0327247973ddd15723285a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDo przechowywania puli aktywnych pracownik\u00f3w u\u017cyli\u015bmy<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/static_pool.go\"> buforowanego kana\u0142u<\/a><\/noindex>, aby usun\u0105\u0107 z puli niespodziewanie 'umar\u0142ych' pracownik\u00f3w, dodali\u015bmy mechanizm \u015bledzenia b\u0142\u0119d\u00f3w i stan\u00f3w pracownik\u00f3w.<\/p>\n<p>W efekcie uzyskali\u015bmy dzia\u0142aj\u0105cy serwer PHP, zdolny do przetwarzania wszelkich zapyta\u0144, przedstawionych w formacie binarnym.<\/p>\n<p>Aby nasza aplikacja zacz\u0119\u0142a dzia\u0142a\u0107 jako serwer webowy, musieli\u015bmy wybra\u0107 niezawodny standard PHP do reprezentacji wszelkich przychodz\u0105cych zapyta\u0144 HTTP. W naszym przypadku po prostu <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/blob\/master\/service\/http\/request.go\">przekszta\u0142camy<\/a><\/noindex> \u017c\u0105danie net\/http z Go w format<noindex><a rel=\"nofollow\" href=\"https:\/\/www.php-fig.org\/psr\/psr-7\/meta\/\"> PSR-7<\/a><\/noindex>, aby by\u0142 zgodny z wi\u0119kszo\u015bci\u0105 dost\u0119pnych dzisiaj framework\u00f3w PHP.<\/p>\n<p>Poniewa\u017c PSR-7 uwa\u017cany jest za niemodyfikowalny (niekt\u00f3rzy powiedz\u0105, \u017ce technicznie nie jest), deweloperzy musz\u0105 pisa\u0107 aplikacje, kt\u00f3re zasadniczo nie traktuj\u0105 \u017c\u0105da\u0144 jako globalnej encji. To doskonale pasuje do koncepcji d\u0142ugoterminowych proces\u00f3w PHP. Nasza finalna implementacja, kt\u00f3ra jeszcze nie otrzyma\u0142a nazwy, wygl\u0105da\u0142a tak:<\/p>\n<p><img decoding=\"async\" alt=\"RoadRunner: PHP nie jest stworzony, aby umiera\u0107, a Golang spieszy na pomoc\" src=\"\/wp-content\/uploads\/2019\/06\/e3a3a1af1925dfc60b7f8fd256d1ae11.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h3>Przedstawiamy RoadRunner \u2014<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> wysokowydajny serwer aplikacji PHP<\/a><\/noindex><\/h3>\n<p>\nNaszym pierwszym testowym zadaniem by\u0142 backend API, na kt\u00f3rym okresowo wyst\u0119powa\u0142y nieprzewidywalne skoki zapyta\u0144 (znacznie cz\u0119\u015bciej ni\u017c zwykle). Mimo \u017ce w wi\u0119kszo\u015bci przypadk\u00f3w mo\u017cliwo\u015bci nginx by\u0142y wystarczaj\u0105ce, regularnie napotykali\u015bmy b\u0142\u0105d 502, poniewa\u017c nie mogli\u015bmy wystarczaj\u0105co szybko zbalansowa\u0107 systemu do oczekiwanego wzrostu obci\u0105\u017cenia.<\/p>\n<p>Aby zast\u0105pi\u0107 to rozwi\u0105zanie, na pocz\u0105tku 2018 roku wdro\u017cyli\u015bmy nasz pierwszy serwer aplikacji PHP\/Go. I od razu uzyskali\u015bmy niesamowity efekt! Nie tylko ca\u0142kowicie pozbyli\u015bmy si\u0119 b\u0142\u0119du 502, ale r\u00f3wnie\u017c uda\u0142o nam si\u0119 zmniejszy\u0107 liczb\u0119 serwer\u00f3w o dwie trzecie, oszcz\u0119dzaj\u0105c mn\u00f3stwo pieni\u0119dzy i tabletek przeciwb\u00f3lowych dla in\u017cynier\u00f3w i mened\u017cer\u00f3w produkt\u00f3w.<\/p>\n<p>W po\u0142owie roku udoskonalili\u015bmy nasze rozwi\u0105zanie, opublikowali\u015bmy je na GitHubie na licencji MIT i nazwali\u015bmy <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\">RoadRunner<\/a><\/noindex>, podkre\u015blaj\u0105c tym samym jego niesamowit\u0105 pr\u0119dko\u015b\u0107 i wydajno\u015b\u0107.<\/p>\n<h3>Jak RoadRunner mo\u017ce poprawi\u0107 Tw\u00f3j stos rozwoju<\/h3>\n<p>\nZastosowanie<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\"> RoadRunner<\/a><\/noindex> pozwoli\u0142o nam wykorzysta\u0107 middleware net\/http po stronie Go, aby przeprowadza\u0107 weryfikacj\u0119 JWT jeszcze przed dotarciem zapytania do PHP, a tak\u017ce do obs\u0142ugi WebSockets i globalnego agregowania stan\u00f3w w Prometheus. <\/p>\n<p>Dzi\u0119ki wbudowanemu RPC mo\u017cna otworzy\u0107 API dowolnych bibliotek Go dla PHP bez konieczno\u015bci pisania wrapper\u00f3w w postaci rozszerze\u0144. Co wa\u017cniejsze, z pomoc\u0105 RoadRunnera mo\u017cna wdra\u017ca\u0107 nowe serwery, kt\u00f3re r\u00f3\u017cni\u0105 si\u0119 od HTTP. Przyk\u0142ady obejmuj\u0105 uruchamianie w PHP procesor\u00f3w<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/roadrunner\/wiki\/AWS-Lambda\"> AWS Lambda<\/a><\/noindex>, tworzenie niezawodnych parser\u00f3w kolejek, a nawet dodawanie<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spiral\/php-grpc\"> gRPC<\/a><\/noindex> do naszych aplikacji.<\/p>\n<p>Przy wsparciu spo\u0142eczno\u015bci PHP i Go poprawili\u015bmy stabilno\u015b\u0107 rozwi\u0105zania, w niekt\u00f3rych testach zwi\u0119kszyli\u015bmy wydajno\u015b\u0107 aplikacji do 40 razy, udoskonalili\u015bmy narz\u0119dzia do debugowania, zaimplementowali\u015bmy integracj\u0119 z frameworkiem Symfony oraz dodali\u015bmy wsparcie dla HTTPS, HTTP\/2, wtyczek i PSR-17.<\/p>\n<h3>Podsumowanie<\/h3>\n<p>\nNiekt\u00f3rzy wci\u0105\u017c tkwi\u0105 w przestarza\u0142ym wyobra\u017ceniu o PHP jako o wolnym, niepor\u0119cznym j\u0119zyku, nadaj\u0105cym si\u0119 jedynie do pisania wtyczek pod WordPress. Ci ludzie mog\u0105 nawet powiedzie\u0107, \u017ce PHP ma takie ograniczenie: gdy aplikacja staje si\u0119 wystarczaj\u0105co du\u017ca, trzeba wybiera\u0107 bardziej \u00abdojrza\u0142y\u00bb j\u0119zyk i przepisywa\u0107 nagromadzony przez lata kod.<\/p>\n<p>Na to wszystko chcemy odpowiedzie\u0107: pomy\u015bl jeszcze raz. Uwa\u017camy, \u017ce tylko Ty sam nak\u0142adasz jakiekolwiek ograniczenia na PHP. Mo\u017cesz sp\u0119dzi\u0107 ca\u0142e \u017cycie przechodz\u0105c z jednego j\u0119zyka na drugi, pr\u00f3buj\u0105c znale\u017a\u0107 idealne dopasowanie do swoich potrzeb, lub mo\u017cesz zacz\u0105\u0107 postrzega\u0107 j\u0119zyki jako narz\u0119dzia. Rzekome niedoci\u0105gni\u0119cia j\u0119zyka takiego jak PHP mog\u0105 w rzeczywisto\u015bci by\u0107 powodem jego sukcesu. A je\u015bli po\u0142\u0105czysz go z innym j\u0119zykiem, takim jak Go, stworzysz znacznie pot\u0119\u017cniejsze produkty, ni\u017c gdyby\u015b ograniczy\u0142 si\u0119 do korzystania z jednego j\u0119zyka.<\/p>\n<p>Po pracy z zestawem Go i PHP mo\u017cemy stwierdzi\u0107, \u017ce pokochali\u015bmy je. Nie planujemy po\u015bwi\u0119ca\u0107 jednego na rzecz drugiego \u2014 wr\u0119cz przeciwnie, b\u0119dziemy szuka\u0107 sposob\u00f3w, aby wydoby\u0107 jeszcze wi\u0119cej korzy\u015bci z tego podw\u00f3jnego stosu.<\/p>\n<p><i>UPD: witamy tw\u00f3rc\u0119 RoadRunnera i wsp\u00f3\u0142autora oryginalnego artyku\u0142u \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/users\/lachezis\/\" class=\"user_link\">Lachezis<\/a><\/noindex><\/i><br \/>\n<br \/>\u0179r\u00f3d\u0142o: <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.1.1 - 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\/pl\/blog\/administrirovanie\/roadrunner-php-ne-sozdan-chtoby-umirat-ili-golang-speshit-na-pomoshh\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\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\/pl\/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 nie jest stworzony, aby umiera\u0107, lub Golang spieszy na pomoc | ProHoster","description":"Cze\u015b\u0107, Habr!","canonical_url":"https:\/\/prohoster.info\/pl\/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":"pl_PL","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\/pl\/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\/pl\/wp-json\/wp\/v2\/posts\/35722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=35722"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/35722\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/26762"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=35722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=35722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=35722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}