RoadRunner: PHP er ekki byggt til að deyja, eða Golang til bjargar

RoadRunner: PHP er ekki byggt til að deyja, eða Golang til bjargar

Hæ Habr! Við erum virk hjá Badoo vinna að PHP frammistöðu, þar sem við erum með nokkuð stórt kerfi á þessu máli og afkomumálið er sparnaðarmál. Fyrir meira en tíu árum bjuggum við til PHP-FPM fyrir þetta, sem í fyrstu var sett af plástra fyrir PHP og fór síðar í opinbera dreifingu.

Undanfarin ár hefur PHP tekið miklum framförum: sorphirðarinn hefur batnað, stöðugleikastigið hefur aukist - í dag er hægt að skrifa púka og langlífa forskriftir í PHP án vandræða. Þetta gerði Spiral Scout kleift að ganga lengra: RoadRunner, ólíkt PHP-FPM, hreinsar ekki upp minni á milli beiðna, sem gefur aukinn árangur (þó að þessi nálgun flæki þróunarferlið). Við erum núna að gera tilraunir með þetta tól, en við höfum engar niðurstöður til að deila. Til að gera bið eftir þeim skemmtilegri, við birtum þýðinguna á RoadRunner tilkynningunni frá Spiral Scout.

Nálgunin úr greininni er okkur nærri: þegar við leysum vandamál okkar notum við líka oftast fullt af PHP og Go, fáum ávinninginn af báðum tungumálum og yfirgefum ekki annað í þágu hins.

Njóttu!

Á síðustu tíu árum höfum við búið til umsóknir fyrir fyrirtæki af listanum Fortune 500, og fyrir fyrirtæki með áhorfendur sem eru ekki fleiri en 500 notendur. Allan þennan tíma hafa verkfræðingar okkar verið að þróa bakendann aðallega í PHP. En fyrir tveimur árum síðan hafði eitthvað mikil áhrif, ekki aðeins á frammistöðu vara okkar, heldur einnig á sveigjanleika þeirra - við kynntum Golang (Go) í tæknistafla okkar.

Næstum strax komumst við að því að Go gerði okkur kleift að smíða stærri forrit með allt að 40x frammistöðubótum. Með því gátum við framlengt núverandi PHP vörur okkar, bætt þær með því að sameina kosti beggja tungumálanna.

Við munum segja þér hvernig samsetning Go og PHP hjálpar til við að leysa raunveruleg þróunarvandamál og hvernig það hefur breyst í tól fyrir okkur sem getur losað okkur við sum vandamálin sem tengjast PHP deyjandi líkan.

Daglegt PHP þróunarumhverfi þitt

Áður en við tölum um hvernig þú getur notað Go til að endurvekja PHP deyjandi líkanið skulum við skoða sjálfgefna PHP þróunarumhverfið þitt.

Í flestum tilfellum keyrir þú forritið þitt með því að nota blöndu af nginx vefþjóninum og PHP-FPM þjóninum. Hið fyrra þjónar kyrrstæðum skrám og vísar tilteknum beiðnum til PHP-FPM, en PHP-FPM sjálft keyrir PHP kóða. Þú gætir verið að nota minna vinsælu samsetninguna af Apache og mod_php. En þó það virki aðeins öðruvísi, þá eru meginreglurnar þær sömu.

Við skulum skoða hvernig PHP-FPM keyrir forritakóða. Þegar beiðni kemur inn frumstillir PHP-FPM PHP undirferli og sendir upplýsingar um beiðnina sem hluta af ástandi hennar (_GET, _POST, _SERVER, osfrv.).

Staðan getur ekki breyst meðan PHP forskrift er keyrð, þannig að það er aðeins ein leið til að fá nýtt sett af inntaksgögnum: með því að hreinsa vinnsluminnið og frumstilla það aftur.

Þetta framkvæmdarlíkan hefur marga kosti. Þú þarft ekki að hafa miklar áhyggjur af minnisnotkun, öll ferli eru algjörlega einangruð og ef eitt þeirra „deyr“ verður það sjálfkrafa endurskapað og það hefur ekki áhrif á restina af ferlunum. En þessi nálgun hefur einnig ókosti sem koma fram þegar reynt er að skala forritið.

Ókostir og óhagkvæmni við venjulegt PHP umhverfi

Ef þú ert faglegur PHP verktaki, þá veistu hvar á að byrja nýtt verkefni - með vali á ramma. Það samanstendur af innspýtingasöfnum fyrir ósjálfstæði, ORM, þýðingar og sniðmát. Og auðvitað er hægt að setja allt notendainntak á þægilegan hátt í einn hlut (Symfony/HttpFoundation eða PSR-7). Rammar eru flottir!

En allt hefur sitt verð. Í hvaða ramma sem er á fyrirtækisstigi, til að vinna úr einfaldri notendabeiðni eða aðgang að gagnagrunni, verður þú að hlaða að minnsta kosti tugum skráa, búa til fjölda flokka og flokka nokkrar stillingar. En það versta er að eftir að hafa lokið hverju verkefni þarftu að endurstilla allt og byrja upp á nýtt: allur kóðinn sem þú varst að byrja á verður gagnslaus, með hjálp hans muntu ekki lengur vinna úr annarri beiðni. Segðu þetta hverjum forritara sem skrifar á einhverju öðru tungumáli og þú munt sjá rugl í andliti hans.

PHP verkfræðingar hafa verið að leita leiða til að leysa þetta vandamál í mörg ár með því að nota snjalla lata hleðslutækni, örramma, fínstillt bókasöfn, skyndiminni osfrv. En á endanum þarftu samt að endurstilla allt forritið og byrja upp á nýtt, aftur og aftur. (Athugasemd þýðanda: þetta vandamál verður að hluta leyst með tilkomu Forhlaða í PHP 7.4)

Getur PHP með Go lifað af fleiri en einni beiðni?

Það er hægt að skrifa PHP forskriftir sem lifa lengur en í nokkrar mínútur (allt að klukkustundum eða dögum): til dæmis cron verkefni, CSV þátta, biðröð. Þeir vinna allir samkvæmt sömu atburðarás: þeir sækja verkefni, framkvæma það og bíða eftir því næsta. Kóðinn er alltaf í minni og sparar dýrmætar millisekúndur þar sem það eru mörg viðbótarskref sem þarf til að hlaða rammanum og forritinu.

En það er ekki auðvelt að þróa langlífa handrit. Sérhver villa drepur ferlið algjörlega, að greina minnisleka er pirrandi og F5 kembiforrit er ekki lengur möguleg.

Ástandið hefur batnað með útgáfu PHP 7: áreiðanlegur sorphirðumaður hefur birst, það hefur orðið auðveldara að meðhöndla villur og kjarnaviðbætur eru nú lekaheldar. Að vísu þurfa verkfræðingar samt að vera varkárir með minni og vera meðvitaðir um ástandsvandamál í kóða (er til tungumál sem getur hunsað þessa hluti?). Samt sem áður hefur PHP 7 færri óvæntar uppákomur fyrir okkur.

Er hægt að taka fyrirmyndina að vinna með langlífa PHP forskriftir, laga það að léttvægari verkefnum eins og að vinna úr HTTP beiðnum og losna þar með við þörfina á að hlaða öllu frá grunni við hverja beiðni?

Til að leysa þetta vandamál þurftum við fyrst að innleiða netþjónaforrit sem gat samþykkt HTTP beiðnir og vísað þeim ein af annarri til PHP starfsmannsins án þess að drepa það í hvert skipti.

Við vissum að við gætum skrifað vefþjón í hreinu PHP (PHP-PM) eða með C viðbót (Swoole). Og þó að hver aðferð hafi sína kosti, hentaði báðir valkostir okkur ekki - við vildum eitthvað meira. Okkur vantaði meira en bara netþjón - við bjuggumst við að fá lausn sem gæti bjargað okkur frá vandamálum tengdum „harðri byrjun“ í PHP, sem á sama tíma var auðvelt að aðlaga og stækka fyrir ákveðin forrit. Það er, okkur vantaði forritaþjón.

Getur Go hjálpað með þetta? Við vissum að það gæti vegna þess að tungumálið setur saman forrit í stakar tvíþættir; það er þvert á vettvang; notar sitt eigið, mjög glæsilega, samhliða vinnslulíkan (samhliða) og bókasafn til að vinna með HTTP; og að lokum munu þúsundir opins bókasöfna og samþættinga verða okkur tiltækar.

Erfiðleikarnir við að sameina tvö forritunarmál

Fyrst af öllu var nauðsynlegt að ákvarða hvernig tvö eða fleiri forrit munu hafa samskipti sín á milli.

Til dæmis að nota frábært bókasafn Alex Palaestras, það var hægt að deila minni milli PHP og Go ferla (svipað og mod_php í Apache). En þetta bókasafn hefur eiginleika sem takmarka notkun þess til að leysa vandamál okkar.

Við ákváðum að nota aðra, algengari nálgun: að byggja upp samspil milli ferla í gegnum innstungur / leiðslur. Þessi nálgun hefur reynst áreiðanleg undanfarna áratugi og hefur verið vel fínstillt á stýrikerfisstigi.

Til að byrja með bjuggum við til einfalda tvíundarsamskiptareglur til að skiptast á gögnum á milli ferla og meðhöndla sendingarvillur. Í sinni einföldustu mynd er þessi tegund af samskiptareglum svipuð netstrengur с pakkahaus í föstri stærð (í okkar tilfelli 17 bæti), sem inniheldur upplýsingar um tegund pakka, stærð hans og tvíundargrímu til að athuga heilleika gagnanna.

Á PHP hliðinni sem við notuðum pakkaaðgerð, og á Go hlið, bókasafnið kóðun/tvíundir.

Okkur virtist sem ein siðareglur væri ekki nóg - og við bættum við möguleikanum á að hringja net/rpc go þjónustu beint frá PHP. Síðar hjálpaði þetta okkur mikið í þróuninni, þar sem við gátum auðveldlega samþætt Go bókasöfn í PHP forrit. Afrakstur þessarar vinnu má til dæmis sjá í annarri opnum hugbúnaði okkar Goridge.

Að dreifa verkefnum á marga PHP starfsmenn

Eftir að hafa innleitt víxlverkunarkerfið fórum við að hugsa um skilvirkustu leiðina til að flytja verkefni yfir í PHP ferla. Þegar verkefni kemur verður forritaþjónninn að velja ókeypis starfsmann til að framkvæma það. Ef starfsmaður/ferli hættir með villu eða „deyr“ losnum við við það og búum til nýjan í staðinn. Og ef starfsmaðurinn/ferlið hefur lokið með góðum árangri, skilum við því aftur í hóp starfsmanna sem eru tiltækir til að framkvæma verkefni.

RoadRunner: PHP er ekki byggt til að deyja, eða Golang til bjargar

Til að geyma laug virkra starfsmanna notuðum við biðminni rás, til að fjarlægja óvænt „dauða“ starfsmenn úr lauginni, bættum við við kerfi til að rekja villur og ástand starfsmanna.

Fyrir vikið fengum við virkan PHP netþjón sem er fær um að vinna úr öllum beiðnum sem settar eru fram í tvöfaldri mynd.

Til þess að forritið okkar gæti byrjað að vinna sem vefþjónn, urðum við að velja áreiðanlegan PHP staðal til að tákna allar innkomnar HTTP beiðnir. Í okkar tilfelli, við bara breyta net/http beiðni frá Fara í snið PSR-7þannig að það er samhæft við flest PHP ramma sem til eru í dag.

Vegna þess að PSR-7 er talið óbreytanlegt (sumir myndu segja að tæknilega sé það ekki), verða verktaki að skrifa forrit sem meðhöndla ekki beiðnina sem alþjóðlega heild í grundvallaratriðum. Þetta passar vel við hugmyndina um langlífa PHP ferla. Endanleg útfærsla okkar, sem enn hefur ekki verið nefnd, leit svona út:

RoadRunner: PHP er ekki byggt til að deyja, eða Golang til bjargar

Við kynnum RoadRunner - hágæða PHP forritaþjónn

Fyrsta prófunarverkefnið okkar var API bakendi, sem reglulega springur í ófyrirsjáanlegum beiðnum (mun oftar en venjulega). Þrátt fyrir að nginx væri nægjanlegt í flestum tilfellum, lentum við reglulega í 502 villum vegna þess að við gátum ekki jafnvægið kerfið nógu hratt fyrir væntanlega aukningu á álagi.

Til að skipta um þessa lausn settum við upp fyrsta PHP/Go forritaþjóninn okkar snemma árs 2018. Og fékk strax ótrúleg áhrif! Ekki nóg með að við losnuðum alveg við 502 villuna heldur gátum við fækkað netþjónum um tvo þriðju og sparað mikla peninga og höfuðverkjatöflur fyrir verkfræðinga og vörustjóra.

Um mitt ár vorum við búin að endurbæta lausnina okkar, birta hana á GitHub undir MIT leyfinu og nefna hana Roadrunner, og leggur þannig áherslu á ótrúlegan hraða og skilvirkni.

Hvernig RoadRunner getur bætt þróunarstafla þinn

Umsókn Roadrunner leyfði okkur að nota Middleware net/http á Go-hliðinni til að framkvæma JWT sannprófun áður en beiðnin nær til PHP, sem og meðhöndla WebSockets og uppsafnað ástand á heimsvísu í Prometheus.

Þökk sé innbyggðu RPC geturðu opnað API hvaða Go bókasöfn sem er fyrir PHP án þess að skrifa framlengingarumbúðir. Meira um vert, með RoadRunner geturðu sent inn nýja netþjóna sem ekki eru HTTP. Sem dæmi má nefna að keyra meðhöndlarar í PHP AWS Lambda, búa til áreiðanlega biðröð, og jafnvel bæta við gRPC við umsóknir okkar.

Með hjálp PHP og Go samfélagsins bættum við stöðugleika lausnarinnar, bættum afköst forrita allt að 40 sinnum í sumum prófum, bættum villuleitarverkfæri, innleiddum samþættingu við Symfony ramma og bættum við stuðningi við HTTPS, HTTP/2, viðbætur og PSR-17.

Ályktun

Sumir eru enn fastir í úreltri hugmynd um PHP sem hægt, ómeðhöndlað tungumál sem er aðeins gott til að skrifa viðbætur fyrir WordPress. Þetta fólk gæti jafnvel sagt að PHP hafi slíkar takmarkanir: þegar forritið verður nógu stórt verðurðu að velja „þroskaðra“ tungumál og endurskrifa kóðagrunninn sem safnast hefur upp í mörg ár.

Við öllu þessu vil ég svara: hugsaðu aftur. Við teljum að aðeins þú setur einhverjar takmarkanir fyrir PHP. Þú getur eytt öllu lífi þínu í að skipta frá einu tungumáli til annars, að reyna að finna hið fullkomna samsvörun fyrir þarfir þínar, eða þú getur byrjað að hugsa um tungumál sem verkfæri. Meintir gallar tungumáls eins og PHP geta í raun verið ástæðan fyrir velgengni þess. Og ef þú sameinar það með öðru tungumáli eins og Go, þá muntu búa til miklu öflugri vörur en ef þú værir takmarkaður við að nota eitt tungumál.

Eftir að hafa unnið með fullt af Go og PHP getum við sagt að við elskum þau. Við ætlum ekki að fórna einu fyrir annað - þvert á móti munum við leita leiða til að fá enn meira verðmæti úr þessum tvöfalda stafla.

UPD: við fögnum skapara RoadRunner og meðhöfundi upprunalegu greinarinnar - Lachesis

Heimild: www.habr.com

Bæta við athugasemd