Pull to refresh

Comments 26

еще несколько причин:
— Lua имеет pascal-подобный синтаксис.
— Массивы индексируются с 1.
— Lua — этой все-таки нишевый язык программирования.

веские причины, что бы начать все с нуля

Учитывая, что у nginx в последнее время новомодные бесплатные прокси откусывают все больше рынка, то маркетинг тоже важен.

— Массивы индексируются с 1.
веские причины, что бы начать все с нуля

как-то да :-)

JS это как-бы не совсем с нуля, если уж говорить честно и откровенно, а Lua — таки нишевый (на TIOBE он на 22 позиции ниже JS и уступает даже Fortran). Его единственный плюс — это JIT компиляция (которая нерелевантна для nginx), и на этом всё.

Мне почему-то думается, что любому кто имел дело только с C/C++/C#/Java/Perl/PHP (а это > 45% из наиболее популярных) JS будет намного понятней и проще чем Lua.

Единственный существенный минус JS — отсутствие эффективной работы с целыми числами (32/64 bit), но это тоже не очень релевантно в случае nginx. Хотя, если это + эффективная работа с целочисленными Array ((u)int 8/16/32/64) будет в njs добавлены, это будет просто супер для прокси-скриптинга.
с нуля не в плане языка (хотя судя по тексту тут своя реализация, которая наверняка будет иметь свои нюансы), а в плане готовых библиотек. Для Lua уже есть куча либ OpenResty именно под Nginx, для JS тоже есть тонны кода, но едва ли он будет полезен в рамках Nginx. Lua сильно проще ECMAScript в изучении, да со своими табличными тараканами, но сам синтаксис очень прост, едва ли вызывает трудности у любого программиста. Да он нишевый, но его ниша — быть встроенным в любое ПО.
Наличие либ для Lua поможет только тем кому нужны специфические задачи, ими решаемые. В большинстве случаев это простая логика под конкретные требования конкретного прокси, значит — сравнительно небольшой и уникальный (для каждого случая) код, который может состоять всего из двух-трёх десятков строк.

При таком раскладе человек вряд-ли захочет изучать новый язык (синтаксис это часть проблемы, структуры данных и среда — более неприятная часть) — проще тот который более похож на один из ему известных. Каким бы простым он не был — на изучение нужно время, которого обычно очень мало.
Язык lua практически близнец javascript и программирующие на js изучит его за несколько часов. Только вместо закрывающей фигурной скобки end. А begin в lua к слову сказать нет.
Короче, это как nginx_http_perl_module, только JS.
Perl невозможно было полноценно встроить, поэтому он всегда был в состоянии экспериментального и не развивался. С JS-модулем совсем другая история, это уже полноценный скриптиг с растущими от релиза к релизу возможностями.
Думаю, полноценность js-модуля будет ровно такой же как и у перла — парсить строки, выставлять хидеры, регекспы, md5 какой-нибудь посчитать…
Работа с файлами, базами, сетью на уровне конфига не предполагается.

Кстати, у этого js-модуля есть общая память хотя бы для процесса (а ещё лучше для всех воркеров)? У перла глобальные переменные общие для процесса, а возможно и заработает какой-то модуль shared memory для разных процессов, не пробовал.
>Кстати, у этого js-модуля есть общая память хотя бы для процесса (а ещё лучше для всех воркеров)?

На данный момент нет. Доступ к общей памяти процесса не предполагается. Тогда как мы думаем над тем как и в каком виде добавить функционал аналогичный ngxshareddict (глобальный словарь в разделяемой памяти доступный всем воркерам).

>Работа с файлами, базами, сетью на уровне конфига не предполагается.
Тут вы ошибаетесь. Работа с файлами уже есть (правда на данный момент блокирующая).
Чего в perl модуле нет так это асинхронного выполения кода, тогда как njs это уже есть в виде таймеров и асинхронных подзапросов (пример).

>Работа с файлами, базами, сетью на уровне конфига не предполагается.
Причем тут конфиг? Модель выполнения несколько другая. Вам доступно несколько хуков для различных фаз выполнения запроса где вы можете написать произвольный код который будет выполнятся для каждого запроса. Вот практический пример использования для openId Connect.
Причем тут конфиг?
Я имел ввиду, собственно, js_set — управлять переменными конфига, используя блокирующие операции на файлах, базе или сети, нельзя.

js_content другое дело, если получится сделать блокирующие операции асинхронными, то это позволит писать уже вполне продвинутые обработчики запросов и сделать из nginx фактически полноценный app-сервер.
>Я имел ввиду, собственно, js_set — управлять переменными конфига, используя блокирующие операции на файлах, базе или сети, нельзя.

тут проблема скорее не в njs, а в том что nginx не умеет асинхронно ждать пока переменная вычислится. Модули тупо зовут ngx_http_complex_value() для вычисление значения переменной (пример), и ожидают что она либо вычислится либо нет. Если сюда добавить некий NGX_AGAIN это все сломает в куче мест.
Работа с файлами, базами, сетью на уровне конфига не предполагается.

Это не так. Работа с файлами уже возможна, а с сетью возможна через подзапросы, но в дальнейшем планируются и другие возможности.

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

Другое дело обработчик запроса (а не установка переменной конфига), там проще сделать асинхронную обработку блокирующих операций, но все равно внедрять в nginx тяжелую логику не есть здравая идея — для этого есть лучшие инструменты.
А внедрить простую логику в обработчик запроса nginx-а иногда бывает очень полезно — убираются накладные расходы на проксирование, уменьшается задержка обработки запроса… Но для этого обычно и встроенного перла хватает )

Я вовсе не противник njs, но пока что он не предоставляет принципиальных преимуществ перед perl-модулем.
В конфигурации nginx все переменные работают и устанавливаются в рамках обработки запроса, а не при чтении конфигурации. Переменных на уровне конфигурации нет, она читается единожды на старте. И в этом смысле вообще никакой «асинхронный процессинг конфига» не требуется.

Я вовсе не противник njs, но пока что он не предоставляет принципиальных преимуществ перед perl-модулем.
Принципиальное приемущество в том, что njs — это решение пригодное для использования в продакшене под высокой нагрузкой, а Perl — нет. Когда интерпретатор Perl-а не может выделить себе память, он убивает весь nginx, поэтому использовать его можно только на свой страх и риск, в надежде, что памяти всегда хватит, особенно под высокой нагрузкой.
У перла много недостатков, банальный парсинг json в POST превращается в 3 экрана кода. На openresty это 3 строки. Да и вообще nginx по сути не умеет обрабатывать post, а также нет контроля вида «если post менее 30кб то обрабатывать»…

Вообще, новый вариант nginx тоже интересен, со встроенными интерпретаторами который.
У перла много недостатков, банальный парсинг json в POST превращается в 3 экрана кода.

Откуда там 3 экрана? JSON это две строки:
use JSON::XS;
$perl_hash_or_arrayref  = decode_json $utf8_encoded_json_text;


Если речь про ngx_http_perl, то обработка собственно POST займёт ещё несколько строк, на этом всё. Другой вопрос, насколько это стабильно, с учётом того что Perl в nginx до сих пор «experimental»…

Perl не умеет нормально обрабатывать ошибки и при любом удобном случае просто завершает весь процесс

Это неправда — Perl отлично умеет обрабатывать ошибки, просто некоторые привыкли писать как модули так и приложения где предпочитают завершать процесс в случае ошибок (djb style). Сделать приложение/модуль который будет вести себя корректно — вообще не проблема, достаточно эти самые ошибки обрабатывать.

Когда интерпретатор Perl-а не может выделить себе память, он убивает весь nginx...

Да, это одна из немногих ситуаций которую невозможно предотвратить простыми средствами в Perl (сюда также входят SIGSEGV/SIGFPE/SIGILL).

Но если уж дошло до нехватки памяти, то вполне логично убить весь процесс — ибо ситуация уже нестабильна, и скорее всего любое другое действие тоже приведет к проблемам (или будет периодически приводить пока система балансирует на границе голодания). Убийство процесса может либо стабилизировать ситуацию (он сошёл с ума и потёк, упершись в лимит, соответственно будет «чистым» после рестарта), либо дать системе время среагировать корректно.

Для embedded систем ситуация может быть иной, но в типичный сценариях frontend proxy или static file serving суицид — это единственно верное решение. Можно попытаться освободить буфера, уменьшить количество workers, etc — но это вряд-ли спасёт ситуацию (если нехватка глобальная, а не обусловленная лимитом на процесс). Опять-таки, при недостаче памяти можен начаться проблема с открытием файлов/сокетов, буферов для сокетов внутри ядра, etc — дело однозначно швах.
Но если уж дошло до нехватки памяти, то вполне логично убить весь процесс — ибо ситуация уже нестабильна, и скорее всего любое другое действие тоже приведет к проблемам (или будет периодически приводить пока система балансирует на границе голодания)


К сожалению, тут есть практическая проблема того что nginx использует разделяемую память между воркерами для многих задач. Киляние воркеров может оставить разделяемую память в несогласованном состоянии. Потом, например, приходят люди в рассылку и удивляются, почему у них перестало работать удаление устаревших файлов из кеше при превышении лимита или времени (реальная ситуация).

Сам nginx вполне себе справляется с ситуацией нехватки памяти и корректно её обрабатывает.
Это неправда — Perl отлично умеет обрабатывать ошибки, просто некоторые привыкли писать как модули так и приложения где предпочитают завершать процесс в случае ошибок (djb style).
Я имел в виду как раз ошибки выделения памяти.

Но если уж дошло до нехватки памяти, то вполне логично убить весь процесс — ибо ситуация уже нестабильна, и скорее всего любое другое действие тоже приведет к проблемам (или будет периодически приводить пока система балансирует на границе голодания).
Это логично в рамках одноразового скрипта, но абсолютно неприемлемо для веб-сервера в высоконагруженных системах. В nginx для корректной и максимально гладкой обработки ошибок выделения памяти проделано много работы. Под пиковыми нагрузками система может упереться во что угодно, в том числе в нехватку памяти, дескрипторов, места на жестком диске и при этом сервер должен продолжать держать нагрузку, завершая с ошибкой лишь часть запросов, которые превышают возможности системы. Падение в такие момент недопустимо.

Более того, ошибка выделения памяти может быть связана не с нехваткой памяти, а с ошибкой в коде или недостаточно качественной фильтрацией данных от пользователя. Как результат какой-то HTTP-запрос может приводить к попытке выделить гигантский объем памяти и это не должно ронять целиком сервер, а завершать ошибкой только один конкретный запрос.
UFO just landed and posted this here
Что вы именно под jit понимаете?
Если компиляцию в байт-код по типу CPython то да.
Если компиляцию в нативный код процессора то нет. JIT малоактуален, если у вас мало кода, или ваш код высокоуровневый (дергаете методы окружения, что как раз типично для кода на стороне прокси) потому что никакого преимущества вы от него не получите. Если же у вас, например, много математических расчетов то JIT будет кстати, но для этого есть другие инструменты.
Куда катится этот чертов мир?
Радует, что пока Линус жив, жаваскрипта не будет хотя бы в ядре.
Хотелось бы все же более подробно услышать про кейсы когда лучше openresty а когда njs.
При этом исходя из того что openresty все же уже используется широко и в некоторых высоконагружпнных проектах. Где будет njs лучше lua и в чем.
Sign up to leave a comment.