---
title: "Убийственная функция OpenResty: Динамичность - API7.ai"
description: "Openresty позволяет реализовать FaaS, Edge Computing, Dynamic Upstream и многое другое благодаря динамическим функциям, предоставляемым LuaJIT."
url: "https://api7.ai/ru/learning-center/openresty/openresty-killer-feature-dynamic"
---

# Убийственная функция OpenResty: Динамичность

API7.ai

January 12, 2023

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

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

Начнем с того, что такое динамичность и как она связана с производительностью. В данном контексте динамичность означает, что программы могут изменять параметры, конфигурации и даже свой код во время выполнения, без необходимости перезагрузки. В частности, в NGINX и OpenResty вы можете изменять upstream, SSL-сертификаты и пороговые значения ограничения скорости без перезапуска сервиса, достигая динамичности. Что касается связи между динамичностью и производительностью, очевидно, что если такие операции нельзя выполнять динамически, то частые перезагрузки сервисов NGINX естественно приведут к потере производительности.

Однако мы знаем, что открытая версия NGINX не поддерживает динамические функции, поэтому для изменения upstream или SSL-сертификатов вам придется изменять конфигурационный файл и перезапускать сервис, чтобы изменения вступили в силу. NGINX Plus (коммерческая версия NGINX) предоставляет некоторые динамические возможности, и вы можете использовать REST API для обновления, но это лишь частичное улучшение.

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

## Динамическая загрузка кода

Вот как можно динамически загружать Lua-код в OpenResty.

```
resty -e 'local s = [[ngx.say("hello world")]]
local func, err = loadstring(s)
func()'
```

Мы видим, что всего в нескольких строках кода можно превратить строку в Lua-функцию и запустить её. Давайте подробнее рассмотрим эти строки кода:

- Сначала мы объявляем строку, содержимое которой представляет собой Lua-код, выводящий `hello world`;
- Затем, используя функцию `loadstring` в Lua, превращаем строку в объект функции `func`.
- Наконец, добавляем скобки к имени функции, чтобы выполнить `func` и вывести `hello world`.

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

## Функция 1: FaaS

Первая функция — это FaaS (Function-as-a-Service), которая в последнее время стала очень популярным направлением. Давайте посмотрим, как это можно реализовать в OpenResty. В упомянутом коде строка представляет собой Lua-код. Мы можем изменить её на Lua-функцию:

```
local s = [[
 return function()
     ngx.say("hello world")
end
]]
```

Как мы уже говорили, функции в Lua являются объектами первого класса, и этот код возвращает анонимную функцию. При выполнении этой анонимной функции мы используем `pcall` для обеспечения защиты. `pcall` запускает функцию в защищенном режиме и перехватывает исключения. Если выполнение прошло успешно, возвращается `true` и результат выполнения. Если произошла ошибка, возвращается `false` и информация об ошибке, как показано в следующем коде:

```
local func1, err = loadstring(s)
local ret, func = pcall(func1)
```

Естественно, если объединить две части, получится полный и рабочий пример:

```
resty -e 'local s = [[
 return function()
    ngx.say("hello world")
end
]]
local  func1 = loadstring(s)
local ret, func = pcall(func1)
func()'
```

Чтобы пойти дальше, мы можем изменить строку `s`, содержащую функции, на форму, которую пользователь может указать, и добавить условия для её выполнения. Это прототип FaaS. Здесь я предоставляю [полную реализацию](https://github.com/apache/apisix/blob/master/apisix/plugins/serverless/init.lua). Если вы заинтересованы в FaaS и хотите продолжить исследования, перейдите по ссылке, чтобы узнать больше.

## Функция 2: Edge Computing

Динамичность OpenResty может быть использована для FaaS, что позволяет уточнить динамичность скриптового языка до уровня функций и играть динамическую роль в edge computing.

Благодаря этим преимуществам мы можем расширить возможности OpenResty от областей API-шлюзов, WAF (Web Application Firewall), веб-серверов и других серверных частей до ближайших к пользователю edge-узлов, таких как IoT-устройства, CDN-узлы, маршрутизаторы и т.д.

Это не просто фантазия. OpenResty уже широко используется в вышеупомянутых областях. Например, Cloudflare, крупнейший пользователь OpenResty, уже давно реализовал динамическое управление CDN-узлами с помощью динамических возможностей OpenResty.

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

- Сначала получить измененные файлы кода из кластера базы данных ключ-значение. Метод может быть фоновым таймером или режимом "публикация-подписка" для мониторинга;
- Затем заменить старый файл на локальном диске обновленным файлом кода и обновить кэш в памяти с помощью методов `loadstring` и `pcall`;

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

Если мы перенесем подход Cloudflare с CDN-узлов на другие edge-сценарии, мы сможем динамически распределить много вычислительных ресурсов на edge-устройства. Это не только позволит полностью использовать вычислительные мощности edge-узлов, но и позволит пользователям получать более быстрые ответы на запросы, так как edge-узел обработает исходные данные и затем отправит их на удаленный сервер, что значительно сократит объем передаваемых данных.

Однако, чтобы успешно реализовать FaaS и edge computing, динамичность OpenResty — это лишь хорошая основа. Вам также нужно учитывать улучшение окружающей экосистемы и участие производителей, что выходит за рамки чисто технических аспектов.

## Динамический Upstream

Теперь вернемся к OpenResty и посмотрим, как реализовать динамический upstream. `lua-resty-core` предоставляет библиотеку `ngx.balancer` для настройки upstream. Её нужно разместить на этапе `balancer` в OpenResty:

```
balancer_by_lua_block {
    local balancer = require "ngx.balancer"
    local host = "127.0.0.2"
    local port = 8080

    local ok, err = balancer.set_current_peer(host, port)
    if not ok then
        ngx.log(ngx.ERR, "failed to set the current peer: ", err)
        return ngx.exit(500)
    end
}
```

Функция `set_current_peer` устанавливает IP-адрес и порт upstream. Однако стоит отметить, что доменные имена здесь не поддерживаются. Для работы с доменными именами нужно использовать библиотеку `lua-resty-dns` для преобразования доменного имени в IP.

Однако `ngx.balancer` является относительно низкоуровневым. Хотя его можно использовать для настройки upstream, реализация динамического upstream далеко не проста. Поэтому перед `ngx.balancer` нужны две функции:

- Во-первых, определить, какой алгоритм выбора upstream использовать: `consistent hash` или `roundrobin`;
- Во-вторых, механизм проверки здоровья upstream, который должен исключать нездоровые upstream и возвращать их, когда они становятся здоровыми.

Официальная библиотека OpenResty [`lua-resty-balancer`](https://github.com/openresty/lua-resty-balancer) содержит два типа алгоритмов: `resty.chash` и `resty.roundrobin` для выполнения первой функции, а также `lua-resty-upstream-healthcheck` для выполнения второй функции.

Однако есть две проблемы.

Первая — это отсутствие полной реализации последнего шага. Объединение `ngx.balancer`, `lua-resty-balancer` и `lua-resty-upstream-healthcheck` для реализации динамического upstream требует дополнительной работы, что останавливает большинство разработчиков.

Вторая — реализация `lua-resty-upstream-healthcheck` неполная. В ней есть только пассивная проверка здоровья, но нет активной проверки.

Пассивная проверка здоровья здесь запускается запросами клиентов, а затем анализирует возвращаемые значения upstream для определения состояния здоровья. Если запросов от клиентов нет, состояние здоровья upstream неизвестно. Активная проверка здоровья может исправить этот недостаток. Она использует `ngx.timer` для периодического опроса указанного интерфейса upstream для проверки состояния здоровья.

Поэтому на практике мы обычно рекомендуем использовать `lua-resty-healthcheck` для проверки здоровья upstream. Его преимущество в том, что он включает как активную, так и пассивную проверку здоровья и был проверен в нескольких проектах с высокой надежностью.

Кроме того, новый микросервисный API-шлюз **Apache APISIX** реализовал полную поддержку динамического upstream на основе `lua-resty-upstream-healthcheck`. Мы можем обратиться к [его реализации](https://github.com/apache/apisix/blob/37f6f81a1a9c18895db1c61cca62785980fe9d10/apisix/balancer.lua). Всего 400 строк кода. Вы можете легко адаптировать его для использования в своем проекте.

## Итог

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

Поделитесь этой статьей и учитесь вместе с другими!

Share article link

Share

Related Posts

[![OpenResty FAQ | Как OpenResty используется на практике](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [OpenResty FAQ | Как OpenResty используется на практике](https://api7.ai/learning-center/openresty/faq-5)

[![Часть 3: Как создать API-шлюз для микросервисов с использованием OpenResty](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [Часть 3: Как создать API-шлюз для микросервисов с использованием OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [Динамическая загрузка кода](#%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F-%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0-%D0%BA%D0%BE%D0%B4%D0%B0)
- [Функция 1: FaaS](#%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F-1-faas)
- [Функция 2: Edge Computing](#%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F-2-edge-computing)
- [Динамический Upstream](#%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9-upstream)
- [Итог](#%D0%B8%D1%82%D0%BE%D0%B3)
