RoadRunner: PHP ez da hiltzeko eraiki, edo Golang erreskatatzeko

RoadRunner: PHP ez da hiltzeko eraiki, edo Golang erreskatatzeko

Aupa Habr! Badoo-n aktibo gaude PHP errendimendua lantzen, hizkuntza honetan sistema nahiko handia dugulako eta errendimenduaren arazoa dirua aurrezteko arazoa baita. Duela hamar urte baino gehiago, PHP-FPM sortu genuen horretarako, hasieran PHPrako adabaki multzo bat zena, eta gero banaketa ofizialean sartu zen.

Azken urteotan, PHP-k aurrerapen handiak egin ditu: zabor-biltzailea hobetu da, egonkortasun-maila handitu da - gaur egun PHPn deabruak eta iraupen luzeko script-ak idatz ditzakezu arazorik gabe. Horri esker, Spiral Scout-ek harago joan zen: RoadRunner-ek, PHP-FPM ez bezala, ez du memoria garbitzen eskaeren artean, eta horrek errendimendu gehigarria ematen du (nahiz eta ikuspegi honek garapen-prozesua zaildu). Une honetan tresna honekin esperimentatzen ari gara, baina oraindik ez dugu emaitzarik partekatzeko. Haien zain egotea dibertigarriagoa izan dadin, Spiral Scout-en RoadRunner iragarkiaren itzulpena argitaratzen ari gara.

Artikuluaren planteamendua hurbil dago: gure arazoak konpontzerakoan, PHP eta Go pila bat ere erabiltzen ditugu gehienetan, bi hizkuntzen onurak lortuz eta bata bestearen alde utzi gabe.

Gozatu!

Azken hamar urteotan, zerrendako enpresentzako aplikazioak sortu ditugu Fortune 500, eta 500 erabiltzaile baino gehiagoko audientzia duten enpresentzat. Denbora honetan guztian, gure ingeniariak backend-a batez ere PHPn garatzen aritu dira. Baina duela bi urte, zerbaitek eragin handia izan zuen gure produktuen errendimenduan ez ezik, haien eskalagarritasunean ere - Golang (Go) sartu genuen gure teknologia pilan.

Ia berehala, Go-k aplikazio handiagoak eraikitzeko aukera eman zigula deskubritu genuen, 40 aldiz errendimendu hobekuntzarekin. Harekin, PHPn idatzitako lehendik zeuden produktuak hedatu ahal izan genituen, bi hizkuntzen abantailak konbinatuz hobetuz.

Go eta PHP-ren konbinazioak benetako garapen-arazoak konpontzen nola laguntzen duen kontatuko dizugu eta nola bihurtu den guretzat lotutako arazo batzuk ken ditzakeen tresna. PHP hiltze eredua.

Zure eguneroko PHP garapen-ingurunea

Joan PHP hiltze eredua berpizteko nola erabil dezakezun hitz egin aurretik, ikus dezagun zure PHP garapen-ingurune lehenetsiari.

Kasu gehienetan, zure aplikazioa exekutatzen duzu nginx web zerbitzariaren eta PHP-FPM zerbitzariaren konbinazioa erabiliz. Lehenengoak fitxategi estatikoak zerbitzatzen ditu eta eskaera zehatzak PHP-FPMra birbideratzen ditu, PHP-FPM-k berak PHP kodea exekutatzen duen bitartean. Baliteke Apache eta mod_php konbinazio ez hain ezaguna erabiltzea. Baina apur bat ezberdinean funtzionatzen duen arren, printzipioak berdinak dira.

Ikus dezagun PHP-FPM aplikazioaren kodea nola exekutatzen duen. Eskaera bat iristen denean, PHP-FPM-k haur PHP prozesua hasieratzen du eta eskaeraren xehetasunak bere egoeraren zati gisa pasatzen ditu (_GET, _POST, _SERVER, etab.).

Egoera ezin da aldatu PHP script exekuzioan zehar, beraz, sarrerako datu-multzo berri bat lortzeko modu bakarra dago: prozesuaren memoria garbitu eta berriro hasieratzea.

Exekuzio eredu honek abantaila asko ditu. Ez duzu memoria-kontsumoaz gehiegi kezkatu behar, prozesu guztiak erabat isolatuta daude, eta horietako bat "hiltzen" bada, automatikoki birsortuko da eta ez du eraginik izango gainerako prozesuetan. Baina ikuspegi honek aplikazioa eskalatzen saiatzean agertzen diren desabantailak ere baditu.

PHP ingurune arruntaren desabantailak eta eraginkortasun ezak

PHP-n garapen profesionalean ari bazara, badakizu non hasi proiektu berri bat - esparru bat aukeratuz. Mendekotasuna sartzeko liburutegiak, ORMak, itzulpenak eta txantiloiak ditu. Eta, jakina, erabiltzaileen sarrera guztiak objektu bakarrean jar daitezke (Symfony/HttpFoundation edo PSR-7). Markoak politak dira!

Baina denak badu bere prezioa. Enpresa-mailako edozein esparrutan, erabiltzaileen eskaera soil bat prozesatzeko edo datu-base batera sartzeko, gutxienez dozenaka fitxategi kargatu, klase ugari sortu eta hainbat konfigurazio analizatu beharko dituzu. Baina okerrena zera da, zeregin bakoitza amaitu ondoren dena berrezarri eta berriro hasi beharko duzula: hasi berri duzun kode guztia alferrikakoa bihurtzen da, bere laguntzarekin ez duzu beste eskaera gehiago prozesatuko. Esan hau beste edozein hizkuntzatan idazten duen edozein programatzaileri, eta harridura ikusiko duzu aurpegian.

PHP ingeniariek urteak daramatzate arazo hau konpontzeko moduak bilatzen, kargatzeko teknika burutsuak erabiliz, mikromarkoak, liburutegi optimizatuak, cachea, etab. Baina azkenean, aplikazio osoa berrezarri eta berriro hasi behar duzu, behin eta berriz. . (Itzultzailearen oharra: arazo hau partzialki konponduko da aurrez kargatu PHP 7.4n)

Go-rekin PHP eskaera bat baino gehiago iraun dezake?

Minutu batzuk baino gehiago iraungo duten PHP script-ak (orduak edo egunak arte) idazteko aukera dago: adibidez, cron zereginak, CSV analizatzaileak, ilarak busters. Guztiek agertoki berdinaren arabera funtzionatzen dute: zeregin bat berreskuratzen dute, exekutatu eta hurrengoaren zain. Kodea memorian dago, milisegundo preziatuak aurreztuz, markoa eta aplikazioa kargatzeko urrats gehigarri asko behar baitira.

Baina iraupen luzeko gidoiak garatzea ez da erraza. Edozein errorek prozesua erabat hiltzen du, memoria ihesak diagnostikatzea amorragarria da eta F5 arazketa ez da posible.

Egoera hobetu egin da PHP 7 kaleratzearekin: zabor-biltzaile fidagarri bat agertu da, akatsak kudeatzea errazagoa bihurtu da eta nukleoaren luzapenak ihesak dira. Egia da, oraindik ere ingeniariek kontuz ibili behar dute memoriarekin eta egoera-arazoen berri izan behar dute kodean (ba al dago gauza hauek bazter ditzakeen hizkuntzarik?). Hala ere, PHP 7k sorpresa gutxiago ditu gordeta.

Posible al da iraupen luzeko PHP scriptekin lan egiteko eredua hartzea, HTTP eskaerak prozesatzea bezalako zeregin hutsaletara egokitzea eta, horrela, eskaera bakoitzeko dena hutsetik kargatzeko beharra ezabatzea?

Arazo hau konpontzeko, lehenik HTTP eskaerak onar ditzakeen zerbitzari-aplikazio bat inplementatu behar genuen eta banan-banan helarazi behar genion PHP langileari aldi bakoitzean hil gabe.

Bagenekien web zerbitzari bat PHP hutsean (PHP-PM) edo C luzapena erabiliz (Swoole) idatzi genezakeela. Eta metodo bakoitzak bere merituak dituen arren, bi aukerak ez zitzaizkigun egokitu - zerbait gehiago nahi genuen. Web zerbitzari bat baino gehiago behar genuen: PHPn “hasiera gogorra”rekin lotutako arazoetatik salba gaitzakeen irtenbide bat lortzea espero genuen, eta aldi berean aplikazio zehatzetarako erraz egokitu eta zabaldu zitekeen. Hau da, aplikazio zerbitzari bat behar genuen.

Go-k lagundu al dezake honekin? Bagenekien zitekeela hizkuntzak aplikazioak bitar bakarrean biltzen dituelako; plataforma anitzekoa da; prozesatzeko eredu propioa, oso dotorea, paraleloa (aldiberekotasuna) eta HTTPrekin lan egiteko liburutegi bat erabiltzen du; eta azkenik, kode irekiko milaka liburutegi eta integrazio izango ditugu eskuragarri.

Bi programazio-lengoaia konbinatzeko zailtasunak

Lehenengo urratsa bi aplikazio edo gehiago nola komunikatuko ziren zehaztea izan zen.

Adibidez, erabiliz liburutegi bikaina Alex Palaestras, PHP eta Go prozesuen artean memoria partekatzea posible zen (Apache-n mod_php-en antzekoa). Baina liburutegi honek gure arazoa konpontzeko erabilera mugatzen duten ezaugarriak ditu.

Ikuspegi ezberdin eta ohikoagoa erabiltzea erabaki genuen: prozesuen arteko elkarrekintza eraikitzea socket / kanalizazioen bidez. Ikuspegi hau fidagarria dela frogatu da azken hamarkadetan eta ondo optimizatu da sistema eragilearen mailan.

Hasteko, prozesuen artean datuak trukatzeko eta transmisio-erroreak kudeatzeko protokolo bitar soil bat sortu dugu. Bere forma sinpleenean, protokolo mota hau antzekoa da sare-katea с tamaina finkoko paketeen goiburua (gure kasuan 17 byte), pakete motari, bere tamainari eta datuen osotasuna egiaztatzeko maskara bitar bat biltzen dituena.

Erabili genuen PHP aldean pakete funtzioa, eta Go aldean - liburutegi bat kodeketa/bitarra.

Protokolo bat nahikoa ez zela iruditu zitzaigun, eta deitzeko gaitasuna gehitu genuen net/rpc go zerbitzuak PHP-tik zuzenean. Gerora honek asko lagundu zigun garapenean, Go liburutegiak PHP aplikazioetan erraz integra genitzake eta. Lan horren emaitza, adibidez, gure kode irekiko beste produktuan ikus daiteke Goridge.

Zereginak PHP langile anitzetan banatzea

Interakzio-mekanismoa ezarri ondoren, zereginak PHP prozesuetara transferitzeko modurik eraginkorrena pentsatzen hasi ginen. Zeregin bat iristen denean, aplikazio zerbitzariak doako langile bat aukeratu behar du hura exekutatzeko. Langile/prozesu bat akatsen batekin irteten bada edo "hiltzen" bada, kendu egingo dugu eta ordezkatzeko beste bat sortuko dugu. Eta langilea/prozesua arrakastaz amaitu bada, zereginak egiteko dauden langileen multzora itzuliko dugu.

RoadRunner: PHP ez da hiltzeko eraiki, edo Golang erreskatatzeko

Erabili genuen langile aktiboen multzoa gordetzeko buffered kanala, ustekabean "hildako" langileak igerilekutik kentzeko, akatsak eta langileen egoerak jarraitzeko mekanismo bat gehitu dugu.

Ondorioz, funtzionatzen duen PHP zerbitzari bat lortu dugu forma bitar batean aurkezten diren eskaerak prozesatzeko gai dena.

Gure aplikazioak web zerbitzari gisa funtziona dezan, PHP estandar fidagarri bat aukeratu behar izan dugu sarrerako HTTP eskaerak irudikatzeko. Gure kasuan besterik ez dugu eraldatu net/http eskaera joan formatura PSR-7beraz, gaur egun dauden PHP esparru gehienekin bateragarria da.

PSR-7 aldaezina denez (batzuek teknikoki ez dela esango lukete), garatzaileek eskaera printzipioz entitate global gisa tratatzen ez duten aplikazioak idatzi behar dituzte. Hau ederki egokitzen da iraupen luzeko PHP prozesuen kontzeptuarekin. Gure azken inplementazioa, oraindik izendatzeke dagoena, honelakoa izan zen:

RoadRunner: PHP ez da hiltzeko eraiki, edo Golang erreskatatzeko

RoadRunner aurkezten - errendimendu handiko PHP aplikazio zerbitzaria

Gure lehen proba-zeregin API backend bat izan zen, aldian-aldian ezusteko eskaerak lehertzen dituena (ohi baino askoz maizago). Nahiz eta nginx nahikoa izan kasu gehienetan, aldizka 502 akats topatu genituen, ezin izan genuelako sistema nahikoa azkar orekatu espero zen karga handitzeko.

Irtenbide hau ordezkatzeko, gure lehen PHP/Go aplikazio zerbitzaria zabaldu genuen 2018 hasieran. Eta berehala efektu izugarria lortu zuen! 502 akatsa guztiz kendu ez ezik, zerbitzarien kopurua bi heren murriztu ahal izan dugu, diru asko eta buruko mina pilulak aurreztuz ingeniarientzat eta produktu-kudeatzaileentzat.

Urtearen erdialderako, gure irtenbidea hobetu genuen, GitHub-en argitaratu genuen MIT lizentziapean eta izena jarri genion. Roadrunner, horrela bere abiadura eta eraginkortasun izugarria azpimarratuz.

Nola hobetu dezake RoadRunner-ek zure garapen pila

Eskaera Roadrunner Go aldean Middleware net/http erabiltzeko aukera eman zigun JWT egiaztapena egiteko eskaera PHPra iritsi aurretik, baita WebSockets eta egoera globala Prometheus-en kudeatzeko ere.

RPC integratuari esker, PHPrako edozein Go liburutegiren APIa ireki dezakezu luzapen-bilgarririk idatzi gabe. Are garrantzitsuagoa dena, RoadRunner-ekin HTTP ez diren zerbitzari berriak zabaldu ditzakezu. Adibideen artean, PHP-n kudeatzaileak exekutatzen dira AWS Lambda, ilara-hausle fidagarriak sortuz, eta baita gehitzea ere gRPC gure aplikazioetara.

PHP eta Go komunitateen laguntzarekin, irtenbidearen egonkortasuna hobetu dugu, aplikazioen errendimendua 40 aldiz handitu dugu proba batzuetan, arazketa tresnak hobetu, Symfony markoarekin integrazioa ezarri eta HTTPS, HTTP/2rako laguntza gehitu dugu, pluginak eta PSR-17.

Ondorioa

Pertsona batzuk oraindik PHP-ren ikuspegi zaharkituan harrapatuta daude, hizkuntza motel eta astun gisa WordPress pluginak idazteko soilik ona den. Pertsona hauek PHP-k muga bat duela ere esan lezake: aplikazioa nahikoa handitzen denean, hizkuntza "helduagoa" bat aukeratu eta urte askotan pilatutako kode-oinarria berridatzi behar duzu.

Horri guztiari erantzun nahi diot: berriro pentsatu. Uste dugu zuk bakarrik ezarri dezakezula PHPrako murrizketarik. Bizitza osoa eman dezakezu hizkuntza batetik bestera jauzika, zure beharretara egokitzen dena bilatzen saiatzen, edo hizkuntzak tresna gisa pentsatzen has zaitezke. PHP bezalako hizkuntza baten gabeziak izan daitezke bere arrakastaren arrazoiak. Eta Go bezalako beste hizkuntza batekin konbinatzen baduzu, askoz produktu indartsuagoak sor ditzakezu hizkuntza bakarrera mugatuko bazina baino.

Go eta PHP askorekin lan egin ondoren, maite ditugula esan dezakegu. Ez dugu bata bestearen alde sakrifikatzeko asmorik; aitzitik, pila bikoitz honetatik are balio handiagoa lortzeko moduak bilatuko ditugu.

UPD: Ongietorria ematen diogu RoadRunner-en sortzaileari eta jatorrizko artikuluaren egilekideari - Lachesis

Iturria: www.habr.com

Gehitu iruzkin berria