---
title: "Три часто используемые библиотеки Lua Resty в OpenResty - API7.ai"
description: "Давайте изучим часто используемые библиотеки Lua Resty в OpenResty: `lua-resty-ngxvar`, `lua-rapidjson` и `lua-resty-worker-events`."
url: "https://api7.ai/ru/learning-center/openresty/lua-resty-libraries-in-openresty"
---

# Три часто используемые библиотеки Lua Resty в OpenResty

API7.ai

January 13, 2023

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

Изучение языков программирования и платформ часто сводится к пониманию стандартных и сторонних библиотек, а не самого синтаксиса. После изучения их API и техник оптимизации производительности, нам нужно изучить использование различных библиотек `lua-resty`, чтобы расширить возможности OpenResty для большего количества сценариев.

## Где найти библиотеку `lua-resty`?

По сравнению с PHP, Python и JavaScript, текущие стандартные и сторонние библиотеки OpenResty все еще относительно скудны, и найти подходящие библиотеки `lua-resty` не так просто. Однако, есть два рекомендуемых источника, которые помогут вам найти их быстрее.

Первая рекомендация — это репозиторий [`awesome-resty`](https://github.com/bungle/awesome-resty), поддерживаемый Aapo. Этот репозиторий организует библиотеки, связанные с OpenResty, по категориям и является всеобъемлющим, включая модули NGINX на C, библиотеки `lua-resty`, веб-фреймворки, библиотеки маршрутизации, шаблоны, фреймворки для тестирования и т.д. Это ваш первый выбор для ресурсов OpenResty.

Если вы не нашли подходящую библиотеку в репозитории Aapo, вы также можете посмотреть на `luarocks`, `topm` или GitHub. Там могут быть библиотеки, которые недавно стали открытыми и пока не получили большого внимания.

В предыдущих статьях мы уже изучили несколько полезных библиотек, таких как `lua-resty-mlcache`, `lua-resty-traffic`, `lua-resty-shell` и другие. Сегодня, в последней статье раздела об оптимизации производительности OpenResty, мы познакомимся с тремя уникальными периферийными библиотеками, все они были созданы разработчиками из сообщества.

## Улучшение производительности `ngx.var`

Сначала рассмотрим модуль на C: [`lua-var-nginx-module`](https://github.com/api7/lua-var-nginx-module). Как я упоминал ранее, `ngx.var` — это операция, которая относительно затратна по производительности. Поэтому на практике нам нужно использовать `ngx.ctx` в качестве слоя кэша.

Есть ли способ полностью решить проблему производительности `ngx.var`?

Этот модуль на C проводит эксперименты в этой области, и результаты впечатляют — производительность улучшается в 5 раз по сравнению с `ngx.var`. Он использует подход `FFI`, поэтому вам нужно сначала скомпилировать OpenResty с следующей опцией компиляции.

```
./configure --prefix=/opt/openresty \
         --add-module=/path/to/lua-var-nginx-module
```

Затем используйте `luarocks` для установки библиотеки lua следующим образом:

```
luarocks install lua-resty-ngxvar
```

Метод, который здесь вызывается, также очень прост, требуется всего одна строка функции `fetch`. Она работает так же, как оригинальный `ngx.var.remote_addr`, чтобы получить IP-адрес клиента.

```
content_by_lua_block {
    local var = require("resty.ngxvar")
    ngx.say(var.fetch("remote_addr"))
}
```

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

```
ngx_int_t
ngx_http_lua_var_ffi_remote_addr(ngx_http_request_t *r, ngx_str_t *remote_addr)
{
    remote_addr->len = r->connection->addr_text.len;
    remote_addr->data = r->connection->addr_text.data;

    return NGX_OK;
}
```

Прочитав этот код, вы увидите, что этот подход Lua `FFI` такой же, как и подход `lua-resty-core`. Он имеет очевидное преимущество использования `FFI` для получения переменных напрямую, минуя оригинальную логику поиска `ngx.var`. Его недостаток очевиден: добавление функций на C и вызовов `FFI` для каждой переменной, которую вы хотите получить, требует времени и усилий.

Некоторые могут спросить: "Почему я говорю, что это требует времени и усилий? Разве код на C выше не выглядит достаточно простым?" Давайте посмотрим на источник этих строк кода, который находится в `src/http/ngx_http_variables.c` в коде NGINX.

```
static ngx_int_t
ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
    v->len = r->connection->addr_text.len;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;
    v->data = r->connection->addr_text.data;

    return NGX_OK;
}
```

После просмотра исходного кода, тайна раскрыта! `lua-var-nginx-module` — это портировщик кода переменных NGINX, с оберткой FFI на внешнем слое, и таким образом он достигает оптимизации производительности. Это хорошая идея и хорошее направление для оптимизации.

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

## JSON Schema

Здесь я представляю библиотеку `lua-resty`: [`lua-rapidjson`](https://github.com/xpol/lua-rapidjson). Это обертка вокруг `rapidjson`, открытой библиотеки JSON от Tencent, известной своей производительностью. Здесь мы сосредоточимся на отличии от `cjson`: поддержка `JSON Schema`.

`JSON Schema` — это общий стандарт, который позволяет нам точно описывать формат параметров в интерфейсе и то, как они должны быть проверены. Вот простой пример:

```
"stringArray": {
    "type": "array",
    "items": { "type": "string" },
    "minItems": 1,
    "uniqueItems": true
}
```

Этот JSON точно описывает, что параметр `stringArray` является массивом строк, и что массив не может быть пустым, а элементы массива не могут повторяться.

`lua-rapidjson` позволяет нам использовать JSON Schema в OpenResty, что может принести большую пользу для проверки интерфейсов. Например, для интерфейса ограничения количества, описанного ранее, мы можем использовать следующую схему для описания:

```
local schema = {
    type = "object",
    properties = {
        count = {type = "integer", minimum = 0},
        time_window = {type = "integer",  minimum = 0},
        key = {type = "string", enum = {"remote_addr", "server_addr"}},
        rejected_code = {type = "integer", minimum = 200, maximum = 600},
    },
    additionalProperties = false,
    required = {"count", "time_window", "key", "rejected_code"},
}
```

Вы обнаружите, что это может привести к двум очень очевидным преимуществам:

1. Для фронтенда, фронтенд может напрямую повторно использовать это описание схемы для разработки интерфейса и проверки параметров, не заботясь о бэкенде.
2. Для бэкенда, бэкенд напрямую использует функцию проверки схемы `SchemaValidator` из `lua-rapidjson` для определения легитимности интерфейса, и нет необходимости писать дополнительный код.

## Общение между `Worker`

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

> У службы OpenResty есть 24 процесса воркеров, и когда администратор обновляет конфигурацию системы через REST HTTP API, только один `Worker` получает обновление от администратора и записывает результат в базу данных, обновляя `shared dict` и `lru cache` внутри своего воркера. Как же остальные 23 воркера могут быть уведомлены об этом обновлении?

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

[`lua-resty-worker-events`](https://github.com/Kong/lua-resty-worker-events) — это конкретная реализация этой идеи. Он поддерживает номер версии в `shared dict`, и когда публикуется новое сообщение, он увеличивает номер версии на один и помещает содержимое сообщения в словарь с номером версии в качестве `key`.

```
event_id, err = _dict:incr(KEY_LAST_ID, 1)
success, err = _dict:add(KEY_DATA .. tostring(event_id), json)
```

Также в фоновом режиме создается цикл `polling` с интервалом по умолчанию в 1 секунду с использованием `ngx.timer`, чтобы постоянно проверять изменения в номере версии:

```
local event_id, err = get_event_id()
if event_id == _last_event then
    return "done"
end
```

Таким образом, как только обнаруживается новое уведомление о событии для обработки, содержимое сообщения извлекается из `shared dict` на основе номера версии:

```
while _last_event < event_id do
    count = count + 1
    _last_event = _last_event + 1
    data, err = _dict:get(KEY_DATA..tostring(_last_event))
end
```

В целом, хотя `lua-resty-worker-events` имеет задержку в одну секунду, он все же реализует механизм уведомления между воркерами.

Однако, в некоторых сценариях реального времени, таких как push-уведомления, отсутствие прямого общения между процессами `Worker` в OpenResty может вызвать у вас некоторые проблемы. Для этого нет лучшего решения, но если у вас есть хорошие идеи, пожалуйста, обсудите их на Github. Многие функции OpenResty развиваются благодаря сообществу, чтобы построить здоровый экологический цикл.

## Итог

Три библиотеки, которые мы представили сегодня, уникальны и открывают больше возможностей для приложений OpenResty. Наконец, интерактивная тема: нашли ли вы какие-либо интересные библиотеки вокруг OpenResty? Или что вы думаете о библиотеках, упомянутых сегодня? Вы можете отправить эту статью пользователям 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

- [Где найти библиотеку `lua-resty`?](#%D0%B3%D0%B4%D0%B5-%D0%BD%D0%B0%D0%B9%D1%82%D0%B8-%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D1%83-lua-resty)
- [Улучшение производительности `ngx.var`](#%D1%83%D0%BB%D1%83%D1%87%D1%88%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8-ngxvar)
- [JSON Schema](#json-schema)
- [Общение между `Worker`](#%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B5%D0%B6%D0%B4%D1%83-worker)
- [Итог](#%D0%B8%D1%82%D0%BE%D0%B3)
