Подпроекты за OpenResty

API7.ai

September 12, 2022

OpenResty (NGINX + Lua)

Как извлечь код Lua из nginx.conf и сохранить его читаемым и поддерживаемым? Решение довольно простое. Давайте посмотрим, как это реализовать с помощью OpenResty.

Сначала создадим директорию с именем lua. Затем мы поместим в неё все файлы .lua.

$ mkdir lua $ cat lua/hello.lua ngx.say("hello, world")

Во-вторых, используем content_by_lua_block для замены content_by_lua_file в файле nginx.conf.

pid logs/nginx.pid; events { worker_connections 1024; } http { server { listen 8080; location / { content_by_lua_file lua/hello.lua; } } }

В-третьих, перезапустим службы OpenResty, и всё готово!

$ sudo kill -HUP `cat logs/nginx.pid`

Используя content_by_lua_file, мы можем обновлять файл Lua напрямую, вместо того чтобы обновлять nginx.conf. Однако возникают некоторые вопросы:

  1. Мы используем относительный путь в разделе content_by_lua_file lua/hello.lua. Как OpenResty находит фактический файл Lua?
  2. После изменения кода Lua нам нужно перезапустить OpenResty, чтобы изменения вступили в силу. Есть ли способ эффективно отлаживать код?
  3. Как добавить директорию, содержащую файлы Lua, в путь поиска OpenResty?

Я рекомендую вам подумать над этими вопросами, ответы на которые можно найти в официальной документации. Именно поэтому я всегда подчеркиваю важность документации.

Для первого вопроса: если указан относительный путь, то при запуске OpenResty он добавит префикс -p PATH из параметров командной строки запуска OpenResty и объединит его с относительным путем, чтобы получить абсолютный путь. Таким образом, OpenResty сможет легко найти файл Lua.

Вторая проблема заключается в том, что код Lua загружается при первом запросе и по умолчанию кэшируется. Поэтому каждый раз, когда вы изменяете исходный файл Lua, вам нужно перезагружать OpenResty, чтобы изменения вступили в силу. Вы можете избежать перезагрузки, отключив lua_code_cache в nginx.conf. Однако важно отметить, что этот метод можно использовать только временно для разработки и отладки. Если вы развертываете на продакшене, вы должны включить кэш. В противном случае это окажет значительное влияние на производительность.

Для последнего вопроса OpenResty предоставляет директиву lua_package_path, которая позволяет установить путь поиска для модулей Lua. Например, мы можем установить lua_package_path в $prefix/lua/?.lua;;:

  • $prefix — это -p PATH в параметрах запуска.
  • /lua/?.lua указывает на все файлы в директории Lua с суффиксом .lua.
  • Две последние точки с запятой представляют встроенный путь поиска кода.

Структура директорий после установки

После понимания первой программы "hello world" давайте углубимся и посмотрим, как выглядит структура директорий OpenResty после установки и какие файлы она содержит.

Сначала передадим опцию -V, чтобы узнать, где находится OpenResty. Для следующего результата я опустил множество параметров компиляции модулей, которые мы добавим позже:

$ openresty -V nginx version: openresty/1.13.6.2 built by clang 10.0.0 (clang-1000.10.44.4) built with OpenSSL 1.1.0h 27 Mar 2018 TLS SNI support enabled configure arguments: --prefix=/usr/local/Cellar/openresty/1.13.6.2/nginx ...

Я использую brew для установки OpenResty на моем Mac. Путь — /usr/local/Cellar/openresty/1.13.6.2/nginx, он может отличаться в вашей среде. Этот путь содержит директории bin, luajit, lualib, nginx, pod и другие. Важно понимать значение этих папок, чтобы лучше изучить OpenResty. Давайте рассмотрим их по очереди.

Первая важная директория — bin.

$ ll /usr/local/Cellar/openresty/1.13.6.2/bin total 320 -r-xr-xr-x 1 ming admin 19K 3 27 12:54 md2pod.pl -r-xr-xr-x 1 ming admin 15K 3 27 12:54 nginx-xml2pod lrwxr-xr-x 1 ming admin 19B 3 27 12:54 openresty -> ../nginx/sbin/nginx -r-xr-xr-x 1 ming admin 62K 3 27 12:54 opm -r-xr-xr-x 1 ming admin 29K 3 27 12:54 resty -r-xr-xr-x 1 ming admin 15K 3 27 12:54 restydoc -r-xr-xr-x 1 ming admin 8.3K 3 27 12:54 restydoc-index

Здесь находятся как CLI OpenResty resty, о котором мы упоминали в предыдущем разделе, так и основной исполняемый файл openresty, который на самом деле является символической ссылкой на nginx. Что касается других инструментов в директории, то, как и resty, они все являются Perl-скриптами.

Среди них opm — это инструмент управления пакетами, который позволяет нам управлять различными сторонними пакетами, о чем будет рассказано в отдельном разделе; а restydoc, старый друг из первого раздела, — это средство просмотра документации, предоставляемое OpenResty, которое позволяет нам просматривать документацию OpenResty и NGINX.

$ restydoc -s ngx.say $ restydoc -s proxy_pass

Два примера выше запрашивают API OpenResty и команды NGINX соответственно. restydoc — это инструмент, который очень полезен для серверных инженеров, сосредоточенных на разработке.

После просмотра директории bin перейдем к директории pod.

Сначала подчеркнем, что pod здесь не имеет ничего общего с концепцией pod в Kubernetes. Вместо этого pod — это язык разметки, используемый в Perl для написания документации для модулей Perl. Эта директория содержит документацию для OpenResty, NGINX, lua-resty-* и LuaJIT, которые связаны с restydoc, упомянутым ранее.

Далее идут знакомые директории NGINX и luajit. Они легко понятны. В основном они хранят исполняемые файлы и зависимости NGINX и LuaJIT и являются основой OpenResty. Многие говорят, что OpenResty основан на Lua, но это неточно. Как мы видим выше, OpenResty на самом деле основан на LuaJIT.

Фактически, на раннем этапе OpenResty поставлялся как с Lua, так и с LuaJIT, и мы могли решить, использовать ли Lua или LuaJIT, с помощью опций компиляции. Однако Lua постепенно устаревает, и поддерживается только более производительный LuaJIT.

Наконец, рассмотрим директорию lualib. Она содержит библиотеки Lua, используемые в OpenResty, и в основном разделена на две директории: ngx и resty.

  • Директория ngx содержит код Lua из официального проекта lua-resty-core, который представляет собой перереализацию API OpenResty на основе FFI. Я объясню в отдельной главе, зачем нам нужно перереализовывать его.
  • Директория resty содержит код Lua из различных проектов lua-resty-*, с которыми мы познакомимся далее.

Следуя традиции этого курса, на этом этапе я укажу источник этих директорий. Это также одна из радостей открытых проектов. Если вам нравится копать до конца, вы всегда найдете что-то интересное.

Вот скрипт упаковки OpenResty для CentOS, который содержит все упомянутые выше директории.

%files %defattr(-,root,root,-) /etc/init.d/%{name} /usr/bin/%{name} %{orprefix}/bin/openresty %{orprefix}/site/lualib/ %{orprefix}/luajit/* %{orprefix}/lualib/* %{orprefix}/nginx/html/* %{orprefix}/nginx/logs/ %{orprefix}/nginx/sbin/* %{orprefix}/nginx/tapset/* %config(noreplace) %{orprefix}/nginx/conf/* %{orprefix}/COPYRIGHT

Обзор проекта OpenResty

Когда речь заходит об OpenResty, мы думаем о lua-nginx-module. Да, этот модуль NGINX на C действительно является ядром OpenResty, но он не эквивалентен OpenResty. Многие инженеры называют OpenResty как ngx + lua, что также используется в книгах, публикуемых на технических конференциях. Это не совсем корректно и не поддерживается сообществом OpenResty.

Давайте поговорим о том, почему это так, и какие другие связанные проекты, кроме lua-nginx-module, есть в OpenResty.

Открыв домашнюю страницу проекта OpenResty на GitHub, вы увидите, что OpenResty содержит 68 публичных проектов, которые можно разделить на следующие семь категорий. Давайте кратко рассмотрим их, чтобы у вас сложилось предварительное представление и вы могли быстро изучить их.

Модули NGINX на C

Названия проектов OpenResty стандартизированы, и те, что названы *-nginx-module, являются модулями NGINX на C.

В OpenResty более 20 модулей на C, и мы можем найти их с помощью команды openresty -V, которую использовали в начале этого раздела.

$ openresty -V nginx version: openresty/1.13.6.2 built by clang 10.0.0 (clang-1000.10.44.4) built with OpenSSL 1.1.0h 27 Mar 2018 TLS SNI support enabled configure arguments: --prefix=/usr/local/Cellar/openresty/1.13.6.2/nginx --with-cc-opt='-O2 -I/usr/local/include -I/usr/local/opt/pcre/include -I/usr/local/opt/openresty-openssl/include' --add-module=../ngx_devel_kit-0.3.0 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2rc3 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.13 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../ngx_stream_lua-0.0.5 --with-ld-opt='-Wl,-rpath,/usr/local/Cellar/openresty/1.13.6.2/luajit/lib -L/usr/local/lib -L/usr/local/opt/pcre/lib -L/usr/local/opt/openresty-openssl/lib' --pid-path=/usr/local/var/run/openresty.pid --lock-path=/usr/local/var/run/openresty.lock --conf-path=/usr/local/etc/openresty/nginx.conf --http-log-path=/usr/local/var/log/nginx/access.log --error-log-path=/usr/local/var/log/nginx/error.log --with-pcre-jit --with-ipv6 --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_geoip_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-dtrace-probes --with-stream --with-stream_ssl_module --with-http_ssl_module

Здесь --add-module= указывает на модули OpenResty на C. Основные из них — это lua-nginx-module и stream-lua-nginx-module, первый из которых обрабатывает трафик уровня 7, а второй — трафик уровня 4.

Некоторые из этих модулей требуют особого внимания и не рекомендуются, хотя они по умолчанию компилируются в OpenResty. Например, redis2-nginx-module, redis-nginx-module и memc-nginx-module используются для взаимодействия с Redis и Memcached. Эти библиотеки на C рекомендовались OpenResty на раннем этапе, но были заменены на lua-resty-redis и lua-resty-memcached после добавления функции cosocket, и сейчас они поддерживаются неактивно.

В дальнейшем OpenResty не будет разрабатывать больше библиотек на C для NGINX, а сосредоточится на библиотеках Lua на основе cosocket, что является будущим.

Библиотеки lua-resty-*

Официальный репозиторий OpenResty содержит 18 библиотек lua-resty-*, включая Redis, MySQL, Memcached, WebSocket, DNS, управление трафиком, обработку строк, кэширование в процессе и другие стандартные библиотеки. Помимо официальных, есть и множество сторонних библиотек. Они очень важны, и мы уделим им больше времени в следующем разделе.

Самостоятельно поддерживаемая ветка LuaJIT

OpenResty поддерживает свою ветку LuaJIT в дополнение к собственному патчу OpenSSL. В 2015 году автор LuaJIT Майк Палл объявил о своем уходе на пенсию в поисках нового сопровождающего LuaJIT, но Майк не нашел подходящего сопровождающего. Сейчас он в основном занимается исправлением ошибок, а разработка новых функций приостановлена, поэтому OpenResty поддерживает свою ветку LuaJIT.

По сравнению с Lua, LuaJIT добавляет множество важных и уникальных функций, но не многие инженеры знают о них, поэтому это полускрытые навыки, которые я представлю позже.

Фреймворк для тестирования

Фреймворк для тестирования OpenResty — это test-nginx, также разработанный на Perl. Как видно из названия, он специально предназначен для тестирования проектов, связанных с NGINX. Все официальные тестовые случаи OpenResty для модулей на C и библиотек lua-resty управляются с помощью test-nginx. Это гораздо более мощная и независимая система, в отличие от обычных фреймворков на основе утверждений.

Некоторые участники OpenResty также не разобрались с этим фреймворком для тестирования и иногда отправляют PR, содержащие сложный код на C и Lua, но все же часто пугаются идеи написания соответствующих тестовых случаев. Поэтому, если вы посмотрели некоторые тестовые случаи в директории /t проекта OpenResty и все еще в замешательстве, не сомневайтесь в себе. Большинство людей такие же.

Помимо test-nginx, проект mockeagain имитирует медленную сеть, позволяя программам читать и записывать по одному байту за раз. Это очень полезный инструмент для веб-серверов.

Инструменты для отладки

Проект OpenResty потратил много усилий на то, как научно и динамически отлаживать код.

Два проекта OpenResty, openresty-systemtap-toolkit и stapxx, основаны на systemtap, инструменте динамической отладки и трассировки. Самое большое преимущество использования systemtap заключается в том, что он позволяет проводить анализ в реальном времени, при этом полностью не нарушая работу целевого приложения.

Например, systemtap похож на поход в больницу и проведение компьютерной томографии — безболезненно и незаметно. Еще лучше, что systemtap может генерировать визуальные графики пламени для анализа производительности, которые я опишу позже, а пока вот пример графика пламени, чтобы вы могли понять, о чем речь.

График пламени, связанный с OpenResty

Упаковка

Скрипты упаковки OpenResty для различных операционных систем (таких как CentOS, Ubuntu, macOS и т.д.) написаны вручную для лучшей управляемости. Когда мы рассматривали структуру директорий после установки, мы уже упоминали эти проекты, связанные с упаковкой: openresty-packaging и home-brew. Если вам интересно, вы можете изучить их самостоятельно, я не буду повторяться здесь.

Инженерные инструменты

Помимо этих крупных проектов, OpenResty имеет несколько инженерных инструментов, которые в основном скрыты.

Например, openresty-devel-utils — это набор инструментов для разработки OpenResty и NGINX. Конечно, они также разработаны на Perl, и большинство инструментов не документированы. Но для разработчиков OpenResty эти инструменты очень полезны. Я начну с нескольких и кратко представлю их.

  • lj-releng — это простой и эффективный инструмент для проверки кода LuaJIT, похожий на luacheck, который может находить потенциальные проблемы с глобальными переменными.
  • reindex, что означает перестроение индекса, — это инструмент для форматирования тестовых случаев test-nginx, переупорядочивания номеров тестовых случаев и удаления лишних пробелов. reindex — один из инструментов, которые разработчики OpenResty используют ежедневно.
  • opsboy используется для автоматизированного развертывания. Он используется для развертывания и запуска регрессионных тестов, которые OpenResty проводит на кластерах AWS EC2 перед каждым выпуском. Подробную информацию можно найти в официальной документации. opsboy — это DSL, реализованный на Perl. Авторы OpenResty любят создавать различные DSL для решения проблем.

Итог

Сегодня мы в основном изучили структуру директорий OpenResty после установки и некоторые подпроекты, стоящие за ним. После изучения сегодняшнего материала я надеюсь, что вы сможете больше узнать о проектах OpenResty. OpenResty вышел далеко за рамки балансировки нагрузки и обратного прокси NGINX и создал свою собственную экосистему. В следующий раз мы поговорим об этом подробнее.

Дополнительное чтение