
Tere, Habr! Me Badoo-s töötame aktiivselt , kuna meil on sellel keelel piisavalt suur sĂŒsteem ja jĂ”udluse kĂŒsimus on rahakĂŒsimus. Ăle kĂŒmne aasta tagasi lĂ”ime selleks PHP-FPM-i, mis algselt oli PHP jaoks mĂ”eldud plaastrite kogum ja hiljem sai ametlikku vĂ€ljastusse.
Viimastel aastatel on PHP palju edenenud: prĂŒgikoristus on paranenud, stabiilsus on kasvanud - tĂ€na saab PHP-s ilma suuremate probleemideta kirjutada deemonite ja pikaajalisi skripte. See vĂ”imaldas Spiral Scoutil edasi liikuda: RoadRunner, erinevalt PHP-FPM-ist, ei puhasta mĂ€lu pĂ€ringute vahel, mis annab lisahĂŒve jĂ”udluses (kuigi see lĂ€henemine muudab arendusprotsessi keerulisemaks). Me katsetame praegu seda tööriista, kuid me ei ole veel tulemusi, mida jagada. Ootamise lĂ”busamaks muutmiseks, avalikustame Spiral Scouti RoadRunneri esitlusest tĂ”lgitud versiooni.
Artiklis esitatud lĂ€henemine on meile lĂ€hedane: oma probleemide lahendamisel kasutame me samuti enamasti PHP ja Go kombinatsiooni, saavutades kasu mĂ”lemast keelest, loobumata ĂŒhest teise kasuks.
Naudi!
Viimase kĂŒmne aasta jooksul oleme loonud rakendusi nii Fortune 500 nimekirjas olevatele ettevĂ”tetele , kui ka ettevĂ”tetele, mille auditoorium ei ĂŒleta 500 kasutajat. Kogu selle aja on meie insenerid toetanud peamiselt PHP taustapinda. Kuid kaks aastat tagasi mĂ”jutas miski mĂ€rkimisvÀÀrselt mitte ainult meie toodete jĂ”udlust, vaid ka nende skaleeritavust - tutvustasime Golangi (Go) meie tehnoloogilisse virna.
Peaaegu kohe avastasime, et Go vÔimaldab meil luua suuremaid rakendusi, suurendades jÔudlust kuni 40 korda. Selle abil saime laiendada olemasolevaid PHP-s kirjutatud tooteid, parandades neid, kasutades mÔlema keele eeliseid.
Me rÀÀgime sellest, kuidas Go ja PHP kombinatsioon aitab lahendada tegelikke arenduse vÀljakutseid ja kuidas sellest on saanud meie tööriist, mis suudab vÀhendada PHP-ga seotud probleeme, mis on seotud .
Teie igapÀevane PHP arenduskeskkond
Enne kui rÀÀgime, kuidas Go abil on vÔimalik elustada PHP 'suretamise' mudelit, vaatame teie standardset PHP arenduskeskkonda.
Enamikul juhtudel kÀivitate rakenduse koos veebiserveri nginx ja PHP-FPM serveriga. Esimene teenindab staatilisi faile ja suunab PHP-FPM-ile spetsiifilisi pÀringuid, samas kui PHP-FPM kÀivitab PHP-koodi. VÔib-olla kasutate vÀhem populaarset kombinatsiooni Apache'ist ja mod_php'ist. Kuigi see töötab veidi teisiti, on pÔhimÔtted samad.
Vaadakem, kuidas PHP-FPM rakenduse koodi kĂ€ivitab. Kui saabub pĂ€ring, kĂ€ivitab PHP-FPM alamsĂŒsteemi PHP-protsessi ja edastab pĂ€ringu detailid osana selle olekust (_GET, _POST, _SERVER jne).
Olek ei saa PHP-skripti tĂ€itmise ajal muutuda, seega on uue sisendkomplekti saamiseks ainult ĂŒks vĂ”imalus: puhastada protsessi mĂ€lu ja algatada see uuesti.
Selle tÀitmismudeli puhul on palju eeliseid. Te ei pea vÀga muretsema mÀlu tarbimise pÀrast, kÔik protsessid on tÀielikult isoleeritud ja kui mÔni neist 'sureb', siis loob see automaatselt uue ning see ei mÔjuta teisi protsesse. Kuid sellel lÀhenemisel on ka puudusi, mis ilmnevad rakenduse skaleerimisel.
TavapÀrase PHP-keskkonna puudused ja ebaefektiivsus
Kui tegelete professionaalse PHP-arendusega, siis teate, et uue projekti alustamiseks tuleb alustada raamistiku valimisega. See on teegikomplekt sĂ”ltuvuste sisestamiseks, ORM-id, tĂ”lked ja templandid. Ja muidugi vĂ”ib kĂ”ik kasutaja sisendandmed mugavalt panna ĂŒhte objekti (Symfony/HttpFoundation vĂ”i PSR-7). Raamistike kasutamine on Ă€ge!
Kuid kĂ”igel on hind. IgapĂ€evases ettevĂ”tte taseme raamistikus peab lihtsa kasutaja pĂ€ringu vĂ”i andmebaasi pĂ€ringu töötlemiseks laadima vĂ€hemalt tosin failidest, looma arvukalt klasse ja parsima mitmeid konfiguratsioone. Kuid kĂ”ige hullem on see, et pĂ€rast iga ĂŒlesande tĂ€itmist tuleb kĂ”ik nullida ja alustada uuesti: kogu just algatatud kood muutub vÀÀrtusetuks, te ei saa selle abil enam ĂŒhegi teise pĂ€ringut töödelda. RÀÀkige sellest ĂŒkskĂ”ik kellele, kes kodeerib mĂ”nes teises keeles, ja te nĂ€ete tema nĂ€os arusaamatust.
PHP-insenerid on aastaid otsinud viise selle probleemi lahendamiseks, kasutanud nutikaid 'laiskade' laadimise meetodeid, mikromooduleid, optimeeritud raamatukogusid, vahemÀlu jne. Kuid lÔpuks tuleb ikkagi kogu rakendus tagasi nullida ja uuesti alustada, ikka ja jÀlle. (TÔlkija mÀrkuse: osaliselt lahendab see probleem PHP 7.4)
Kas PHP suudab Go abil vastu pidada rohkem kui ĂŒhele pĂ€ringule?
VĂ”ib kirjutada PHP skripte, mis elavad kauem kui mĂ”ned minutid (kuni tundide vĂ”i pĂ€evadeni): nĂ€iteks cron-ĂŒlesanded, CSV-parserid, jĂ€rjekorra töötlejad. KĂ”ik need toimivad ĂŒhesuguse stsenaariumi alusel: nad toovad ĂŒlesande, tĂ€idavad selle, ootavad jĂ€rgmist. Kood on pidevalt mĂ€lus, sÀÀstes vÀÀrtuslikke millisekunde, kuna raamistiku ja rakenduse laadimiseks on vajalik teostada mitmeid lisaĂŒlesandeid.
Kuid pikaajaliste skriptide arendamine pole nii lihtne. Iga viga tapab protsessi tÀielikult, mÀlulekke diagnoosimine ajab vihale ja F5-debugimise kasutamine pole enam vÔimalik.
Olek on paranenud koos PHP 7 ilmumisega: ilmus usaldusvÀÀrne prĂŒgikogumise sĂŒsteem, vigade töötlemine on lihtsam ja tuumalaienemised on nĂŒĂŒd lekkete eest kaitstud. TĂ”si, inseneridel tuleb endiselt ettevaatlikult mĂ€lu kĂ€sitleda ja meeles pidada koodiseisundi probleeme (kas on olemas keel, kus nendele asjadele tĂ€helepanu ei pöörata?). Siiski on PHP 7-s meid vĂ€hem ootamatustega.
Kas on vĂ”imalik vĂ”tta pikaajaliste PHP-skriptide töömudel, kohandada see lihtsate ĂŒlesannete, nĂ€iteks HTTP-pĂ€ringute töötlemise jaoks ja seelĂ€bi vabaneda vajadusest iga pĂ€ringu puhul kĂ”ik uuesti laadida?
Selle probleemi lahendamiseks pidi esmalt rakendama serverirakendust, mis suudab vastu vĂ”tta HTTP-pĂ€ringuid ja suunata need ĂŒksteise jĂ€rel PHP-töötlejale, tapmata seda iga kord.
Me teadsime, et suudame kirjutada veebiserveri puhta PHP (PHP-PM) vĂ”i C-lisandiga (Swoole). Kuigi kummalgi meetodil on omad eelised, ei rahuldanud mĂ”lemad variandid meid â soovisime midagi enamat. Vajasime mitte lihtsalt veebiserverit â meie eesmĂ€rk oli leida lahendus, mis vabastaks meid PHP âraskest kĂ€ivitamisestâ ja oleks samas kergesti kohandatav ja laiendatav konkreetsete rakenduste jaoks. Seega oli meil vajalik rakenduste server.
Kas Go vĂ”ib selles aidata? Me teadsime, et vĂ”ib, sest see keel kompileerib rakendused ĂŒhtsetesse binaarfailidesse; see on platvormidevaheline; kasutab oma vĂ€ga elegantset, paralleelse töötlemise mudelit ja HTTP töötluse raamatukogu; ning lĂ”puks, meil on juurdepÀÀs tuhandetele avatud lĂ€htekoodiga raamatukogudele ja integratsioonidele.
Kahe programmeerimiskeele ĂŒhendamise raskused
Esimene samm oli mÀÀrata, kuidas kaks vÔi enam rakendust omavahel suhtlevad.
NĂ€iteks, kasutades Alex PalĂ€stra, oli vĂ”imalik rakendada PHP ja Go protsesside vahel mĂ€lu jagamist (sarnaselt mod_php-ga Apache's). Kuid sellel raamatukogul on omadused, mis piiravad selle rakenduse sobivust meie ĂŒlesande lahendamiseks.
Otsustasime kasutada teist, laialdasemalt levinud lĂ€henemist: ehitada interaktsioon protsesside vahel lĂ€bi socket'ite/torude. See lĂ€henemine on viimase paarikĂŒmne aasta jooksul tĂ”estanud oma usaldusvÀÀrsust ja on hĂ€sti optimeeritud operatsioonisĂŒsteemi tasemel.
Alustuseks lĂ”ime lihtsa binaarprotokolli andmevahetuseks protsesside vahel ja edastamise vigade töötlemiseks. Oma kĂ”ige lihtsamas vormis sarnaneb selline protokoll jot (meie puhul 17 baiti), mis sisaldab teavet paketi tĂŒĂŒbi, selle suuruse ja andmete terviklikkuse kontrollimiseks mĂ”eldud binaarset maski.
PHP poolel kasutasime , samas kui Go poolel kasutasime raamatukogu.
Ăks protokoll ei tundunud piisav â lisasime vĂ”imaluse kutsuda. Hiljem aitas see meid arenduses, kuna saime hĂ”lpsasti integreerida Go-raamatukogusid PHP-rakendustesse. Selle töö tulemust vĂ”ib nĂ€ha nĂ€iteks meie teises avatud lĂ€htekoodiga tootes.
Ălesannete jaotamine mitme PHP-töötaja vahel
PĂ€rast suhtlemismehhanismi rakendamist hakkasime mĂ”tlema, kuidas edastada PHP-protsessidele ĂŒlesandeid vĂ”imalikult efektiivselt. Kui ĂŒlesanne saabub, peab rakenduse server valima töötaja, kes selle tĂ€itmise jaoks vaba on. Kui töötaja/protsess lĂ”petas töö veaga vĂ”i âsuriâ, vabaneme temast ja loome uue asemele. Kui töötaja/protsess töötas edukalt, saadame ta tagasi töötajate rikka, kes on valmis ĂŒlesandeid tĂ€itma.

Aktiivsete töötajate kogu salvestamiseks kasutasime, töötajate ootamatult âsuretudâ eemaldamiseks lisasime veahaldus- ja olekute jĂ€lgimise mehhanismi.
Tulemuseks saime töötava PHP-serveri, mis suudab töödelda igasuguseid binaarseid pÀringuid.
Et meie rakendus saaks töötada nagu veebiserver, pidime valima usaldusvÀÀrse PHP-standardi igasuguste sissetulevate HTTP-pĂ€ringute esitlemiseks. Meie puhul net/http-pĂ€ringu Go's PSR-7 formaatiKuna PSR-7 on muutumatu (keegi ĂŒtleb, et tehniliselt see nii pole), peavad arendajad kirjutama rakendusi, mis ei kĂ€sitle pĂ€ringut globaalse olendina. See sobib suurepĂ€raselt pikaajaliste PHP-protsesside kontseptsiooniga. Meie lĂ”plik teostus, mis ei ole veel nime saanud, nĂ€gi vĂ€lja nii:
Tutvustame RoadRunnerit â

kÔrge jÔudlusega PHP-rakenduste server
Selle lahenduse asendamiseks alustasime 2018. aasta alguses oma esimest PHP/Go-rakenduste serverit. Ja kohe saime uskumatuid tulemusi! Me mitte ainult ei vabanenud veast 502, vaid suutsime vÀhendada serverite arvu kolmandiku vÔrra, sÀÀstes palju raha ja valu tablettide jaoks inseneridele ja tootjate juhtidele.
Kuna 2018. aasta alguses, et asendada see lahendus, kĂ€ivitasime meie esimese PHP/Go rakenduste serveri. Ja kohe saime uskumatuid tulemusi! Me mitte ainult ei kĂ”rvaldanud 502 viga, vaid suutsime ka serverite arvu kolmandiku vĂ”rra vĂ€hendada, sÀÀstes tohutult raha ja nĂ€rve inseneridele ja tootemĂ€nedĆŸeridele.
Aasta keskpaiku tÀiustasime oma lahendust, avaldasime selle GitHubis MIT-i litsentsi all ja kutsusime seda , rÔhutades seelÀbi selle uskumatut kiirus ja efektiivsust.
Kuidas RoadRunner saab teie arendussteki parandada
Rakendamine lubas meil kasutada Middleware net/http Go pool, et teha JWT-sertifikaati juba enne, kui pÀring jÔuab PHP-sse, samuti WebSocketite töötlemiseks ja globaalsete olekute koondamiseks Prometheuses.
Sisseehitatud RPC vÔimaldab avada API igasuguste Go-teekide jaoks PHP-s ilma laienduste-mÀhiste kirjutamiseta. Veelgi olulisem on see, et RoadRunneriga on vÔimalik juurutada uusi servereid, mis ei piirdu HTTP-ga. NÀiteks vÔime mainida PHP töötlejate kÀivitamist, usaldusvÀÀrsete jÀrjekorraparserside loomist ja isegi lisamist meie rakendustesse.
Koos PHP ja Go kogudega oleme tÔstnud lahenduse stabiilsust, mÔningates testides suurendanud rakenduste jÔudlust kuni 40 korda, tÀiustanud silumisvahendeid, rakendanud integratsiooni Symfony raamistiku ja lisanud HTTPS-i, HTTP/2, pistikute ja PSR-17 toe.
KokkuvÔte
MĂ”ned inimesed on endiselt kinni vananenud arvamuses, et PHP on aeglane ja mahukas keel, mis sobib ainult WordPressi pistikprogrammide kirjutamiseks. Need inimesed vĂ”ivad isegi öelda, et PHP-l on selline piirang: kui rakendus muutub piisavalt suureks, peab valima âkĂŒpsemaâ keele ja ĂŒmber kirjutama aastate jooksul kogunenud koodibaasi.
Sellele kĂ”igile tahaksime vastata: mĂ”elge uuesti. Me usume, et ainult teie ise seab mĂ”ned piirangud PHP-le. Te vĂ”ite kulutada kogu elu, liikudes ĂŒhest keelest teise, pĂŒĂŒdes leida oma vajadustega ideaalset kombinatsiooni, vĂ”i hakata keeli kĂ€sitlema kui tööriistu. Kujuteldavad puudused nagu PHP vĂ”ivad tegelikult olla selle eduka kasvu pĂ”hjused. Ja kui ĂŒhendada see mĂ”ne teise keelega nagu Go, siis loote palju vĂ”imsamaid tooteid, kui kui piirdute vaid ĂŒhe keele kasutamisega.
Töötades Go ja PHP kombinatsiooniga, vĂ”ime kinnitada, et oleme neid armastanud. Me ei kavatse ĂŒhte ohverdada teise nimel â vastupidi, me otsime viise, kuidas sellest kahefstrahi veelgi rohkem kasu saada.
UPD: tervitame RoadRunneri loojat ja originaali artikli kaasautor -
Allikas: habr.com
