Ne po publikojmë përsëri transkriptin e fjalës nga konferenca 2016, që u mbajt në Skolkovo, jashtë Moskës, më 7–8 nëntor të vitit të kaluar. tregon si të zgjeroni funksionalitetin e NGINX duke përdorur OpenResty dhe Lua.
Përshëndetje të gjithëve, unë quhem Vladimir Protasov, punoj në Parallels. Do të flas pak për veten time. Tre të katërtat e jetës time kam punuar me kodin. Kam bërë programues deri në esencë: ndonjëherë e shoh kodin edhe në ëndrrat e mia. Një të katërtën e jetës - zhvillim industrial, shkruaj kod që shkon direkt në prodhim. Kod që disa nga ju e përdorni, por nuk e dini këtë.
Për ta kuptuar se sa keq ishte. Kur isha një junior i vogël, erdha dhe më dhanë baza me dy terabajt. Tani këtu të gjithë kanë highload. Shkoja në konferenca dhe pyesja: 'Djem, tregoni, a keni big data, gjithçka është super? Sa e madhe është baza juaj?' Ata me përgjigjen: 'Ne kemi 100 gigabajt!' Unë thosha: 'Super, 100 gigabajt!' Ndërsa në mendje mendoja se si të mbaja një fytyrë të qetë. Mendoj, po, djemtë janë të mrekullueshëm, dhe pastaj kthehem dhe përleshem me këto baza shumë terabajt. Dhe kjo - duke qenë junior. Mund të imagjinoni se sa goditje ishte?
Unë njoh më shumë se 20 gjuhë programimi. Kjo është diçka që më është dashur të kuptoj gjatë punës. Ju japin kod në Erlang, C, C++, Lua, Python, Ruby, dhe diçka tjetër, dhe duhet ta punoni. Në përgjithësi, kjo ishte e nevojshme. Nuk arrita të llogaris saktë numrin, por ndoshta humba countin pas 20.
Duke qenë se të gjithë të pranishëm e dinë çfarë është Parallels dhe me çfarë merremi, nuk do të flas për sa të shkëlqyer jemi dhe çfarë bëjmë. Do të theksoj vetëm se kemi 13 zyre në botë, më shumë se 300 punonjës, zhvillimi në Moskë, Tallin dhe në Maltë. Nëse dëshironi, mund të transferoheni në Maltë, nëse është ftohtë dimri dhe duhet të ngroheni.
Saktësisht, departamenti ynë punon me Python 2. Ne merremi me biznes dhe nuk kemi kohë për të futur teknologjitë e modës, kështu që kemi vështirësi. Ne përdorim Django, sepse aty ka gjithçka, dhe heqim të tepërat. Po ashtu MySQL, Redis dhe NGINX. Kemi shumë gjëra të tjera të shkëlqyera. Kemi MongoDB, ne kemi lepuj që vrapojnë, kemi çfarëdo - por kjo nuk është punë ime, dhe unë nuk merrem me të.
OpenResty
Kam për vete folëm. Le të shohim se për çfarë do flas sot:
- Çfarë është OpenResty dhe si e përdorim atë?
- Pse të shpikim një biçikletë tjetër, kur kemi Python, NodeJS, PHP, Go dhe gjëra të tjera të shkëlqyera me të cilat të gjithë janë të kënaqur?
- Dhe pak shembuj nga jeta. Më duhej të shkurtova shumë ligjëratën, sepse ajo rezultoi të ishte 3.5 orë, prandaj shembujt do të jenë të pakta.
OpenResty është NGINX. Falë tij kemi një server të plotë web, i shkruar mirë dhe punon shpejt. Mendoj se shumica prej nesh përdorin NGINX në prodhim. Të gjithë e dini se ai është i shpejtë dhe i shkëlqyer. Ata bënë një hyrje/dalje të shkëlqyer sinkron, prandaj nuk kemi nevojë të shpikim gjëra siç është bërë me gevent në Python. Gevent është fantastik, por nëse shkruani kod në C dhe diçka shkon keq, ju do të çmendeni për ta debuguar atë me gevent. Kam pasur eksperiencë: m'u deshën dy ditë të plota për të kuptuar se çfarë kishte shkuar keq. Nëse dikush nuk do të kishte gërmuar për disa javë përpara, nuk do të kishte gjetur problem dhe nuk do ta kishte shkruar atë në Internet, Google nuk do ta kishte gjetur këtë, do të ishim çmendur.
Në NGINX, tashmë janë bërë caching dhe përmbajtje statike. Nuk keni nevojë të shqetësoheni se si ta bëni atë siç duhet, në mënyrë që dikund të mos ngecni, që të mos humbni ndonjë deskriptor. NGINX është shumë e lehtë për tu depolu, nuk keni nevojë të mendoni se çfarë të përdorni - WSGI, PHP-FPM, Gunicorn, Unicorn. Instaluar NGINX, ia dorëzuat administratorëve, ata dinë si ta trajtojnë atë. NGINX trajton kërkesat në mënyrë të strukturuar. Për këtë do flas pak më vonë. Në përmbledhje, ka një fazë kur sapo pranoi kërkesën, një fazë kur e përpunoi dhe një fazë kur iu dha përmbajtja përdoruesit.
Nginx është i shkëlqyer, por ka një problem: ai nuk është mjaft i fleksibël edhe me të gjitha ato gjëra të shkëlqyera që ekipi ka përfshirë në konfigurimin e tij, përkundër se mund të konfigurohet. Kësaj fuqie i mungon fleksibiliteti. Prandaj, ekipi nga Taobao, para rreth tetë vjetësh, e futi Lua atje. Çfarë na sjell kjo?
- Madhësia. Ai është i vogël. LuaJIT ofron rreth 100-200 kilobajt mbivendosje në memorje dhe një mbivendosje minimale në performancë.
- ShpejtësiaInterpreteri LuaJIT në shumë situata është i afërm me C, në disa situata ai humbet ndaj Java, dhe në disa situata e tejkalon. Një kohë, ai u konsiderua state of the art, kompilatorin JIT më të avancuar. Tani ka më të avancuar, por ato janë shumë të rënda, si për shembull V8. Disa interpretues JS dhe HotSpot-i i Java-s në disa pika janë më të shpejtë, por në disa vendet akoma humbin.
- Lehtësia në mësim. Nëse ju, për shembull, keni një bazë kodi në Perl, dhe nuk jeni Booking, nuk do të gjeni programues Perl. Sepse nuk ka, të gjithë i morën, dhe t’i mësoj ata është e gjatë dhe e vështirë. Nëse dëshironi programues në diçka tjetër, ndoshta do të duhet t'i ri-edukoni ose t'i gjeni. Në rastin e Lua, gjithçka është e thjeshtë. Lua mësohet nga çdo junior brenda tre ditësh. Më mori rreth dy orë për t’u kuptuar. Pas dy orëve isha duke shkruar kod në prodhim. Pas rreth një jave, ai shkoi direkt në prodhim.
Si rezultat, kjo duket kështu:

Këtu ka shumë gjëra. Në OpenResty janë mbledhur shumë module, si ato të lua-s ashtu edhe ato të engine-s. Dhe ju keni gjithçka gati - e keni deploy-ed dhe funksionon.
Shembuj
Mjaft me lirikat, kalojmë te kodi. Ja një Hello World të vogël:

Çfarë ka këtu? ky është një location i engine-s. Ne nuk shqetësohemi, nuk shkruajmë routing tonë, nuk marrim ndonjë që ekziston - kemi tashmë në NGINX, jetojmë mirë dhe lenvë.
content_by_lua_block – është një bllok, që thotë se ne po japim përmbajtje me ndihmën e një skripti Lua. Marrim një variabël të engine-s remote_addr dhe e fusim atë në string.format. Kjo është e njëjta gjë si sprintf, vetëm në Lua, vetëm në mënyrë të duhur. Dhe ia japim klientit.
Si rezultat, do të duket kështu:

Por le të kthehemi në botën reale. Në prodhim askush nuk deploy-on Hello World. Aplikacioni ynë zakonisht shkon në bazë ose diku tjetër dhe shumicën e kohës pret një përgjigje.

Thjesht ulur dhe pret. Kjo nuk është shumë mirë. Kur vijnë 100.000 përdorues, na vjen shumë e vështirë. Prandaj le të marrim si shembull një aplikacion të thjeshtë. Do të kërkojmë imazhe, për shembull, të maceve. Por ne nuk do të kërkojmë thjesht kështu, ne do të zgjeronim fjalët kyçe dhe, nëse përdoruesi kërkoi "kacurrel", ne do t'i gjejmë mace, të buta dhe gjëra të tjera. Së pari na nevojitet të marrim të dhënat e kërkesës në backend. Kjo duket kështu:

Dy dy nota ju ofrojnë mundësinë të merrni parametrat GET, pa asnjë vështirësi. Pastaj, le të themi, nga një bazë të dhënash me një tabelë për fjalën kyç dhe zgjerimin, marrim këtë informacion me një kërkesë SQL të zakonshme. Është e thjeshtë. Kështu duket:

Konektimi me bibliotekën resty.mysql, e cila është tashmë në paketë. Nuk na nevojitet asgjë për të instaluar, gjithçka është gati. Shënojmë si të lidhemi dhe bëjmë kërkesën SQL:

Këtu është disi e frikshme, por gjithçka funksionon. Këtu 10 është kufiri. Ne nxjerrim 10 shënime, jemi të lenatë, nuk duam të tregojmë më shumë. Në SQL e harrova kufirin.
Më pas, ne gjejmë imazhe për të gjitha kërkesat. Mblidhemi një grup kërkesash dhe mbushim një tabelë Lua, e cila quhet reqs, dhe bëjmë ngx.location.capture_multi.

Të gjithë këta kërkesa shkojnë në paralele dhe na kthehen përgjigjet. Koha e ekzekutimit është e barabartë me kohën e përgjigjes më të ngadalshme. Nëse të gjithë përfundojnë brenda 50 milisekondash, dhe ne kemi dërguar njëqind kërkesa, përgjigja jonë do të vijë brenda 50 milisekondash.
Pas si jemi të lenatë dhe nuk duam të shkruajmë përpunimin HTTP dhe caching, ne do ta detyrojmë NGINX të bëjë gjithçka për ne. Ashtu siç e keni parë, kishte një kërkesë për url/fetch, ja ai:

Ne bëjmë një të thjeshtë, shënojmë se ku të ruajmë në cache, si ta bëjmë këtë, dhe gjithçka funksionon. proxy_passPor kjo nuk është e mjaftueshme, ne gjithashtu duhet t'i japim të dhënat përdoruesit. Ideja më e thjeshtë është ta serizojmë gjithçka në JSON, lehtë, në dy nota. Jepni Content-Type, jepni JSON.
Por ka një veshtirësi: përdoruesi nuk dëshiron të lexojë JSON. Duhet të angazhojmë front-end developerët. Ndonjëherë, fillimisht, nuk duam ta bëjmë këtë. Edhe SEO specialistët do të thonë se, nëse po kërkojmë imazhe, ata nuk kanë rëndësi. Por nëse po u japim ndonjë përmbajtje, atëherë ata do të thonë se motorët tanë të kërkimit nuk indeksojnë asgjë.
Çfarë të bëjmë me këtë? Sigurisht, ne do t'i japim përdoruesit HTML. Të krijosh me dorë - nuk është e kualifikuar, prandaj duam të përdorim shabllone. Për këtë ka bibliotekën
lua-resty-template Ndoshta e keni parë tre shkronjat e frikshme OPM. OpenResty vjen me menaxherin e tij të paketave, përmes të cilit mund të instaloni një sërë moduli të ndryshëm, në veçanti,.

. Ky është një motor i thjeshtë shablloni, i afërt me shabllonat Django. Atje mund të shkruani kod dhe të bëni zëvendësimin e variablave. Ndoshta e keni parë tre shkronjat e frikshme OPM. OpenResty vjen me menaxherin e tij të paketave, përmes të cilit mund të instaloni një sërë moduli të ndryshëm, në veçanti,Si rezultat, gjithçka do të duket përafërsisht kështu:
Si rezultat, gjithçka do të duket përreth kështu:

Ne morëm të dhënat dhe e kërkuam sërish shabllonin në dy rreshta. Përdoruesi është i lumtur, ka marrë mace. Sepse ne e zgjatëm kërkesën, ai për macet e vegjël mori edhe një fokë. Kush e di, ndoshta ai e kërkonte pikërisht atë, por nuk mund ta formulojë siç duhet kërkesën e tij.
Gjithçka është super, por jemi në zhvillim, dhe nuk duam akoma t'ua tregojmë përdoruesve. Le të bëjmë autorizimin. Për ta bërë këtë, le të shohim si NGINX e trajton kërkesën në terma të OpenResty:
- Faza e parë — access, kur përdoruesi sapo ka ardhur, dhe ne e shikojmë atë sipas titujve, IP adresës, dhe të dhënave të tjera. Mund ta ndërpresim menjëherë nëse nuk na pëlqen. Kjo mund të përdoret për autorizimin, ose nëse na vijnë shumë kërkesa, mund t'i ndalojmë lehtësisht në këtë fazë.
- rewrite. Rishkruajmë disa të dhëna të kërkesës.
- me mbështetje. I japim përmbajtjen përdoruesit.
- headers filter. Ndërrimi i titujve të përgjigjes. Nëse kemi përdorur
proxy_pass, mund të rishkruajmë disa tituj para se t'ia dorëzojmë përdoruesit. - body filter. Mund të ndërroni trupin.
- log — regjistrimi. Mund të shkruani logët në Elasticsearch pa një nivel shtesë.
Autorizimi ynë do të duket përafërsisht kështu:

Ne do ta shtojmë këtë në atë location, që e kemi përshkruar më parë, dhe do ta vendosim një kod të tillë:

Shikojmë nëse kemi cookie token. Nëse jo, atëherë e çojmë në autorizim. Përdoruesit janë të zgjuar dhe mund ta kuptojnë se duhet të vendosin cookie token. Prandaj ne do ta vendosim atë edhe në Redis:

Kodi për punën me Redis është shumë i thjeshtë dhe nuk ndryshon nga gjuhët e tjera. Në të njëjtën kohë, gjithë hyrja/dalja, aty dhe këtu, është jo bllokuese. Nëse shkruani kod të sinkronizuar, atëherë punon asinkronisht. Përshtatshëm si me gevent, vetëm se është bërë mirë.

Le ta bëjmë vetë autorizimin:

Them se na nevojitet të lexojmë trupin e kërkesës. Marrim argumentet POST, kontrollojmë që emri i përdoruesit dhe fjalëkalimi janë të saktë. Nëse janë të pasakta, atëherë e çojmë në autorizim. Por nëse janë të sakta, shënojmë token në Redis:

Mos harro të vendosësh cookie, kjo gjithashtu bëhet në dy rreshta:

Shembulli është i thjeshtë, teorik. Sigurisht që nuk do të krijojmë një shërbim që tregon njerëzve mace. Megjithatë, kush na njeh. Prandaj, le të kalojmë në atë që mund të bëhet në prodhim.
- Backend minimalist. Ndonjëherë na nevojitet të ofrojmë disa të dhëna në backend: ndonjëherë duhet të vendosim një datë, ndonjëherë të shfaqim ndonjë listë, të tregojmë se sa përdorues aktualisht janë në faqen e internetit, të lidhemi me ndonjë numërues apo statistikë. Diçka e tillë. Këto copëza minimale mund të realizohen shumë lehtësisht. Kështu do të dalë shpejt, lehtësisht dhe bukur.
- Parapërpunimi i të dhënave. Ndonjëherë na do të integrojmë reklamë në faqen tonë, dhe këtë reklamë e marrim përmes API requests. Kjo është shumë e lehtë për tu realizuar pikërisht këtu. Ne nuk e ngarkojmë backend-in tonë, i cili dhe ashtu është i ngarkuar shumë. Mund të marrim dhe të mbledhim këtu. Ne mund të krijojmë disa JS ose, përkundrazi, t'i ndajmë, diçka për t'u parapërpunuar përpara se t'ia japim përdoruesit.
- Facade për mikroshërbisin. Ky është gjithashtu një rast shumë i mirë, që e kam realizuar. Para kësaj kam punuar në kompaninë Tenzor, e cila merret me raportimin elektronik, duke siguruar raportimin për rreth gjysmën e personave juridikë në vend. Ne krijuam një shërbim, aty me këtë mekanizëm janë realizuar shumë gjëra: routimi, autorizimi dhe të tjera.
OpenResty mund të përdoret si shakulli për mikroshërbimet tuaja, që do të sigurojë një qasje të njëjtë për të gjitha dhe një ndërfaqe të njëjtë. Duke qenë se mikroshërbimet mund të shkruhen në mënyrë që këtu keni Node.js, këtu keni PHP, këtu Python, dhe aty është ndonjë gjë në Erlang, ne e kuptojmë se nuk duam ta rikorrektojmë të njëjtin kod në të gjithë vendin. Prandaj OpenResty mund të vendoset në front. - Statistika dhe analiza. Zakonisht NGINX është në hyrje dhe të gjitha kërkesat kalojnë përmes tij. Pikërisht në këtë vend është shumë e përshtatshme të mbledhim. Mund të bëjmë ndonjë llogaritje menjëherë dhe ta dërgojmë diku, për shembull në Elasticsearch, Logstash, ose thjesht ta regjistrojmë në log dhe pastaj ta dërgojmë diku.
- Sistemet me përdorues të shumtë. Për shembull, lojrat online janë gjithashtu shumë të lehta për tu realizuar. Sot në Cape Town, Aleksandër Gladys do të tregojë se si të prototipojmë shpejt një lojë multiplayer përmes OpenResty.
- Filtrimi i kërkesave (WAF). Sot është bërë moden të krijosh firewalls për aplikacionet web, ka shumë shërbime që i ofrojnë ato. Me ndihmën e OpenResty, mund të krijosh një firewall për aplikacionet web, i cili do të filtrojë kërkesat sipas kërkesave tuaja në mënyrë të thjeshtë dhe të lehtë. Nëse ke Python, e kupton se PHP sigurisht nuk do të injektohet, nëse, sigurisht, nuk e nxjerr nga konsola diku. E di që ke MySQL dhe Python. Ndoshta, këtu mund të provojnë të bëjnë ndonjë kalim direkt të direktorive dhe të injektojnë diçka në bazën e të dhënave. Prandaj, është e mundur të filtrohen kërkesat e dyshimta shpejt dhe me kosto të ulët menjëherë në front.
- Bashkësia. Duke qenë se OpenResty është ndërtuar mbi bazën e NGINX, ai ka një avantazh - kjo është komuniteti NGINX. Ai është shumë i madh, dhe një pjesë e konsiderueshme e pyetjeve që do të kesh në fillim, tashmë janë zgjidhur nga komuniteti NGINX.
Zhvilluesit e Lua. Dje bisedova me djemtë që erdhën për ditën e mësimeve HighLoad++ dhe dëgjova se Tarantool është e vetmja që është shkruar në Lua. Kjo nuk është e vërtetë, në Lua janë shkruar shumë gjëra. Shembuj: OpenResty, serveri XMPP Prosody, motorin e lojërave Love2D, Lua script-izohet në Warcraft dhe në vende të tjera. Ka shumë zhvillues të Lua, ata kanë një komunitet të madh dhe të përgjegjshëm. Të gjitha pyetjeve të mia për Lua u përgjigjën brenda disa orësh. Kur shkruan në listën e shpërndarjes, praktikisht pas disa minutash tashmë ka një mori përgjigjesh, shpjegojnë çfarë dhe si, çfarë është çfarë. Kjo është shumë e shkëlqyer. Fatkeqësisht, nuk është gjithmonë një komunitet kaq të mirëpritës.
Për OpenResty ka GitHub, atje mund të hapësh një çështje nëse diçka ka dështuar. Ka një listë shpërndarjeje në Google Groups, ku mund të diskutosh pyetje të përgjithshme, ka një shpërndarje në kinezisht - ndoshta, ndoshta nuk ke njohuri të mjaftueshme në anglisht, por di dhe kinezisht.
Përfundime
- Shpresoj se kam arritur të shpjegoj se OpenResty është një framework shumë i përshtatshëm, i fokusuar në web.
- Ai ka një nivel të ulët të hyrjes, pasi kodi është i ngjashëm me atë në të cilën shkruajmë, gjuha është mjaft e thjeshtë dhe minimalistike.
- Ai ofron I/O asinkron pa callbacks, nuk do të kemi ngatërrim, siç mund ta shkruajmë ndonjëherë në NodeJS.
- Ai ka një deploy të lehtë, pasi na nevojitet vetëm NGINX me modulin e nevojshëm dhe kodi ynë, dhe gjithçka funksionon menjëherë.
- Një komunitet i madh dhe i përgjegjshëm.
Nuk i kam folur në detaje se si bëhet rrugëzgjidhja, rezultoi se ishte një histori shumë e gjatë.
Faleminderit për vëmendjen!

Burimi: habr.com
