What Is the Difference Between OpenResty and NGINX?

API7.ai

September 9, 2022

OpenResty (NGINX + Lua)

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

Процесс разработки OpenResty

OpenResty не создавался с нуля, как другие языки разработки, а основан на зрелых открытых компонентах — NGINX и LuaJIT. OpenResty появился в 2007 году, но его первая версия не использовала Lua, а Perl, что во многом связано с техническими предпочтениями автора.

Однако производительность Perl далека от требований, поэтому во второй версии Perl был заменён на Lua. Тем не менее, в официальном проекте OpenResty Perl всё ещё играет важную роль. Проекты экосистемы OpenResty создаются с использованием Perl, такие как тестовый фреймворк, Linter, CLI и другие. Мы будем постепенно знакомиться с ними позже.

Благодаря высокой производительности и динамическим преимуществам OpenResty, он идеально подходит для нужд CDN-бизнеса, и вскоре стал техническим стандартом для CDN. Более того, благодаря богатым библиотекам lua-resty-*, OpenResty начал постепенно выходить из тени NGINX и формировать свою экосистему, которая широко используется в API-шлюзах, программных WAF и других областях.

Я часто говорю, что OpenResty — это широко используемая технология, но не популярная, что звучит противоречиво. Что это значит?

Он широко используется, потому что OpenResty сейчас является пятым по популярности веб-сервером в мире.

Он не популярен, потому что доля использования OpenResty для построения бизнес-систем невелика. Большинство пользователей используют OpenResty для обработки входящего трафика, не углубляясь в бизнес-логику. Поэтому, естественно, использование OpenResty остаётся поверхностным и достаточным для текущих нужд. Это, конечно, также связано с отсутствием у OpenResty зрелых веб-фреймворков и экосистем, как у Java и Python.

Сказав так много, далее я сосредоточусь на нескольких аспектах, которые делают OpenResty достойным похвалы и изучения.

Основные моменты OpenResty

Подробная документация и тестовые примеры

Да, документация и тестирование — это ключевые показатели надёжности открытого проекта, даже важнее качества кода и производительности.

Документация OpenResty очень подробна, и автор описал каждый момент, на который стоит обратить внимание. В большинстве случаев нам достаточно внимательно изучить документацию, чтобы решить проблему, не прибегая к поиску в Google или анализу исходного кода. Для удобства OpenResty также поставляется с инструментом командной строки restydoc, который помогает просматривать документацию через оболочку, не прерывая процесс кодирования.

Однако в документации доступно лишь несколько фрагментов кода, и нет полных и сложных примеров. Где же найти такие примеры?

Для OpenResty это, естественно, каталог /t, который содержит все тестовые примеры. Каждый тестовый пример включает полную конфигурацию NGINX и код на Lua, а также тестовые входные данные и ожидаемые результаты. Однако тестовый фреймворк OpenResty полностью отличается от других фреймворков с утверждениями, о чём я расскажу позже в отдельной главе.

Синхронное неблокирующее выполнение

Корутины — это новая функция, которую многие скриптовые языки добавили в последние годы для повышения производительности. Но они не идеально реализованы: некоторые являются синтаксическим сахаром, а другие требуют явного объявления ключевых слов.

OpenResty поддерживает корутины с самого начала и реализует синхронную неблокирующую модель программирования. Это важно, потому что программисты — тоже люди, и код должен быть более близок к человеческому мышлению. Явные обратные вызовы и ключевые слова async прерывают мышление и затрудняют отладку.

Так что же такое синхронное неблокирующее выполнение? Давайте сначала поговорим о синхронности. Это очень просто: выполнение происходит последовательно в соответствии с кодом. Например, следующий псевдокод:

local res, err = query-mysql(sql) local value, err = query-redis(key)

В одном запросе, если нам нужно дождаться возврата результата запроса MySQL, прежде чем продолжить запрос к Redis, это синхронное выполнение; если нам не нужно ждать возврата MySQL и мы можем продолжить запрос к Redis, то это асинхронное выполнение. Для OpenResty большинство операций являются синхронными. Только API, связанные с фоновыми таймерами, такие как ngx.timer, являются асинхронными операциями.

Что касается неблокирующего выполнения, это концепция, которую легко спутать с асинхронностью. Когда мы говорим о блокировке здесь, мы имеем в виду блокировку потока операционной системы. Продолжим рассматривать приведённый выше пример, предположим, что запрос к MySQL занимает 1s. Если в течение этих 1s ресурсы операционной системы (CPU) простаивают и просто ждут возврата, это блокирующее выполнение; если CPU использует это время для обработки других запросов, это неблокирующее выполнение. Неблокирующее выполнение также является ключом к реализации высокой конкуренции, такой как C10K и C100K.

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

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

Динамичность

Огромное преимущество OpenResty, которое ещё не полностью раскрыто, — это его динамичность.

Традиционные веб-серверы, такие как NGINX, требуют от нас изменения конфигурационного файла на диске и его перезагрузки для вступления изменений в силу, поскольку они не предоставляют API для управления поведением во время выполнения. Поэтому в микросервисах, требующих частых изменений, NGINX пробовал много раз, но ничего не улучшилось. И внезапное появление Envoy с динамическим API управления xDS представляет серьёзную угрозу для NGINX.

В отличие от NGINX и Envoy, OpenResty управляется скриптовым языком Lua, и динамичность — это естественное преимущество Lua. Например, через API Lua, предоставляемый в модуле lua-nginx-module в OpenResty, мы можем динамически управлять маршрутами, апстримами, SSL-сертификатами, запросами, ответами и т.д. Более того, мы можем изменять логику обработки бизнеса без перезапуска OpenResty, не ограничиваясь API Lua, предоставляемым OpenResty.

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

Овладев этой магической способностью, OpenResty расширил свою область компетенции и воображения на другие области, такие как Serverless и Edge computing.

Что следует изучать?

После стольких ключевых особенностей OpenResty, что же нам следует изучать? Я предпочитаю сосредоточиться на основной линии, а не хвататься за всё подряд, чтобы построить систему знаний с чёткой структурой.

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

Возвращаясь к изучению OpenResty, на мой взгляд, если вы хотите хорошо изучить OpenResty, вам следует понять следующие восемь ключевых моментов:

  • Синхронная неблокирующая модель программирования
  • Роль различных фаз Request/Response
  • Различия между LuaJIT и Lua
  • API OpenResty и окружающие библиотеки
  • Корутины и cosocket
  • Фреймворк для модульного тестирования и инструменты для тестирования производительности
  • Флеймграфы и связанные инструменты
  • Оптимизация производительности

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

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

Если вы используете OpenResty в своём проекте, это замечательно! Однако я уверен, что когда вы прочитаете главы о LuaJIT и оптимизации производительности, у вас будет больше резонанса и практических применений, и вы увидите улучшение производительности до и после оптимизации в вашем проекте.

Кроме того, если вы хотите внести вклад в код OpenResty и окружающие библиотеки, самым большим барьером будет не понимание принципов OpenResty или написание модулей NGINX на C, а тестовые примеры и стандарты кода. Я видел слишком много контрибьюторов OpenResty (включая себя), которые многократно изменяли тестовые примеры и стили кода в PR, и существует слишком много негласных правил. Поэтому разделы курса о стандартах кода и модульном тестировании предназначены для вас.

И если вы инженер по качеству, даже если вы не используете OpenResty, тестовый фреймворк и набор инструментов для анализа производительности OpenResty дадут вам много вдохновения. В конце концов, вложения и накопления OpenResty в тестировании довольно глубоки.

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