OpenResty 中常用的三个 Lua Resty 库
API7.ai
January 13, 2023
プログラミング言語やプラットフォームについて学ぶことは、しばしば構文そのものではなく、標準ライブラリやサードパーティライブラリを理解することです。APIとパフォーマンス最適化技術を学んだ後、さまざまなlua-resty
ライブラリの使用を学び、OpenRestyの機能をより多くのシナリオに拡張する必要があります。
lua-resty
ライブラリはどこで見つけられるか?
PHP、Python、JavaScriptと比較して、現在のOpenRestyの標準およびサードパーティライブラリはまだ比較的乏しく、適切なlua-resty
ライブラリを見つけるのは容易ではありません。しかし、ここではそれらをより速く見つけるための2つの推奨ソースを紹介します。
最初の推奨は、Aapoがメンテナンスしているawesome-resty
リポジトリです。このリポジトリは、OpenResty関連のライブラリをカテゴリ別に整理しており、NGINX Cモジュール、lua-resty
ライブラリ、Webフレームワーク、ルーティングライブラリ、テンプレート、テストフレームワークなどが含まれています。OpenRestyリソースの第一選択肢です。
Aapoのリポジトリで適切なライブラリが見つからない場合、luarocks
、topm
、またはGitHubを参照することもできます。長期間オープンソース化されていないが注目されていないライブラリが存在するかもしれません。
以前の記事で、lua-resty-mlcache
、lua-resty-traffic
、lua-resty-shell
などの有用なライブラリについて学びました。今日、OpenRestyパフォーマンス最適化セクションの最後の記事で、コミュニティの開発者によって貢献された3つのユニークな周辺ライブラリを紹介します。
ngx.var
のパフォーマンス向上
まず、Cモジュールのlua-var-nginx-module
を見てみましょう。以前述べたように、ngx.var
は比較的パフォーマンスを消費する操作です。したがって、実際にはngx.ctx
をキャッシュ層として使用する必要があります。
では、ngx.var
のパフォーマンス問題を完全に解決する方法はあるのでしょうか?
このCモジュールはこの分野でいくつかの実験を行い、その結果は顕著で、ngx.var
よりも5倍のパフォーマンス向上を達成しました。FFI
アプローチを使用しているため、まず以下のコンパイルオプションでOpenRestyをコンパイルする必要があります。
./configure --prefix=/opt/openresty \
--add-module=/path/to/lua-var-nginx-module
次に、luarocks
を使用して以下の方法でluaライブラリをインストールします:
luarocks install lua-resty-ngxvar
ここで呼び出されるメソッドも非常に簡単で、fetch
関数の1行だけが必要です。これは、元の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コードはかなり実質的に見えるのではないか?」と疑問に思う人もいるかもしれません。これらのコードのソースを見てみましょう。これらはNGINXコードのsrc/http/ngx_http_variables.c
から来ています。
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
を紹介します。これは、Tencentがオープンソース化したJSONライブラリrapidjson
のラッパーであり、そのパフォーマンスで知られています。ここでは、cjson
との違いであるJSON Schema
サポートに焦点を当てます。
JSON Schema
は、インターフェースのパラメータの形式とその検証方法を正確に記述できる一般的な標準です。以下は簡単な例です:
"stringArray": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
このJSONは、stringArray
パラメータが文字列配列の型であり、配列が空であってはならず、配列要素が重複してはならないことを正確に記述しています。
lua-rapidjson
を使用すると、OpenRestyでJSON Schemaを使用でき、インターフェース検証に大きな便利さをもたらします。例えば、前述の制限カウントインターフェースを以下のスキーマで記述できます:
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"},
}
これにより、2つの非常に明らかな利点が得られます:
- フロントエンドにとって、フロントエンドはこのスキーマ記述を直接再利用してフロントエンドページの開発とパラメータ検証を行うことができ、バックエンドを気にする必要がありません。
- バックエンドにとって、バックエンドは
lua-rapidjson
のスキーマ検証機能SchemaValidator
を直接使用してインターフェースの正当性を判断し、余分なコードを書く必要がありません。
Worker
間通信
最後に、OpenRestyでワーカー間通信を可能にするlua-resty
ライブラリについて話します。OpenRestyにはワーカープロセス間の直接通信メカニズムがないため、多くの問題が発生します。次のシナリオを想像してみてください:
OpenRestyサービスには24のワーカープロセスがあり、管理者がREST HTTP APIを通じてシステムの設定を更新すると、1つの
Worker
だけが管理者からの更新を受け取り、データベースに結果を書き込み、自身のWorker内のshared dict
とlru cache
を更新します。では、他の23のワーカーにこの設定を更新するように通知するにはどうすればよいでしょうか?
複数のWorker
間の通知メカニズムが必要です。OpenRestyがそれをサポートしていない場合、shared dict
データを介してワーカー間でデータを保存する必要があります。
lua-resty-worker-events
はこのアイデアの具体的な実装です。shared dict
にバージョン番号を維持し、新しいメッセージが公開されると、バージョン番号に1を加え、メッセージの内容をバージョン番号をkey
として辞書に格納します。
event_id, err = _dict:incr(KEY_LAST_ID, 1)
success, err = _dict:add(KEY_DATA .. tostring(event_id), json)
また、デフォルトで1秒間隔のpolling
ループを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
には1秒の遅延がありますが、それでもワーカー間のイベント通知メカニズムを実装しています。
ただし、メッセージプッシュなどのリアルタイムシナリオでは、OpenRestyのWorker
プロセス間の直接通信の欠如が問題を引き起こす可能性があります。これに対するより良い解決策はありませんが、良いアイデアがあればGithubで自由に議論してください。OpenRestyの多くの機能は、コミュニティによって駆動され、健全な生態系を構築しています。
まとめ
今日紹介した3つのライブラリはユニークで、OpenRestyアプリケーションにさらなる可能性をもたらします。最後に、インタラクティブなトピックとして、OpenResty周辺で面白いライブラリを見つけましたか?または、今日紹介したライブラリについて何か発見や疑問がありますか?この記事を周りのOpenRestyユーザーに送って、一緒に交流し、進歩してください。