OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacjiPonownie publikujemy zapis relacji z konferencji Wysokie obciążenie++ 2016, która odbyła się w Skołkowie pod Moskwą w dniach 7-8 listopada ubiegłego roku. Władimir Protasow opowiada, jak rozszerzyć funkcjonalność NGINX za pomocą OpenResty i Lua.

Witam wszystkich, nazywam się Władimir Protasow, pracuję dla Parallels. Opowiem Ci trochę o sobie. Trzy czwarte mojego życia spędzam na pisaniu kodu. Zostałem programistą do szpiku kości w dosłownym tego słowa znaczeniu: czasami widzę kod w snach. Jedna czwarta życia to rozwój przemysłu i pisanie kodu, który trafia bezpośrednio do produkcji. Kod, którego niektórzy z Was używają, ale o nim nie wiedzą.

Żeby dać ci znać, jak źle było. Kiedy byłem młodszy, przyszedłem i dali mi te dwie terabajtowe bazy danych. Teraz jest dostępny dla każdego. Chodziłem na konferencje i pytałem: „Chłopaki, powiedzcie mi, czy macie big data, czy wszystko jest w porządku? Ile masz tam baz? Odpowiedzieli mi: „Mamy 100 gigabajtów!” Powiedziałem: „Świetnie, 100 gigabajtów!” I pomyślałem, jak zgrabnie zachować pokerową twarz. Myślisz, że tak, chłopaki są fajni, a potem wracasz i majstrujesz przy tych wieloterabajtowych bazach danych. I to jest bycie juniorem. Wyobrażacie sobie, jaki to hit?

Znam ponad 20 języków programowania. Tego właśnie musiałem się dowiedzieć w trakcie pracy. Dają ci kod w Erlangu, w C, w C++, w Lua, w Pythonie, w Ruby, w czymś innym i musisz to wszystko wyciąć. Generalnie musiałem. Nie udało się obliczyć dokładnej liczby, ale gdzieś około 20 liczba ta zaginęła.

Ponieważ wszyscy tutaj wiedzą, czym jest Parallels i czym się zajmujemy, nie będę mówił o tym, jacy jesteśmy fajni i co robimy. Powiem tylko, że mamy 13 biur na całym świecie, ponad 300 pracowników, rozwój w Moskwie, Tallinie i na Malcie. Jeśli chcesz, możesz zabrać i przenieść się na Maltę, jeśli w zimie jest zimno i potrzebujesz ogrzać plecy.

Konkretnie nasz dział pisze w Pythonie 2. Prowadzimy biznes i nie mamy czasu na wprowadzanie modnych technologii, więc cierpimy. Mamy Django, bo ma wszystko, a nadmiar wzięliśmy i wyrzuciliśmy. Również MySQL, Redis i NGINX. Mamy też wiele innych fajnych rzeczy. Mamy MongoDB, biegają po nas króliki, po prostu nie mamy nic - ale to nie jest moje i ja tego nie robię.

OtwórzResty

Opowiedziałem o sobie. Zobaczmy, o czym dzisiaj będę mówić:

  • Co to jest OpenResty i z czym się go spożywa?
  • Po co wymyślać koło na nowo, skoro mamy Python, NodeJS, PHP, Go i inne fajne rzeczy, z których wszyscy są zadowoleni?
  • I kilka przykładów z życia wziętych. Musiałem mocno skrócić raport, bo dostałem go na 3,5 godziny, więc przykładów będzie niewiele.

OpenResty to NGINX. Dzięki niemu mamy pełnoprawny serwer WWW, który jest dobrze napisany, działa szybko. Myślę, że większość z nas używa NGINX w produkcji. Wszyscy wiecie, że jest szybki i fajny. Zrobili w nim fajne synchroniczne wejścia/wyjścia, więc nie musimy niczego cyklicznie uruchamiać w taki sam sposób, w jaki gevent był uruchamiany w Pythonie. Gevent jest fajny, fajny, ale jeśli napiszesz kod w C i coś pójdzie nie tak z gevent, oszalejesz, debugując go. Mam doświadczenie: ustalenie, co poszło nie tak, zajęło całe dwa dni. Gdyby ktoś wcześniej kilka tygodni wcześniej nie kopał, nie znalazł problemu, nie napisał go w internecie, a Google go nie znalazł, to byśmy kompletnie oszaleli.

NGINX już obsługuje buforowanie i zawartość statyczną. Nie trzeba się martwić, jak to zrobić po ludzku, żeby gdzieś nie zwolnić, żeby gdzieś nie zgubić deskryptorów. Nginx jest bardzo wygodny we wdrożeniu, nie musisz myśleć o tym, co zabrać - WSGI, PHP-FPM, Gunicorn, Unicorn. Zainstalowano Nginx, przekazano administratorom, oni wiedzą, jak z nim pracować. Nginx przetwarza żądania w uporządkowany sposób. Porozmawiam o tym nieco później. Krótko mówiąc, ma fazę, kiedy właśnie przyjął żądanie, kiedy przetworzył i kiedy przekazał treść użytkownikowi.

Nginx jest fajny, ale jest jeden problem: nie jest wystarczająco elastyczny nawet przy tych wszystkich fajnych funkcjach, które chłopaki wepchnęli do konfiguracji, mimo że można go dostosować. Ta moc nie wystarczy. Dlatego chłopaki z Taobao pewnego razu, myślę, że jakieś osiem lat temu, wbudowali w to Luę. Co on daje?

  • Rozmiar. To jest małe. LuaJIT zapewnia około 100-200 kilobajtów narzutu pamięci i minimalny narzut wydajności.
  • prędkość. Interpreter LuaJIT w wielu sytuacjach jest blisko C, w niektórych sytuacjach przegrywa z Javą, w innych ją wyprzedza. Przez pewien czas uznawano go za najnowocześniejszy i najfajniejszy kompilator JIT. Teraz są chłodniejsze, ale są bardzo ciężkie, na przykład ten sam V8. Niektóre interpretery JS i Java HotSpot są w niektórych momentach szybsze, ale w niektórych miejscach nadal przegrywają.
  • Łatwe do nauki. Jeśli masz, powiedzmy, bazę kodu Perla i nie dokonujesz rezerwacji, nie znajdziesz programistów Perla. Ponieważ ich tam nie ma, wszyscy zostali zabrani, a nauczanie ich jest długie i trudne. Jeśli chcesz programistów do czegoś innego, być może trzeba ich będzie przeszkolić lub znaleźć. W przypadku Lua wszystko jest proste. Lua może nauczyć się każdy junior w trzy dni. Rozpracowanie tego zajęło mi jakieś dwie godziny. Dwie godziny później pisałem już kod w fazie produkcyjnej. Około tydzień później poszedł prosto do produkcji i wyszedł.

W efekcie wygląda to tak:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Jest tu dużo. OpenResty zgromadził kilka modułów, zarówno luash, jak i silniki. I masz wszystko gotowe - wdrożone i działające.

Примеры

Dość tekstów, przejdźmy do kodu. Oto mały Hello World:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Co tam jest? to jest lokalizacja silników. Nie martwmy się, nie piszemy własnego routingu, nie bierzemy jakiegoś gotowego – mamy to już w NGINX, żyjemy dobrze i leniwie.

content_by_lua_block to blok mówiący, że udostępniamy treść za pomocą skryptu Lua. Bierzemy zmienną silnika remote_addr i wsuń go string.format. To jest to samo co sprintf, tylko w Lua, tylko poprawne. I dajemy to klientowi.

W rezultacie będzie to wyglądać następująco:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Ale wróćmy do prawdziwego świata. W środowisku produkcyjnym nikt nie wdraża Hello World. Nasza aplikacja zazwyczaj trafia do bazy danych lub gdzie indziej i przez większość czasu czeka na odpowiedź.

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Po prostu siedzi i czeka. To nie jest zbyt dobre. Kiedy przychodzi 100.000 XNUMX użytkowników, jest nam bardzo ciężko. Dlatego jako przykład posłużymy się prostą aplikacją. Będziemy szukać obrazków np. kotów. Tylko, że nie będziemy po prostu szukać, rozszerzymy słowa kluczowe i jeśli użytkownik wyszukał „kocięta”, znajdziemy koty, puszyste i tak dalej. Najpierw musimy uzyskać dane żądania z backendu. To wygląda tak:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Dwie linie pozwalają na pobranie parametrów GET bez żadnych komplikacji. Następnie uzyskujemy te informacje na przykład z bazy danych zawierającej tabelę według słowa kluczowego i rozszerzenia za pomocą zwykłego zapytania SQL. Wszystko jest proste. To wygląda tak:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Łączymy bibliotekę resty.mysql, który mamy już w zestawie. Nie musimy niczego instalować, wszystko jest gotowe. Określ sposób nawiązania połączenia i wykonania zapytania SQL:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

To trochę przerażające, ale działa. Tutaj 10 jest granicą. Wyciągamy 10 płyt, jesteśmy leniwi, nie chcemy pokazywać więcej. W SQL zapomniałem o limicie.

Następnie znajdujemy obrazy dla wszystkich zapytań. Zbieramy kilka żądań i wypełniamy tabelę Lua o nazwie reqs, i robić ngx.location.capture_multi.

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Wszystkie te prośby idą równolegle, a odpowiedzi są do nas zwracane. Czas działania jest równy czasowi odpowiedzi najwolniejszego. Jeśli wszyscy odpiszemy w ciągu 50 milisekund i wysłaliśmy sto próśb, odpowiedź otrzymamy w ciągu 50 milisekund.

Ponieważ jesteśmy leniwi i nie chcemy pisać obsługi HTTP i buforowania, sprawimy, że NGINX zrobi wszystko za nas. Jak widziałeś, była prośba o url/fetch, tutaj jest:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Robimy proste proxy_pass, określ, gdzie buforować, jak to zrobić i wszystko działa dla nas.

Ale to nie wystarczy, musimy jeszcze przekazać dane użytkownikowi. Najprostszym pomysłem jest łatwe serializowanie wszystkiego do formatu JSON w dwóch wierszach. Podajemy typ zawartości, podajemy JSON.

Ale jest jedna trudność: użytkownik nie chce czytać JSON. Musimy przyciągnąć programistów front-end. Czasami na początku nie mamy ochoty tego robić. Tak, a specjaliści SEO powiedzą, że jeśli szukamy zdjęć, to ich to nie obchodzi. A jeśli podamy im jakąś treść, powiedzą, że nasze wyszukiwarki niczego nie indeksują.

Co z tym zrobić? Oczywiście przekażemy użytkownikowi kod HTML. Generowanie za pomocą uchwytów nie jest popularne, dlatego chcemy używać szablonów. Jest do tego biblioteka lua-resty-template.

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Musiałeś widzieć trzy przerażające litery OPM. OpenResty ma własnego menedżera pakietów, za pomocą którego możesz zainstalować wiele różnych modułów, w szczególności: lua-resty-template. Jest to prosty silnik szablonów podobny do szablonów Django. Tam możesz napisać kod i dokonać podstawienia zmiennych.

W rezultacie wszystko będzie wyglądać mniej więcej tak:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Wzięliśmy dane i ponownie wyrenderowaliśmy szablon w dwóch wierszach. Użytkownik jest zadowolony, ma koty. Ponieważ rozszerzyliśmy prośbę, otrzymał także fokę dla kociąt. Nigdy nie wiadomo, może tego szukał, ale nie potrafił poprawnie sformułować swojej prośby.

Wszystko jest w porządku, ale jesteśmy w fazie rozwoju i nie chcemy jeszcze pokazywać użytkownikom. Zróbmy autoryzację. Aby to zrobić, zobaczmy, jak NGINX obsługuje żądanie w zakresie OpenResty:

  • Pierwsza faza - dostęp, kiedy użytkownik właśnie przyszedł i patrzyliśmy na niego po nagłówkach, adresie IP i innych danych. Można go od razu odciąć, jeśli nam się nie spodoba. Można to wykorzystać do autoryzacji lub jeśli otrzymamy wiele żądań, możemy je łatwo pociąć na tym etapie.
  • przepisać. Przepisanie niektórych danych żądania.
  • zawartość. Dajemy treść użytkownikowi.
  • filtr nagłówkowy. Zmień nagłówki odpowiedzi. Gdybyśmy użyli proxy_pass, możemy przepisać niektóre nagłówki przed przekazaniem ich użytkownikowi.
  • filtr ciała. Możemy zmienić ciało.
  • log - Logowanie. Możliwe jest pisanie logów w Elasticsearch bez dodatkowej warstwy.

Nasza autoryzacja będzie wyglądać mniej więcej tak:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Dodamy to do tego location, który opisaliśmy wcześniej i umieść tam następujący kod:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Sprawdzamy, czy mamy token cookie. Jeśli nie, to rzucamy na autoryzację. Użytkownicy są przebiegli i mogą odgadnąć, że należy ustawić token cookie. Dlatego umieścimy to również w Redis:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Kod do pracy z Redisem jest bardzo prosty i nie różni się od innych języków. Jednocześnie całe wejście/wyjście, co tam jest, co tu jest, nie blokuje się. Jeśli napiszesz kod synchroniczny, będzie on działał asynchronicznie. Podobnie jak w przypadku gevent, tylko dobrze zrobione.

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Zróbmy samą autoryzację:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Mówimy, że musimy przeczytać treść żądania. Otrzymujemy argumenty POST, sprawdzamy czy login i hasło są poprawne. Jeżeli jest niepoprawny to rzucamy na autoryzację. A jeśli są poprawne, to zapisujemy token do Redis:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Nie zapomnij ustawić pliku cookie, odbywa się to również w dwóch liniach:

OpenResty: zmiana NGINX w pełnoprawny serwer aplikacji

Przykład jest prosty, spekulacyjny. Oczywiście nie będziemy realizować usługi pokazywania kotów ludziom. Ale kto nas zna. Przyjrzyjmy się więc, co można zrobić na produkcji.

  • Minimalistyczny backend. Czasami musimy przekazać do backendu całkiem sporo danych: gdzieś musimy podstawić datę, gdzieś wyświetlić jakąś listę, powiedzieć, ilu użytkowników jest obecnie na stronie, wkręcić licznik lub statystyki. Coś tak małego. Niektóre minimalne elementy można wykonać bardzo łatwo. To będzie szybkie, łatwe i świetne.
  • Wstępne przetwarzanie danych. Czasami chcemy osadzić reklamy na naszej stronie i przyjmujemy te reklamy wraz z żądaniami API. Tutaj jest to bardzo łatwe. Nie ładujemy naszego backendu, który już ciężko pracuje. Tutaj możesz odebrać i odebrać. Możemy coś uformować w JS-ie lub odwrotnie, odkleić, przetworzyć coś przed oddaniem użytkownikowi.
  • Fasada dla mikroserwisów. To również bardzo dobry przypadek, zastosowałem go. Wcześniej pracowałem dla Tenzor, firmy zajmującej się raportowaniem elektronicznym, która zapewnia raportowanie dla około połowy podmiotów prawnych w kraju. Stworzyliśmy usługę, wiele rzeczy robi się tam przy użyciu tego samego mechanizmu: routing, autoryzacja i inne.
    OpenResty można wykorzystać jako spoiwo dla mikrousług, aby zapewnić pojedynczy dostęp do wszystkiego i jeden interfejs. Ponieważ mikrousługi można napisać w taki sposób, że mamy tu Node.js, tu mamy PHP, tu mamy Pythona, jest tu coś z Erlanga, rozumiemy, że nie chcemy wszędzie przepisywać tego samego kodu. Dlatego OpenResty można podłączyć z przodu.

  • Statystyka i analityka. Zwykle NGINX znajduje się przy wejściu i wszystkie żądania przechodzą przez nie. To w tym miejscu bardzo wygodnie jest zbierać. Można od razu coś policzyć i gdzieś wrzucić, np. do tego samego Elasticsearch, Logstash, albo po prostu zapisać to do logu i potem gdzieś wysłać.
  • Systemy dla wielu użytkowników. Na przykład gry online są również bardzo dobre. Dziś w Kapsztadzie Alexander Gladysh opowie Wam, jak szybko stworzyć prototyp gry wieloosobowej przy użyciu OpenResty.
  • Filtrowanie żądań (WAF). Teraz modne jest tworzenie wszelkiego rodzaju zapór sieciowych dla aplikacji internetowych, istnieje wiele usług, które je zapewniają. Za pomocą OpenResty możesz samodzielnie stworzyć zaporę sieciową dla aplikacji internetowych, która w prosty i łatwy sposób będzie filtrować żądania zgodnie z Twoimi wymaganiami. Jeśli masz Pythona, to rozumiesz, że PHP na pewno nie zostanie ci wstrzyknięte, chyba że oczywiście odrodzisz go gdziekolwiek z konsoli. Wiesz, że masz MySQL i Python. Prawdopodobnie tutaj mogą spróbować przeszukać katalogi i wstawić coś do bazy danych. Dzięki temu możesz od razu szybko i tanio odfiltrować głupie żądania.
  • Społeczność. Ponieważ OpenResty opiera się na NGINX, ma to bonus - to jest społeczność NGINX. Jest bardzo duży i społeczność NGINX odpowiedziała już na wiele pytań, które będziesz mieć na początku.

    Programiści Lua. Wczoraj rozmawiałem z chłopakami, którzy przyszli na dzień szkoleniowy HighLoad++ i usłyszałem, że tylko Tarantool jest napisany w Lua. To nieprawda, wiele rzeczy jest napisanych w Lua. Przykłady: OpenResty, serwer Prosody XMPP, silnik gry Love2D, Lua jest napisany w Warcraft i gdzie indziej. Jest wielu programistów Lua, mają dużą i responsywną społeczność. Odpowiedzi na wszystkie moje pytania dotyczące Lua otrzymałem w ciągu kilku godzin. Kiedy piszesz na listę mailingową, dosłownie za kilka minut pojawia się już cała masa odpowiedzi, opisują co i jak, co jest co. Wspaniale. Niestety, taka szczera społeczność nie jest wszędzie.
    OpenResty ma GitHub, gdzie możesz otworzyć problem, jeśli coś się zepsuje. W Grupach dyskusyjnych Google istnieje lista mailingowa, na której można omawiać kwestie ogólne, jest lista mailingowa w języku chińskim – nigdy nie wiadomo, może nie mówisz po angielsku, ale znasz chiński.

Wyniki

  • Mam nadzieję, że udało mi się przekazać, że OpenResty to bardzo wygodny framework sieciowy.
  • Ma niski próg wejścia, ponieważ kod jest podobny do tego, co piszemy, język jest dość prosty i minimalistyczny.
  • Zapewnia asynchroniczne operacje we/wy bez wywołań zwrotnych, nie będziemy mieli makaronu, jak czasami możemy pisać w NodeJS.
  • Ma łatwe wdrożenie, bo wystarczy NGINX z odpowiednim modułem i naszym kodem i wszystko od razu działa.
  • Duża i responsywna społeczność.

Nie opisałem szczegółowo, jak odbywa się routing, okazało się, że to bardzo długa historia.

Dziękuję za uwagę!


Vladimir Protasov - OpenResty: przekształcanie NGINX w pełnoprawny serwer aplikacji

Źródło: www.habr.com

Dodaj komentarz