RoadRunner: PHP ùn hè micca custruitu per mori, o Golang à a salvezza

RoadRunner: PHP ùn hè micca custruitu per mori, o Golang à a salvezza

Ehi Habr! Semu attivi in ​​Badoo travaglià nantu à u rendiment PHP, Siccomu avemu un sistema abbastanza grande in questa lingua è u prublema di rendiment hè un prublema di risparmiu di soldi. Più di deci anni fà, avemu creatu PHP-FPM per questu, chì prima era un set di patch per PHP, è dopu intrutu in a distribuzione ufficiale.

Nta l'ultimi anni, PHP hà fattu un grande prugressu: u cullettivu di basura hà migliuratu, u livellu di stabilità hè aumentatu - oghje pudete scrive daemons è scripts longu in PHP senza prublemi. Questu hà permessu à Spiral Scout di andà più in là: RoadRunner, à u cuntrariu di PHP-FPM, ùn pulisce micca a memoria trà e dumande, chì dà un guadagnu di prestazione supplementu (ancu se questu approcciu complica u prucessu di sviluppu). Attualmente sperimentamu stu strumentu, ma ùn avemu micca ancu risultati da sparte. Per fà aspittà per elli più divertente, publichemu a traduzzione di l'annunziu RoadRunner da Spiral Scout.

L'approcciu di l'articulu hè vicinu à noi: quandu risolve i nostri prublemi, avemu ancu aduprà più spessu una mansa di PHP è Go, ottenendu i benefici di e duie lingue è micca abbandunà una in favore di l'altru.

Liccà si!

In l'ultimi deci anni, avemu creatu applicazioni per cumpagnie da a lista Fortune 500, è per l'imprese cù un publicu di micca più di 500 utilizatori. Tuttu stu tempu, i nostri ingegneri anu sviluppatu u backend principalmente in PHP. Ma dui anni fà, qualcosa hà avutu un grande impattu micca solu in u rendiment di i nostri prudutti, ma ancu in a so scalabilità - avemu introduttu Golang (Go) in a nostra pila di tecnulugia.

Quasi subitu, avemu scupertu chì Go ci hà permessu di custruisce applicazioni più grandi cù megliurenze di rendiment finu à 40x. Cun ella, pudemu allargà i prudutti esistenti scritti in PHP, migliurenduli cumminendu i vantaghji di e duie lingue.

Vi diceremu cumu a cumminazzioni di Go è PHP aiuta à risolve i prublemi di sviluppu reale è cumu si hè diventatu un strumentu per noi chì pò sbarazza di alcuni di i prublemi assuciati cù mudellu PHP mori.

U vostru ambiente di sviluppu PHP ogni ghjornu

Prima di parlà di cumu pudete aduprà Andate à rinviviscia u mudellu di PHP mori, fighjemu un ochju à u vostru ambiente di sviluppu PHP predeterminatu.

In a maiò parte di i casi, eseguite a vostra applicazione utilizendu una cumminazione di u servitore web nginx è u servore PHP-FPM. U primu serve i fugliali statichi è redirige e richieste specifiche à PHP-FPM, mentre chì PHP-FPM stessu eseguisce codice PHP. Puderete aduprà a cumminazzioni menu populari di Apache è mod_php. Ma ancu s'ellu travaglia un pocu sfarente, i principii sò listessi.

Fighjemu un ochju à cumu PHP-FPM eseguisce u codice di l'applicazione. Quandu una dumanda vene, PHP-FPM inizializza un prucessu di u zitellu PHP è passa i dettagli di a dumanda cum'è parte di u so statu (_GET, _POST, _SERVER, etc.).

U statu ùn pò micca cambià durante l'esekzione di u script PHP, cusì ci hè solu un modu per uttene un novu settore di dati di input: sguassendu a memoria di prucessu è re-inizializà.

Stu mudellu di esecutivu hà assai vantaghji. Ùn ci vole micca troppu preoccupatu di u cunsumu di memoria, tutti i prucessi sò cumplettamente isolati, è se unu di elli "morte", serà automaticamente ricreatu è ùn affetterà micca u restu di i prucessi. Ma questu approcciu hà ancu svantaghji chì appariscenu quandu pruvate di scala l'applicazione.

Svantaghji è Inefficienze di un Ambiente PHP Regular

Sè vo site un sviluppatore PHP prufessiunale, allora sapete induve inizià un novu prughjettu - cù a scelta di un framework. Hè custituitu di biblioteche di iniezione di dipendenza, ORM, traduzzioni è mudelli. E, sicuru, tutti l'input di l'utilizatori ponu esse cunvenuti in un oggettu (Symfony/HttpFoundation o PSR-7). I quadri sò cool!

Ma tuttu hà u so prezzu. In ogni quadru di u livellu di l'impresa, per processà una semplice dumanda d'utilizatore o accessu à una basa di dati, duverete carricà almenu decine di schedari, creà numerosi classi è analizà parechje cunfigurazioni. Ma u peghju hè chì dopu à compie ogni compitu, avete bisognu di resettate tuttu è ricominciate: tuttu u codice chì avete appena iniziatu diventa inutile, cù u so aiutu ùn avete più processà una altra dumanda. Dite questu à qualsiasi programatore chì scrive in una altra lingua, è vi vede u cunfusu nantu à a so faccia.

L'ingegneri PHP anu cercatu modi per risolve stu prublema per anni, utilizendu tecniche intelligenti di carica lazy, microframeworks, biblioteche ottimisate, cache, etc. Ma à a fine, avete sempre resettatu l'appiecazione sana è ricuminciate, una volta è una volta. (Nota di u traduttore: stu prublema serà risoltu parzialmente cù l'avventu di precaricà in PHP 7.4)

Pò PHP cù Go sopravvive più di una dumanda?

Hè pussibule scrive script PHP chì campanu più di pochi minuti (finu à ore o ghjorni): per esempiu, cron tasks, CSV parsers, queue breakers. Tutti travaglianu secondu u listessu scenariu: ricuperanu un compitu, eseguite, è aspettanu u prossimu. U codice reside in memoria tuttu u tempu, salvendu preziosi millisecondi postu chì ci sò parechji passi supplementari necessarii per carricà u quadru è l'applicazione.

Ma u sviluppu di scrittura di longa vita ùn hè micca faciule. Qualchese errore uccide cumplettamente u prucessu, diagnosticà e fughe di memoria hè infuriante, è a debugging F5 ùn hè più pussibule.

A situazione hà migliuratu cù a liberazione di PHP 7: un cullettore di basura affidabile hè apparsu, hè diventatu più faciule per trattà l'errori, è l'estensioni di kernel sò avà a prova di fuga. True, l'ingegneri anu sempre bisognu à esse attenti à a memoria è esse cuscenti di i prublemi statali in codice (ci hè una lingua chì pò ignurà queste cose?). Eppuru, PHP 7 hà menu sorprese per noi.

Hè pussibule di piglià u mudellu di travaglià cù script PHP longu, adattà à i travaglii più triviali cum'è l'elaborazione di e dumande HTTP, è cusì sguassate di a necessità di carricà tuttu da zero cù ogni dumanda?

Per risolve stu prublema, avemu prima bisognu di implementà una applicazione di u servitore chì puderia accettà e dumande HTTP è redirige una per una à u travagliu PHP senza tumbà ogni volta.

Sapemu chì pudemu scrive un servitore web in PHP puru (PHP-PM) o usendu una estensione C (Swoole). E ancu chì ogni metudu hà i so meriti, e duie opzioni ùn ci cunvene micca - vulemu qualcosa di più. Avemu bisognu di più cà un servitore web - avemu aspittatu di ottene una suluzione chì puderia salvà da i prublemi assuciati cù un "iniziu duru" in PHP, chì à u stessu tempu puderia esse facilmente adattatu è allargatu per applicazioni specifiche. Questu hè, avemu bisognu di un servitore d'applicazione.

Pudete Go aiutà cù questu? Sapemu chì puderia perchè a lingua compila l'applicazioni in binari unichi; hè cross-piattaforma; usa u so propiu, assai eleganti, mudellu di trasfurmazioni parallele (concurrency) è una biblioteca per travaglià cù HTTP; è infine, migghiara di biblioteche open-source è integrazioni seranu dispunibuli per noi.

E difficultà di cumminà dui linguaggi di prugrammazione

Prima di tuttu, era necessariu di determinà cumu duie o più applicazioni cumunicanu cù l'altri.

Per esempiu, usendu eccellente biblioteca Alex Palaestras, era pussibule di sparte memoria trà i prucessi PHP è Go (simile à mod_php in Apache). Ma sta biblioteca hà caratteristiche chì limitanu u so usu per risolve u nostru prublema.

Avemu decisu d'utilizà un approcciu sfarente, più cumuni: per custruisce l'interazzione trà i prucessi attraversu sockets / pipelines. Stu approcciu hà dimustratu chì hè affidabile in l'ultimi decennii è hè statu bè ottimizatu à u livellu di u sistema operatore.

Per principià, avemu creatu un protokollu binariu simplice per u scambiu di dati trà i prucessi è a gestione di l'errori di trasmissione. In a so forma più simplice, stu tipu di protokollu hè simili à netstring с intestazione di pacchettu di dimensione fissa (in u nostru casu 17 bytes), chì cuntene infurmazione nantu à u tipu di pacchettu, a so dimensione è una maschera binaria per verificà l'integrità di e dati.

Da u latu PHP avemu usatu funzione di pacchettu, è da u latu Go, a biblioteca codificazione / binariu.

Ci pareva chì un protokollu ùn era micca abbastanza - è avemu aghjustatu a capacità di chjamà net/rpc go servizii direttamente da PHP. In seguitu, questu ci hà aiutatu assai in u sviluppu, postu chì pudemu facilmente integrà e librerie Go in applicazioni PHP. U risultatu di stu travagliu pò esse vistu, per esempiu, in u nostru altru pruduttu open-source Goridge.

Distribuzione di i travaglii in parechji travagliadori PHP

Dopu avè implementatu u mecanismu d'interazzione, avemu principiatu à pensà à a manera più efficaci di trasfiriri i travaglii à i prucessi PHP. Quandu un compitu ghjunghje, u servitore di l'applicazione deve sceglie un travagliadore liberu per eseguisce. Se un travagliadore / prucessu esce cù un errore o "morte", sguassemu è creamu un novu per rimpiazzà. È se u travagliu / prucessu hè cumpletu cù successu, u turnemu à u gruppu di travagliadori dispunibuli per eseguisce i travaglii.

RoadRunner: PHP ùn hè micca custruitu per mori, o Golang à a salvezza

Per almacenà a piscina di i travagliadori attivi, avemu usatu canale buffered, per caccià i travagliadori "morti" imprevisu da a piscina, avemu aghjustatu un mecanismu per seguità l'errori è i stati di i travagliadori.

In u risultatu, avemu un servitore PHP chì funziona capace di processà ogni dumanda presentata in forma binaria.

Per chì a nostra applicazione cumencia à travaglià cum'è un servitore web, avemu avutu a sceglie un standard PHP affidabile per rapprisintà ogni dumanda HTTP entrante. In u nostru casu, avemu solu trasfurmà net/http dumanda da Vai à furmatu PSR-7cusì chì hè cumpatibile cù a maiò parte di i frameworks PHP dispunibili oghje.

Perchè PSR-7 hè cunsideratu immutable (alcuni dicenu tecnicamente chì ùn hè micca), i sviluppatori anu da scrive applicazioni chì ùn trattanu micca a dumanda cum'è una entità globale in principiu. Questu si mette bè cù u cuncettu di prucessi PHP longu. A nostra implementazione finale, chì ùn hà ancu esse chjamatu, pareva cusì:

RoadRunner: PHP ùn hè micca custruitu per mori, o Golang à a salvezza

Presentazione di RoadRunner - Servitore d'applicazioni PHP di altu rendiment

U nostru primu compitu di prova era un backend API, chì periodicamente scoppia in modu imprevisible (assai più spessu di u solitu). Ancu nginx era abbastanza in a maiò parte di i casi, avemu regularmente scontru errori 502 perchè ùn pudemu micca equilibrà u sistema abbastanza rapidamente per l'aumentu previstu di carica.

Per rimpiazzà sta suluzione, avemu implementatu u nostru primu servitore d'applicazione PHP/Go in principiu di 2018. È subitu hà avutu un effettu incredibile! Ùn avemu micca solu sbarazzatu di l'errore 502 cumplitamenti, ma avemu statu capaci di riduce u numeru di servitori da dui terzi, salvendu assai soldi è pillole di mal di testa per l'ingegneri è i gestori di produttu.

À a mità di l'annu, avemu migliuratu a nostra suluzione, publicata in GitHub sottu a licenza MIT è chjamatu. roadrunner, enfatizendu cusì a so incredibile rapidità è efficienza.

Cumu RoadRunner pò migliurà a vostra pila di sviluppu

Applicazione roadrunner ci hà permessu di utilizà Middleware net/http in u latu Go per fà a verificazione JWT prima chì a dumanda ghjunghje à PHP, è ancu di gestisce WebSockets è aggregate state globally in Prometheus.

Grazie à u RPC integratu, pudete apre l'API di qualsiasi librerie Go per PHP senza scrive wrappers di estensione. A più impurtante, cù RoadRunner pudete implementà novi servitori non HTTP. L'esempii includenu i gestori in esecuzione in PHP AWS Lambda, creendu interruttori di fila affidabili, è ancu aghjunghje gRPC à e nostre applicazioni.

Cù l'aiutu di e cumunità PHP è Go, avemu migliuratu a stabilità di a suluzione, hà aumentatu u rendiment di l'applicazioni finu à 40 volte in certi testi, l'arnesi di debugging megliu, implementatu l'integrazione cù u framework Symfony, è aghjustatu supportu per HTTPS, HTTP/2, plugins, è PSR-17.

cunchiusioni

Certi pirsuni sò sempre catturati in a nozione antica di PHP cum'è una lingua lenta è ingrata solu bona per scrive plugins per WordPress. Queste persone puderanu ancu dì chì PHP hà una tale limitazione: quandu l'applicazione diventa abbastanza grande, avete da sceglie una lingua più "matura" è riscrive a basa di codice accumulata in parechji anni.

À tuttu questu vogliu risponde : pensate dinò. Cridemu chì solu avete stabilitu qualsiasi restrizioni per PHP. Pudete passà tutta a vostra vita in transizione da una lingua à l'altru, circate di truvà a partita perfetta per i vostri bisogni, o pudete cumincià à pensà à e lingue cum'è strumenti. I supposti difetti di una lingua cum'è PHP pò esse veramente u mutivu di u so successu. È s'ellu si combina cù una altra lingua cum'è Go, allora creerete prudutti assai più putenti chè s'è vo site limitatu à aduprà una lingua.

Dopu avè travagliatu cù una mansa di Go è PHP, pudemu dì chì l'amiamo. Ùn avemu micca pensatu à sacrificà unu per l'altru - à u cuntrariu, cercheremu modi per ottene ancu più valore da sta pila duale.

UPD: accogliamu u creatore di RoadRunner è u coautore di l'articulu originale - Lachesis

Source: www.habr.com

Add a comment