RoadRunner: PHP is net boud om te stjerren, of Golang ta de rêding

RoadRunner: PHP is net boud om te stjerren, of Golang ta de rêding

Hoi Habr! Wy binne aktyf by Badoo wurkje oan PHP-prestaasjes, om't wy in frij grut systeem hawwe yn dizze taal en de prestaasjekwestje is in jildbesparring. Mear as tsien jier lyn makken wy PHP-FPM hjirfoar, dy't earst in set patches foar PHP wie, en letter de offisjele distribúsje ynfierd.

Yn 'e ôfrûne jierren hat PHP grutte foarútgong makke: de garbage collector is ferbettere, it nivo fan stabiliteit is ferhege - hjoed kinne jo sûnder problemen daemons en lange libbene skripts yn PHP skriuwe. Dit koe Spiral Scout fierder gean: RoadRunner, yn tsjinstelling ta PHP-FPM, makket gjin ûnthâld op tusken fersiken, wat in ekstra prestaasjeswinst jout (hoewol't dizze oanpak it ûntwikkelingsproses komplisearret). Wy eksperimintearje op it stuit mei dit ark, mar wy hawwe noch gjin resultaten om te dielen. Om it wachtsjen op har leuker te meitsjen, wy publisearje de oersetting fan 'e RoadRunner-oankundiging fan Spiral Scout.

De oanpak fan it artikel is ticht by ús: by it oplossen fan ús problemen, brûke wy ek meastentiids in boskje PHP en Go, krije de foardielen fan beide talen en litte de iene net yn it foardiel fan 'e oare.

Genietsje!

Yn 'e lêste tsien jier hawwe wy applikaasjes makke foar bedriuwen út' e list Fortune 500, en foar bedriuwen mei in publyk fan net mear as 500 brûkers. Al dy tiid hawwe ús yngenieurs de backend ûntwikkele foaral yn PHP. Mar twa jier lyn hie wat in grutte ynfloed net allinich op 'e prestaasjes fan ús produkten, mar ek op har skaalberens - wy yntrodusearre Golang (Go) yn ús technologystack.

Hast fuortendaliks ûntdutsen wy dat Go ús tastiene om gruttere applikaasjes te bouwen mei maksimaal 40x prestaasjesferbetteringen. Dêrmei koene wy ​​ús besteande PHP-produkten útwreidzje, se ferbetterje troch de foardielen fan beide talen te kombinearjen.

Wy sille jo fertelle hoe't de kombinaasje fan Go en PHP helpt om echte ûntwikkelingsproblemen op te lossen en hoe't it is feroare yn in ark foar ús dat guon fan 'e problemen kin ferwiderje PHP stjerrende model.

Jo deistige PHP ûntwikkeling omjouwing

Foardat wy prate oer hoe't jo Go kinne brûke om it PHP-stjerrende model te doen herleven, litte wy ris nei jo standert PHP-ûntwikkelingsomjouwing sjen.

Yn 'e measte gefallen rinne jo jo applikaasje mei in kombinaasje fan' e nginx-webserver en de PHP-FPM-tsjinner. De eardere tsjinnet statyske bestannen en ferwiist spesifike oanfragen nei PHP-FPM, wylst PHP-FPM sels PHP-koade útfiert. Jo kinne miskien de minder populêre kombinaasje fan Apache en mod_php brûke. Mar hoewol it in bytsje oars wurket, binne de prinsipes itselde.

Litte wy ris sjen hoe't PHP-FPM applikaasjekoade útfiert. As in fersyk binnenkomt, initialisearret PHP-FPM in PHP-berneproses en jout de details fan it fersyk troch as diel fan syn steat (_GET, _POST, _SERVER, ensfh.).

De steat kin net wizigje by it útfieren fan PHP-skript, dus d'r is mar ien manier om in nije set ynfiergegevens te krijen: troch it prosesûnthâld te wiskjen en it opnij te initialisearjen.

Dit útfieringsmodel hat in protte foardielen. Jo hoege jo net te soargen te folle oer ûnthâld konsumpsje, alle prosessen binne folslein isolearre, en as ien fan harren "stjert", it sil automatysk opnij oanmakke en it sil gjin ynfloed op de rest fan de prosessen. Mar dizze oanpak hat ek neidielen dy't ferskine as jo besykje de applikaasje te skaaljen.

Neidielen en ineffisjinsjes fan in reguliere PHP-omjouwing

As jo ​​​​in profesjonele PHP-ûntwikkelder binne, dan wite jo wêr't jo in nij projekt moatte begjinne - mei de kar fan in ramt. It bestiet út ôfhinklikens ynjeksje biblioteken, ORMs, oersettingen en sjabloanen. En, fansels, alle brûkersynput kin maklik yn ien objekt pleatst wurde (Symfony / HttpFoundation of PSR-7). Frameworks binne cool!

Mar alles hat syn priis. Yn elk ramt op ûndernimmingsnivo, om in ienfâldich brûkersfersyk of tagong ta in database te ferwurkjen, moatte jo op syn minst tsientallen bestannen laden, ferskate klassen oanmeitsje en ferskate konfiguraasjes parse. Mar it slimste is dat jo nei it foltôgjen fan elke taak alles moatte weromsette en opnij begjinne: alle koade dy't jo krekt inisjearre wurde nutteloos, mei har help sille jo gjin oar fersyk mear ferwurkje. Fertel dit oan elke programmeur dy't skriuwt yn in oare taal, en jo sille ferbjustering op syn gesicht sjen.

PHP-yngenieurs hawwe jierrenlang socht nei manieren om dit probleem op te lossen, mei help fan tûke lazy-loading-techniken, mikroframeworks, optimisearre biblioteken, cache, ensfh. . (Opmerking fan 'e oersetter: dit probleem sil foar in part oplost wurde mei de komst fan foarlêze yn PHP 7.4)

Kin PHP mei Go mear dan ien fersyk oerlibje?

Jo kinne PHP-skripts skriuwe dy't langer libje as in pear minuten (oant oeren of dagen): bygelyks cron-taken, CSV-parsers, wachtrigebrekkers. Se wurkje allegear neffens itselde senario: se helje in taak op, fiere it út en wachtsje op de folgjende. De koade leit de hiele tiid yn it ûnthâld, en besparret kostbere millisekonden, om't d'r in protte ekstra stappen nedich binne om it ramt en de applikaasje te laden.

Mar it ûntwikkeljen fan lange libbene skripts is net maklik. Elke flater deadet it proses folslein, diagnoaze fan ûnthâldlekken is ferfelend, en F5-debuggen is net mear mooglik.

De situaasje is ferbettere mei de frijlitting fan PHP 7: in betroubere garbage collector is ferskynd, it is makliker wurden om flaters te behanneljen, en kernel-útwreidingen binne no lekbestindich. Wier, yngenieurs moatte noch altyd foarsichtich wêze mei ûnthâld en bewust wêze fan steatproblemen yn koade (is d'r in taal dy't dizze dingen negearje kin?). Noch, PHP 7 hat minder ferrassingen foar ús.

Is it mooglik om it model fan wurkjen mei lange libbene PHP-skripts te nimmen, it oan te passen oan mear triviale taken lykas it ferwurkjen fan HTTP-oanfragen, en dêrmei kwyt te reitsjen fan 'e needsaak om alles fanôf it begjin te laden mei elk fersyk?

Om dit probleem op te lossen, moasten wy earst in serverapplikaasje ymplementearje dy't HTTP-oanfragen koe akseptearje en se ien foar ien trochferwize nei de PHP-arbeider sûnder it elke kear te deadzjen.

Wy wisten dat wy in webserver skriuwe koene yn pure PHP (PHP-PM) of mei in C-útwreiding (Swoole). En hoewol elke metoade syn eigen fertsjinsten hat, pasten beide opsjes ús net - wy woenen wat mear. Wy hiene mear nedich dan allinich in webserver - wy ferwachte in oplossing te krijen dy't ús koe rêde fan 'e problemen ferbûn mei in "hurde start" yn PHP, dy't tagelyk maklik oanpast en útwreide wurde koe foar spesifike applikaasjes. Dat is, wy hawwe in applikaasjetsjinner nedich.

Kin Go hjirmei helpe? Wy wisten dat it koe om't de taal applikaasjes kompilearret yn inkele binaries; it is cross-platform; brûkt syn eigen, hiel elegant, parallel ferwurkjen model (samsyngong) en in bibleteek foar wurkjen mei HTTP; en úteinlik sille tûzenen iepenboarne bibleteken en yntegraasjes foar ús beskikber wêze.

De swierrichheden fan it kombinearjen fan twa programmeartalen

Earst wie it nedich om te bepalen hoe't twa of mear applikaasjes sille kommunisearje mei elkoar.

Bygelyks, it brûken fan poerbêst bibleteek Alex Palaestras, it wie mooglik om ûnthâld te dielen tusken PHP- en Go-prosessen (lykas mod_php yn Apache). Mar dizze bibleteek hat funksjes dy't it gebrûk beheine foar it oplossen fan ús probleem.

Wy besletten om in oare, mear mienskiplike oanpak te brûken: ynteraksje te bouwen tusken prosessen fia sockets / pipelines. Dizze oanpak hat bewiisd te wêzen betrouber yn 'e ôfrûne desennia en is goed optimalisearre op bestjoeringssysteemnivo.

Om te begjinnen hawwe wy in ienfâldich binêr protokol makke foar it útwikseljen fan gegevens tusken prosessen en it behanneljen fan oerdrachtflaters. Yn syn ienfâldichste foarm is dit soarte protokol gelyk oan netstring с fêste grutte pakket koptekst (yn ús gefal 17 bytes), dy't ynformaasje befettet oer it type pakket, har grutte en in binêre masker om de yntegriteit fan 'e gegevens te kontrolearjen.

Oan 'e PHP-kant hawwe wy brûkt pack funksje, en oan 'e Go-kant, de biblioteek kodearring / binêr.

It like ús dat ien protokol net genôch wie - en wy tafoege de mooglikheid om te skiljen net/rpc gean tsjinsten direkt fan PHP. Letter holp dit ús in protte yn ûntwikkeling, om't wy Go-biblioteken maklik yn PHP-applikaasjes kinne yntegrearje. It resultaat fan dit wurk is te sjen, bygelyks, yn ús oare iepen-boarne produkt Goridge.

Taken fersprieden oer meardere PHP-arbeiders

Nei it ymplementearjen fan it ynteraksjemeganisme, begûnen wy nei te tinken oer de meast effisjinte manier om taken oer te setten nei PHP-prosessen. As in taak oankomt, moat de applikaasjetsjinner in frije arbeider kieze om it út te fieren. As in arbeider/proses útgiet mei in flater of "stjert", reitsje wy it kwyt en meitsje in nij om it te ferfangen. En as de arbeider / proses mei súkses foltôge is, jouwe wy it werom nei it swimbad fan arbeiders dy't beskikber binne om taken út te fieren.

RoadRunner: PHP is net boud om te stjerren, of Golang ta de rêding

Om it swimbad fan aktive arbeiders op te slaan, brûkten wy buffered kanaal, Om ûnferwachte "deade" arbeiders út it swimbad te ferwiderjen, hawwe wy in meganisme tafoege foar it folgjen fan flaters en steaten fan arbeiders.

As gefolch hawwe wy in wurkjende PHP-tsjinner krigen dy't alle oanfragen presintearre yn binêre foarm kin ferwurkje.

Om ús applikaasje as webserver te begjinnen te wurkjen, moasten wy in betroubere PHP-standert kieze om alle ynkommende HTTP-oanfragen te fertsjintwurdigjen. Yn ús gefal, wy gewoan transformearje net/http fersyk fan Gean nei opmaak PSR-7sadat it kompatibel is mei de measte PHP-ramten dy't hjoed beskikber binne.

Om't PSR-7 wurdt beskôge as ûnferoarlik (guon soene sizze dat it technysk net is), moatte ûntwikkelders applikaasjes skriuwe dy't it fersyk yn prinsipe net as in globale entiteit behannelje. Dit past moai by it konsept fan lange libbene PHP-prosessen. Us definitive ymplemintaasje, dy't noch moat wurde neamd, seach der sa út:

RoadRunner: PHP is net boud om te stjerren, of Golang ta de rêding

Yntroduksje fan RoadRunner - hege prestaasjes PHP applikaasje tsjinner

Us earste testtaak wie in API-backend, dy't periodyk barst yn ûnfoarspelbere oanfragen (folle faker dan normaal). Hoewol't nginx yn 'e measte gefallen genôch wie, hawwe wy regelmjittich 502 flaters tsjinkaam, om't wy it systeem net fluch genôch balansearje koene foar de ferwachte ferheging fan lading.

Om dizze oplossing te ferfangen, hawwe wy begjin 2018 ús earste PHP/Go-applikaasjetsjinner ynset. En fuortendaliks krige in ongelooflijk effekt! Net allinich hawwe wy de 502-flater folslein kwytreitsje, mar wy koene it oantal tsjinners troch twa-tredde ferminderje, in protte jild en hoofdpijnpillen besparje foar yngenieurs en produktbehearders.

Tsjin it midden fan it jier hiene wy ​​ús oplossing ferbettere, publisearre op GitHub ûnder de MIT-lisinsje en neamden it roadrunner, sa beklamme syn ongelooflijke snelheid en effisjinsje.

Hoe RoadRunner jo ûntwikkelingsstapel kin ferbetterje

Applikaasje roadrunner tastien ús Middleware net/http oan 'e Go-kant te brûken om JWT-ferifikaasje út te fieren foardat it fersyk PHP berikt, en ek WebSockets te behanneljen en aggregearre steat wrâldwiid yn Prometheus.

Mei tank oan de ynboude RPC kinne jo de API fan elke Go-biblioteken foar PHP iepenje sûnder útwreidingswrappers te skriuwen. Noch wichtiger, mei RoadRunner kinne jo nije net-HTTP-tsjinners ynsette. Foarbylden omfetsje rinnende handlers yn PHP AWS Lambda, it meitsjen fan betroubere wachtrige breakers, en sels tafoegje gRPC oan ús applikaasjes.

Mei help fan de PHP- en Go-mienskippen hawwe wy de stabiliteit fan 'e oplossing ferbettere, tapassingsprestaasjes oant 40 kear yn guon tests ferbettere, ferbettere debuggen-ark, ymplementearre yntegraasje mei it Symfony-ramt, en tafoege stipe foar HTTPS, HTTP/2, plugins en PSR-17.

konklúzje

Guon minsken binne noch fongen yn it ferâldere begryp fan PHP as in trage, ûnhandiche taal allinich goed foar it skriuwen fan plugins foar WordPress. Dizze minsken kinne sels sizze dat PHP sa'n beheining hat: as de applikaasje grut genôch wurdt, moatte jo in mear "folere" taal kieze en de koadebasis opnij skriuwe oer in protte jierren.

Op dit alles wol ik antwurdzje: tink nochris. Wy leauwe dat allinich jo beheiningen ynstelle foar PHP. Jo kinne jo heule libben trochbringe fan de iene taal nei de oare oergong, besykje de perfekte wedstriid te finen foar jo behoeften, of jo kinne begjinne te tinken oan talen as ark. De sabeare gebreken fan in taal lykas PHP kinne eins de reden wêze foar har sukses. En as jo it kombinearje mei in oare taal lykas Go, dan sille jo folle krêftiger produkten meitsje dan as jo beheind wiene ta it brûken fan ien taal.

Nei't wy mei in protte Go en PHP wurke hawwe, kinne wy ​​​​sizze dat wy fan har hâlde. Wy binne net fan plan de iene foar de oare op te offerjen - krekt oarsom, wy sille sykje nei manieren om noch mear wearde te krijen fan dizze dûbele stapel.

UPD: wy ferwolkomje de makker fan RoadRunner en de mei-auteur fan it orizjinele artikel - Lachesis

Boarne: www.habr.com

Add a comment