- PVSM.RU - https://www.pvsm.ru -

Nginx-переменные с njs: просто, безболезненно и через JavaScript

njs — это JavaScript-интерпретатор в легковесном веб-сервере, с помощью которого можно создавать новые nginx-переменные и обработчики стадий запроса. Чем njs хорош? Чего не умеет? И зачем вообще его сделали? На эти и другие вопросы ответит Дмитрий Волынцев (xeioex [1]), разработчик nginx и основной разработчик интерпретатора njs.

Nginx-переменные с njs: просто, безболезненно и через JavaScript - 1

— Дмитрий, зачем понадобился скриптинг в конфигах nginx?

— Первая причина — директива if. Люди, которые первый раз ее увидели, думают, что можно использовать ее императивно. На самом деле это не так — конфигурация nginx является декларативной. В примере ниже можно подумать, что в ответе будут два header: X-First и X-Second. Но в ответ попадет только второй header, потому что так устроен nginx: если мы напишем две if-директивы, то выберется самая последняя.

location /only-one-if {
    set $true 1;

    if ($true) {
        add_header X-First 1;
    }

    if ($true) {
        add_header X-Second 2;
    }


Вторая причина — то, к чему nginx пришел сейчас. Раньше он использовался для кэширования статики и запросов, а также балансировки нагрузки — классический набор прокси. Распространение микросервисов размыло сферу применения nginx. Если раньше настройка конфигураций заканчивалась на паре location на нескольких бэкендах на каких-то языках, то с микросервисной архитектурой у нас появляется больше движущихся частей. Бэкенд превратился в кучу маленьких компонентов. Логику авторизации, например, необходимо дублировать на каждом микросервисе или выносить ее, скажем, на фронтенд. Чтобы реализовать продвинутую авторизацию, встроенных механизмов решения в nginx хватает не всегда.

В-третьих, в nginx многие директивы принимают динамически вычисляемые выражения, например:

proxy cache bypass   $cookie_nocache $arg_nocache;

Вы можете сделать конкатенацию переменных друг с другом или с литеральными строками. Но этого недостаточно, и хотелось бы иметь более мощные инструменты, например, для вычисления хэша, для работы с числовыми данными, для приведения к верхнему и нижнему регистру.

Чтобы расширить все узкие места в nginx, нужно либо разработать свой синтаксис, либо использовать что-то готовое. Мы пришли к выводу, что лучше всего взять уже имеющийся скриптовой язык программирования. Таким образом, разработчикам не нужно учить новый язык, что также сэкономит время и понизит порог входа. Мы выбрали JavaScript.

— А почему именно JavaScript?

— Мы выбрали JavaScript по нескольким причинам:

  • Современный диалект, что хорошо для разработчиков, переходящих с других языков.
  • С-подобный стиль. Это важно, потому что в конфиге nginx используются фигурные скобки, и в будущем мы хотим добавить возможность написания кода на JS прямо внутри конфига. Фигурные скобки нам в этом помогут. В Lua, например, роль фигурных скобок выполняют begin и end — это неудобно.
  • Модель JavaScript хорошо ложится на архитектуру nginx.

— Значит, Lua тоже рассматривали? Неужели из-за begin и end?

— Уже существует готовый сторонний проект OpenResty. Если не вдаваться в подробности, то это, по сути, nginx + Lua, но он имеет архитектуру, которая идет вразрез с nginx. Мы хотели избежать пересечений с этой экосистемой. Кроме того, есть еще несколько причин:

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

— Как njs работает в сравнении с конкурентами?

— Мы оценили njs в сравнении с известными движками — V8 и SpiderMonkey. Они неэффективны для задач внутри nginx, потому что заточены под браузеры и очень тяжеловесны, а nginx необходима высокая скорость работы. Кроме того, оба этих движка быстро эволюционируют, их API нестабилен. Наконец, njs может более эффективно встраиваться в nginx:

Nginx-переменные с njs: просто, безболезненно и через JavaScript - 2
Количество контекстов, создаваемых в секунду

— Какие стандарты поддерживает njs?

— На данный момент реализованы практически все основные элементы спецификации ECMAScript 5.1 с некоторым вкраплением элементов спецификаций 6 и 7. То есть стандартные объекты типа Object, Array, String, Number, Date, RegExp, JSON. Полноценно поддерживаются замыкания, анонимные функции, работа с исключениями.

Мы не ставим своей первоочередной целью полное соответствие спецификации языка. Так что на данный момент отсутствует поддержка eval(), и пока что добавлять ее мы не планируем. Зато планируем добавить поддержку ключевых слов const и let, а также стрелочных функций.

Nginx-переменные с njs: просто, безболезненно и через JavaScript - 3
Что умеет и чего не умеет njs на данный момент

Важно упомянуть еще кое-что: отсутствие сборки мусора. Большинство современных языков самостоятельно следят за временем жизни объектов. Если объект больше не используется, то он автоматически удаляется. Без этого механизма нельзя обойтись, но обычно для него приходится чем-то жертвовать — работа программы замедляется или вообще приостанавливается. В njs память не освобождается до тех пор, пока объект запроса не будет освобожден.

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

— Чем njs не является?

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

Теперь непосредственно сам вопрос. Что стоит заранее учитывать?

  • njs — это не замена Node.js.
  • Связка nginx + njs — это не application server.
  • njs не реализует полноценно стандарты ECMAScript, поскольку здесь нет поддержки eval().


Если для вас эта тема крайне актуальна и вы жаждите больше деталей, рекомендуем посмотреть видеозаписью доклада Дмитрия Волынцева на HighLoad++ Siberia 2018, где он раскрыл ее со всех сторон.

Также мы приглашаем всех профи к подаче своих докладов на ноябрьскую конференцию HighLoad++ 2018 [2], которая пройдет в Сколково 8 и 9 ноября. Если у вас есть уникальный и интересный опыт и вы готовы им поделиться — до 1 сентября регистрируйтесь и заполняйте форму [3].

Если боитесь выступать публично — у нас есть так называемая школа докладчиков [4], где мы бесплатно помогаем прокачивать эти скилы.

Автор: Олег Бунин

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/289773

Ссылки в тексте:

[1] xeioex: https://habr.com/users/xeioex/

[2] HighLoad++ 2018: http://www.highload.ru/moscow/2018

[3] форму: https://conf.ontico.ru/lectures/propose/?conference=hl2018

[4] школа докладчиков: https://habr.com/company/oleg-bunin/blog/345698/

[5] Источник: https://habr.com/post/420465/?utm_source=habrahabr&utm_medium=rss&utm_campaign=420465