Me taas avaldame konverentsi ettekande transkriptsiooni 2016. aastal, mis toimus Moskva lĂ€histel Skolkovo 7â8. novembril möödunud aastal. rÀÀgib, kuidas laiendada NGINX-i funktsionaalsust OpenResty ja Lua abil.
Tere kĂ”igile, minu nimi on Vladimir Protasov, ma töötan Parallelsis. RÀÀgin veidi endast. Kolm neljandikku oma elust olen ma kirja pannud koodi. Olen tĂ”eline programmeerija: mĂ”nikord nĂ€en ma unes koodi. Ăks neljandik elust â tööstuslik arendus, koodi kirjutamine, mis lĂ€heb otse tootmisse. Kood, millega mĂ”ned teist kasutavad, aga ei pruugi sellest teadlikud olla.
Et te mĂ”istaksite, kui halb see kĂ”ik oli. Kui olin noor algaja, tulin kohale ja mulle anti kahesaja terabaidi andmebaasid. NĂŒĂŒd on kĂ”igil siin highload. KĂ€isin konverentsidel ja kĂŒsisin: «Kuidas, rÀÀgi, teil on big data, kĂ”ik on lahe? Kui suur on teie andmebaas?» Nad vastasid: «Meil on 100 gigabaiti!» Ma ĂŒtlesin: «Lahe, 100 gigabaiti!» Samas mĂ”tlesin, kuidas sĂ€ilitada rahulik nĂ€gu. MĂ”tled, et jah, need tĂŒĂŒbid on Ă€gedad, ja siis tuled tagasi ja tegeled nende mitme terabaidi andmebaasidega. Ja see kĂ”ik â olles algaja. Kas te oskate ette kujutada, kui suur see löök oli?
Ma tunnen ĂŒle 20 programmeerimiskeele. See on see, millega pidin töö kĂ€igus kokku puutuma. Sulle antakse koodi Erlangis, C-s, C++-s, Luas, Pythonis, Ruby's jne, ja sa pead sellega hakkama saama. ĂhesĂ”naga, pidin. TĂ€pset arvu kokku lugeda ei Ă”nnestunud, aga kuskil 20 on kaotsi lĂ€inud.
Kuna kĂ”ik kohalolijad teavad, mis on Parallels ja millega me tegeleme, ei hakka ma rÀÀkima, kui Ă€gedad me oleme ja mida teeme. RÀÀgin ainult, et meil on 13 kontorit ĂŒle maailma, rohkem kui 300 töötajat, arendus Tallinnas, Moskvas ja Maltal. Soovi korral saab Maltale kolida, kui talvel on kĂŒlm ja tahad end soojendada.
Meie osakond kirjutab Python 2-s. Me tegeleme Ă€rihuvidega ja meil pole aega modernsete tehnoloogiate juurutamiseks, seetĂ”ttu kannatame. Meil on Django, sest seal on kĂ”ik olemas, ja ĂŒleliigse viskame minema. Samuti MySQL, Redis ja NGINX. Meil on ka palju muid lahedaid asju. Meil on MongoDB, meie vahel jooksevad kĂŒĂŒlikud, meil on kĂ”ike â aga see ei ole minu osa ja sellega ma ei tegele.
OpenResty
Oma kohta rÀÀkisin. Olgem nĂŒĂŒd selged, millest ma tĂ€na rÀÀgin:
- Mis on OpenResty ja millega seda sĂŒĂŒakse?
- Miks vĂ€lja mĂ”tlema veel ĂŒhte jalgratast, kui meil on olemas Python, NodeJS, PHP, Go ja muud Ă€gedad asjad, millega kĂ”ik on rahul?
- Veidi elulisi nÀiteid. Mul tuli esitluse mahtu mÀrgatavalt vÀhendada, kuna see venis koguni 3,5 tunni pikkuseks, seega nÀiteid jÀÀb vÀhemaks.
OpenResty on NGINX. TĂ€nu sellele on meil tĂ€ieĂ”iguslik veebiserver, mis on kenasti kirjutatud ja töötab kiiresti. Ma arvan, et enamik meist kasutab NGINX-i tootmises. Te kĂ”ik teate, et see on kiire ja Ă€ge. Sellel on suurepĂ€rane sĂŒnkrone sisend/vĂ€ljund, seega ei pea me mitut jalgratast leiutama nagu Pythonis, kus gevent on leiutatud. Gevent on Ă€ge, aga kui kirjutate C-keelt ja midagi lĂ€heb valesti, siis geventi tĂ”rgete leidmine ajab teid hulluks. Mul oli kogemus, kus kulus lausa kaks pĂ€eva, et mĂ”ista, mis valesti lĂ€ks. Kui keegi poleks eelnevalt nĂ€dalaid kaevanud, probleemi leidnud, sellest Internetis kirjutanud ja Google seda leidnud, siis oleksime tĂ€iesti hullu lĂ€inud.
NGINX-is on juba olemas vahemĂ€lu ja staatiline sisu. Te ei pea muretsema selle ĂŒle, kuidas seda korralikult teha, et kuskil ei tekiks takistusi ja et te ei kaotaks kirjeldusi. Nginx-i on vĂ€ga mugav kasutada, teil ei pea olema peamurdmist selle ĂŒle, mida valida - WSGI, PHP-FPM, Gunicorn, Unicorn. Paigaldage Nginx, andke adminstratsioonile, nad teavad, kuidas sellega töötada. Nginx töötleb pĂ€ringud struktureeritult. RÀÀgin sellest veidi hiljem. LĂŒhidalt on sellel faas, kui see vastuvĂ”tt, teine faas, kui see töötleb, ja kolmas, kui see edastab sisu kasutajale.
Nginx on Ă€ge, kuid on ĂŒks probleem: see ei ole piisavalt paindlik isegi kĂ”ikide nende Ă€gedate funktsioonide puhul, mida arendajad on seadistusse lisanud. Seda vĂ”imu on liiga vĂ€he. SeetĂ”ttu integreerisid Taobao arendajad sinna kunagi ammu, umbes kaheksa aastat tagasi, Lua. Mida see annab?
- Suurus. See on vĂ€ike. LuaJIT annab umbes 100-200 kilobaiti mĂ€lu ĂŒlekaalu ja minimaalset jĂ”udluse ĂŒlekaalu.
- Kiirus. LuaJIT tĂ”lkija on paljudes olukordades C lĂ€hedane, mĂ”nedes olukordades jÀÀb see Java-le alla ja mĂ”nedes olukordades ĂŒletab selle. Teatud aja jooksul peeti seda parimaks, Ă€gedaimaks JIT-kompilaatoriks. Praegu on olemas veelgi Ă€gedamaid, kuid need on vĂ€ga rasked, nĂ€iteks sama V8. MĂ”ned JS tĂ”lkijad ja Java HotSpot on mĂ”nes punktis kiiremad, kuid teistes kohtades jÀÀvad endiselt alla.
- Lihtsus omandamisel. Kui teie koodibaas on nĂ€iteks Perl, ja te ei ole Booking, siis te ei leia Perl programmeerijaid. Sest neid ei ole, kĂ”ik on nad Ă€ra viidud ja nende Ă”petamine on pikaldane ja keeruline. Kui soovite programmeerijaid millegi muu jaoks, siis vĂ”ib-olla tuleb ka neid ĂŒmber koolitada vĂ”i leida. Lua puhul on kĂ”ik lihtne. Lua Ă”pib ĂŒkskĂ”ik milline algaja kolme pĂ€evaga. Mul kulus umbes kaks tundi, et selgeks saada. Kaks tundi hiljem kirjutasin ma juba tootmises koodi.
Tulemus vÀlja nÀeb nii:

Siin on palju asju. OpenResty's on kogutud hulk mooduleid, nii Luaga kui ka NGINXiga. Ja teil on kÔik valmis - sÔlmitud ja töötab.
NĂ€ited
LÔpetame luule, liikuge koodi juurde. Siin on vÀike Hello World:

Mida siin on? See on NGINXi location. Me ei vaeva end, me ei kirjuta oma suunamist ega kasuta mingit valmis - meil on juba NGINXis olemas, elame hÀsti ja laiskade elu.
content_by_lua_block â see on plokk, mis ĂŒtleb, et anname conteneti edasi Lua skripti abil. VĂ”tame NGINXi muutuja remote_addr ja paneme selle sisse string.format. See on sama, mis sprintf, ainult et Lua-s, ainult Ă”ige. Ja anname selle kliendile.
Tulemus nÀeb vÀlja nii:

Aga naaseme reaalsesse maailma. Tootmises ei saa keegi Hello World'i. Meie rakendus kÀib enamasti andmebaasi vÔi mujale ja suure osa ajast ootab vastust.

Lihtsalt istub ja ootab. See ei ole vĂ€ga hea. Kui tuleb 100 000 kasutajat, siis on meil vĂ€ga raske. SeetĂ”ttu looge nĂ€iteks lihtne rakendus. Otsime pilte, nĂ€iteks kasse. Ainult et me ei otsi lihtsalt, vaid laiendame mĂ€rksĂ”nu ja kui kasutaja otsib 'kutsikaid', siis leiame me kassid, karvased ja muud. Esiteks peame saama taotluse andmed tagakĂŒljel. See nĂ€eb vĂ€lja nii:

Kaks rida vÔimaldavad teil GET-parameetreid kÀtte saada, ei mingeid raskusi. Edasi saame nÀiteks andmebaasist mÀrksÔna ja laienduse tabelist selle teabe tavalise SQL-pÀringuga. KÔik on lihtne. See nÀeb vÀlja nii:

Ăhendame raamatukogu resty.mysql, mis on meil juba komplektis. Me ei pea midagi installima, kĂ”ik on valmis. NĂ€itame, kuidas ĂŒhenduda ja teeme SQL-pĂ€ringu:

Siin on natuke hirmutav, aga kĂ”ik toimib. Siin on 10 â see on limiit. Me vĂ”tame vĂ€lja 10 kirjeid, me oleme laiskad, ei taha rohkem nĂ€idata. SQLis unustasin ma limiidi.
Edasi otsime pilte kÔikide pÀringute pÔhjal. Kogume hunniku pÀringuid ja tÀidame Lua-tabeli, mis on nimetatud reqs, ja teeme ngx.location.capture_multi.

KÔik need pÀringud lÀhevad paralleelselt ja me saame vastused tagasi. Tööaeg on vÔrdsustatud kÔige aeglasema vastuse ajaga. Kui kÔik meie pÀringud tuleb tagasi 50 millisekundi pÀrast ja me saatsime sada pÀringut, siis saame vastuse 50 millisekundi pÀrast.
Kuna me oleme laiskad ja ei taha kirjutada HTTP töötlemist ja vahemÀlu, siis paneme NGINX'i kÔike meie eest tegema. Nagu te nÀgite, oli seal pÀring url/fetch, see ongi:

Teeme lihtsa proxy_pass, nÀitame, kuhu vahemÀllu salvestada, kuidas seda teha, ja meil kÔik töötab.
Aga sellest ei piisa, me peame ka andmed kasutajale andma. KÔige lihtsam mÔte on see kÔik JSON'i seriaalida, lihtsalt, kahel reabil. Anname Content-Type, anname JSON'i.
Aga on ĂŒks raskus: kasutaja ei taha lugeda JSON'i. Peame kaasama frontend arendajad. MĂ”nikord ei taha me seda alguses teha. Ja SEO spetsialistid ĂŒtlevad, et kui me otsime pilte, siis neil pole vahet. Aga kui me anname mingit sisu, siis nad ĂŒtlevad, et meie otsingumootorid ei indekseeri midagi.
Mida sellega teha? Loomulikult anname kasutajale HTML'i. KÀsi-kÀes genereerimine ei ole cool, seega tahame kasutada malle. Selleks on olemas raamatukogu lua-resty-template.

Te olete ilmselt nÀinud kolme hirmutavat tÀhte OPM. OpenResty tuleb oma pakihalduriga, mille kaudu saab paigaldada veel palju erinevaid mooduleid, sealhulgas lua-resty-template. See on lihtne malle engine, mis on sarnane Django mallidele. Seal saab kirjutada koodi ja teha muutujate asendusi.
Tulemuseks on, et kÔik nÀeb vÀlja umbes nii:

Me vÔtsime andmed ja renderdasime malli taas kahe reaga. Kasutaja on Ônnelik, sai kassipojad. Kuna me laiendasime pÀringut, sai ta kassipoja koos merikassiga. Kes teab, vÔib-olla otsis ta just teda, aga ei osanud oma pÀringut Ôigesti formuleerida.
KÔik on hÀsti, aga me oleme arenduses ja ei taha veel kasutajatele nÀidata. Tehkem autentimine. Selleks vaatame, kuidas NGINX töötleb pÀringut OpenResty mÔistes:
- Esimene faas â access, kui kasutaja alles liitus ja me vaatame teda pealkirjade, IP-aadressi ja muude andmete kaudu. Saame ta kohe vĂ€lja lĂŒlitada, kui ta meile ei meeldi. Seda saab kasutada autoriseerimiseks vĂ”i kui saame liiga palju pĂ€ringuid, saame neid hĂ”lpsasti sellel etapil katkestada.
- rewrite. Kirjutame mĂ”ned pĂ€ringu andmed ĂŒmber.
- content. Anname sisu kasutajale.
- pealkirjade filter. Muudame vastuse pealkirju. Kui oleme kasutanud
proxy_pass, vĂ”ime kirjutada mĂ”ned pealkirjad ĂŒmber enne, kui anname need kasutajale. - sisu filter. Saame keha muuta.
- log â logimine. Saame kirjutada logisid elasticsearchi ilma lisa kihita.
Meie autoriseerimine nÀeb vÀlja umbes nii:

Lisame selle sinna asukoht, mille me varem kirjeldasime, ja paneme sinna sellise koodi:

Kontrollime, kas meil on kĂŒpsise token. Kui ei, siis suuname autoriseerimise peale. Kasutajad on nutikad ja vĂ”ivad arvata, et tuleb kĂŒpsise token paigaldada. SeetĂ”ttu paneme selle ka Redis'sse:

Kood Redisega töötamiseks on vĂ€ga lihtne ja ei erine teiste keeltest. Samuti on kogu sisend/vĂ€ljund seal ja siin mitteblokeeriv. Kui kirjutate sĂŒnkrontkoodi, töötab see asĂŒnkroonselt. Umbes nagu gevent, ainult hĂ€sti tehtud.

Teeme autoriseerimise:

Ătleme, et peame lugema pĂ€ringu keha. Saame POST-argumendid, kontrollime, kas kasutajanimi ja parool on Ă”iged. Kui ei, siis suuname autoriseerimise peale. Ja kui on Ă”iged, siis salvestame tokeni Redis'sse:

Ărge unustage seada kĂŒpsist, see tehakse ka kahe reaga:

Lihtne, teoreetiline nÀide. Me kindlasti ei tee teenust, mis nÀitab inimestele kiisusid. Kuigi kes teab. SeetÔttu kÀime lÀbi, mida saab teha tootmisprotsessis.
- Minimalistlik backend. MÔnikord vajame backend'ist vaid vÀga vÀhe andmeid: kuskil tuleb kuupÀeva lisada, kuskil tuua vÀlja mingi nimekiri, öelda, kui palju kasutajaid on praegu saidil, lisada loendaja vÔi statistika. Midagi sarnast vÀikest. VÀikesed osad on vÀga kergesti teostatavad. Sellega saab kiirelt, lihtsalt ja suurepÀraselt hakkama.
- Andmete eelprotsessimine. Aegiatseme on meil soov sisestada oma lehe reklaami, ja selle saame API-pĂ€ringutega. Seda saab siit vĂ€ga lihtsalt teha. Me ei koorma oma tagakĂŒlge, mis samuti raskelt töötab. Me saame seda siin koguda. Saame kokku panna mingit JS-i vĂ”i vastupidi, lahti vĂ”tta ja midagi eeltöödelda enne, kui kasutajale vĂ€lja anname.
- Mikroteenuse liides. See on samuti vÀga hea lahendus, mida ma olen ellu viinud. Enne seda töötasin ettevÔttes Tenzor, mis tegeleb elektroonilise aruandlusega ja tagab aruandluse umbes poolele juriidilistele isikutele riigis. Me tegime teenuse, kus paljusid asju on tehtud sama mehhanismi abil: marsruutimine, autoriseerimine ja muud.
OpenResty't saab kasutada teie mikroteenuste liimimiseks, mis tagab ĂŒhtse juurdepÀÀsu kĂ”igile ja ĂŒhtse liidese. Kuna mikroteenused vĂ”ivad olla kirjutatud nii, et siin on Node.js, seal on PHP, seal Python ja kuskil on tĂŒkk Erlang, mĂ”istame, et me ei soovi sama koodi igale poole uuesti kirjutada. SeetĂ”ttu saab OpenResty't paigutada ette. - Statistika ja analĂŒĂŒs. Tavaliselt on NGINX sissepÀÀsus ja kĂ”ik pĂ€ringud lĂ€hevad lĂ€bi selle. Just siin on vĂ€ga mugav midagi kokku koguda. Saab kohe midagi vĂ€lja arvutada ja kuhugi panna, nĂ€iteks Elasticsearchisse, Logstashi vĂ”i lihtsalt logisse kirja panna ja siis kuhugi saata.
- Mitme kasutaja sĂŒsteemid. NĂ€iteks, online-mĂ€nge on samuti vĂ€ga hĂ€sti teha. TĂ€na rÀÀgib Kaplinnas Alexander Gladys, kuidas kiiresti prototĂŒĂŒpida mitme mĂ€ngijaga mĂ€ngu OpenResty abil.
- PĂ€ringute filtreerimine (WAF). Praegu on moes teha erinevaid veebi rakenduste tulemĂŒĂŒre, on palju teenuseid, mis neid pakuvad. OpenResty abil saate enda jaoks luua veebi rakenduste tulemĂŒĂŒri, mis lihtsalt ja kergesti filtreerib pĂ€ringud vastavalt teie nĂ”udmistele. Kui teil on Python, siis mĂ”istate, et PHP't ei saa kindlasti sisse sĂŒstida, kui te, muidugi, ei spawnida seda kuskil konsoolist. Teate, et teil on MySQL ja Python. TĂ”enĂ€oliselt vĂ”ivad siin proovida teha mingit katalooge lĂ€bivat rĂŒnnakut ja midagi sisestada andmebaasi. SeetĂ”ttu saab kahtlased pĂ€ringud kiiresti ja odavalt kohe ees filtrida.
- Kogukond. Kuna OpenResty on ĂŒles ehitatud NGINX-i baasil, on sellel boonus - see NGINXi kogukondSee on vĂ€ga suur ja enamik alguses tekkida vĂ”ivaid kĂŒsimusi on juba lahendatud NGINX-i kogukonna poolt.
Lua arendajadEile rÀÀkisin poistega, kes tulid HighLoad++ Ă”ppepĂ€evale, ja kuulsin, et ainult Tarantool on kirjutatud Luas. See pole tĂ”si, Luas on kirjutatud palju. NĂ€iteks: OpenResty, XMPP-server Prosody, mĂ€ngumootor Love2D, Lua skripteeritakse Warcraftis ja mujal. Lua arendajaid on palju ning neil on suur ja vastutulelik kogukond. KĂ”ik minu kĂŒsimused Lua kohta lahendati paaritunniga. Kui kirjutad meililistile, saad sisuliselt mĂ”ne minuti jooksul hulga vastuseid, kus seletatakse, kuidas ja mis toimub. See on tĂ”eliselt suurepĂ€rane. Kahjuks pole igal pool nii lahke ja abivalmis kogukonda.
OpenResty kohta on olemas GitHub, kus saab avada probleemide pilet, kui midagi on katki. On olemas meililist Google Groupsis, kus saab arutada ĂŒldisi kĂŒsimusi, samuti on olemas hiinakeelne meililist - Ă€kki sul ei ole inglise keeles oskusi, aga hiina keeles on.
Summary
- Loodan, et suutsin edastada, et OpenResty on vÀga mugav raamistik, mis on suunatud veebile dem.
- Sellel on madal sisenemiskĂŒnnis, kuna kood sarnaneb sellele, millega me kirjutame, keel on ĂŒsna lihtne ja minimalistlik.
- See pakub asĂŒnkroonset I/O ilma callback'ideta, meil ei tule segadust nagu vahel NodeJS-is kirjutades.
- Sellel on lihtne kasutusele vÔtmine, kuna meil on vaja ainult NGINX-i koos vajaliku mooduliga ja meie kood, ja kÔik töötab kohe.
- Suur ja vastutulelik kogukond.
Ma ei rÀÀkinud ĂŒksikasjalikult marsruutimisest, see oleks saanud vĂ€ga pikk jutustus.
AitÀh tÀhelepanu eest!

Allikas: habr.com
