編集者– 「NGINX JavaScript モジュールの概要」というタイトルのブログ投稿はここにリダイレクトされます。 この投稿は、2021 年 4 月時点でサポートされている NGINX JavaScript モジュールのディレクティブと機能に基づいて更新されました。
NGINX JavaScript モジュール (njs) は、NGINX Open Source 1.11.10 およびNGINX Plus R12で安定モジュールとして一般公開されました。 [このモジュールは元々 nginScript と呼ばれており、その名前はいくつかの古い投稿に登場しています。]私たちは2015 年 9 月のリリース以来、安定モジュールに含まれる機能と言語サポートを追加しながら、NGINX JavaScript に着実に取り組んできました。
NGINX JavaScript は、NGINX および NGINX Plus 用の独自の JavaScript 実装であり、サーバー側のユースケースとリクエストごとの処理に特化して設計されています。 洗練された構成ソリューションを実装するために、JavaScript コードを使用して NGINX 構成構文を拡張します。
NGINX JavaScript モジュールは HTTP プロトコルと TCP/UDP プロトコルの両方で使用できるため、使用例は多岐にわたります。 NGINX JavaScript の使用例には次のようなものがあります。
NGINX JavaScript について詳しく説明する前に、まずよくある誤解を 2 つ取り上げましょう。
NGINX コミュニティは長年にわたっていくつかのプログラム拡張機能を作成してきました。 執筆時点では、Lua が最も人気があり、 NGINX のモジュールとして、また NGINX Plus 用のサポートされている、事前に構築されたサードパーティの動的モジュールとして利用できます。 Lua モジュールとアドオン ライブラリは、NGINX コアとの緊密な統合と、Redis 用のドライバーを含む豊富な機能セットを提供します。
Lua は強力なスクリプト言語です。 しかし、採用の点では依然としてかなりニッチな分野であり、フロントエンド開発者や DevOps エンジニアの「スキルセット ツールボックス」には通常含まれていません。
NGINX JavaScript は Lua を置き換えることを目的としておらず、NGINX JavaScript が同等レベルの機能を備えるまでにはしばらく時間がかかるでしょう。 NGINX JavaScript の目標は、一般的なプログラミング言語を使用して、できるだけ幅広いコミュニティにプログラムによる構成ソリューションを提供することです。
NGINX JavaScript は、NGINX または NGINX Plus をアプリケーション サーバーに変えることを目的としていません。 簡単に言えば、NGINX JavaScript の使用例はミドルウェアに似ており、JavaScript コードの実行はクライアントとコンテンツの間で行われます。 技術的に言えば、Node.js は NGINX JavaScript と NGINX または NGINX Plus の組み合わせと、イベント駆動型アーキテクチャと JavaScript プログラミング言語という 2 つの共通点を持っていますが、類似点はそれだけです。
Node.js は Google V8 JavaScript エンジンを使用しますが、NGINX JavaScript は NGINX および NGINX Plus 専用に設計された ECMAScript 標準のカスタム実装です。 Node.js はメモリ内に永続的な JavaScript 仮想マシン (VM) を持ち、メモリ管理のために定期的なガベージ コレクションを実行しますが、NGINX JavaScript はリクエストごとに新しい JavaScript VM と必要なメモリを初期化し、リクエストが完了するとメモリを解放します。
前述のように、NGINX JavaScript は JavaScript 言語のカスタム実装です。 他のすべての既存の JavaScript ランタイム エンジンは、Web ブラウザー内で実行されるように設計されています。 クライアント側コード実行の性質は、システム リソースの可用性から同時実行可能な数まで、さまざまな点でサーバー側コード実行とは異なります。
サーバー側コード実行の要件を満たし、NGINX のリクエスト処理アーキテクチャにうまく適合するために、独自の JavaScript ランタイムを実装することにしました。 NGINX JavaScript の設計原則は次のとおりです。
ランタイム環境はリクエストに応じて生死を分ける
NGINX JavaScript モジュールは、迅速な初期化と破棄のために設計されたシングルスレッドのバイトコード実行を使用します。 ランタイム環境はリクエストごとに初期化されます。 複雑な状態や初期化するヘルパーがないため、起動は非常に高速です。 実行中はメモリがプールに蓄積され、完了時にプールを解放することで解放されます。 このメモリ管理スキームにより、個々のオブジェクトを追跡して解放したり、ガベージ コレクターを使用したりする必要がなくなります。
非ブロッキングコード実行
NGINX と NGINX Plus のイベント駆動型モデルは、個々の NGINX JavaScript ランタイム環境の実行をスケジュールします。 NGINX JavaScript ルールがブロッキング操作 (ネットワーク データの読み取りや外部サブリクエストの発行など) を実行すると、NGINX と NGINX Plus は関連する NGINX JavaScript VM の実行を透過的に一時停止し、イベントの完了時に再スケジュールします。 つまり、ルールをシンプルかつ直線的に記述でき、NGINX と NGINX Plus は内部ブロックなしでルールをスケジュールできます。
必要な言語サポートのみを実装する
JavaScript の仕様は、 ECMAScript標準によって定義されています。 NGINX JavaScript は、数学関数用のECMAScript 6を一部含んだECMAScript 5.1に準拠しています。 独自の JavaScript ランタイムを実装することで、サーバー側の使用例の言語サポートを優先し、不要なものを無視する自由が得られます。 現在サポートされている言語要素のリストを維持しています。
リクエスト処理フェーズとの緊密な統合
NGINX と NGINX Plus は、リクエストを異なるフェーズで処理します。 構成ディレクティブは通常、特定のフェーズで動作し、ネイティブ NGINX モジュールは特定のフェーズでリクエストを検査または変更する機能を利用することがよくあります。 NGINX JavaScript は、JavaScript コードが実行されるタイミングを制御するために、構成ディレクティブを通じて処理フェーズの一部を公開します。 この構成構文との統合により、ネイティブ NGINX モジュールのパワーと柔軟性が JavaScript コードのシンプルさとともに実現されます。
以下の表は、執筆時点で NGINX JavaScript 経由でアクセス可能な処理フェーズと、それを提供する構成ディレクティブを示しています。
処理フェーズ | HTTP モジュール | ストリームモジュール |
---|---|---|
アクセス – 認証とアクセス制御 |
auth_request とjs_content |
js_アクセス |
事前読み取り – ペイロードの読み取り/書き込み |
該当なし | js_preread |
フィルター – プロキシ中の読み取り/書き込み応答 |
js_body_filter js_ヘッダーフィルター |
js_フィルター |
コンテンツ – クライアントに応答を送信する |
js_コンテンツ |
該当なし |
ログ/変数 – 要求に応じて評価 |
js_set |
js_set |
NGINX JavaScript は、NGINX オープンソース バイナリにコンパイルしたり、NGINX または NGINX Plus に動的にロードしたりできるモジュールとして実装されています。 NGINX JavaScript を有効にする手順 NGINX と NGINX Plus の詳細については、この記事の最後に記載されています。
この例では、NGINX または NGINX Plus を単純なリバース プロキシとして使用し、NGINX JavaScript を使用して、次のような特殊な形式でアクセス ログ エントリを構築します。
この例の NGINX 構成は非常にシンプルです。
ご覧のとおり、NGINX JavaScript コードは構成構文にインラインで配置されていません。 代わりに、 js_import
ディレクティブを使用して、すべての JavaScript コードを含むファイルを指定します。 js_set
ディレクティブは、新しい NGINX 変数$access_log_headers
と、それを設定する JavaScript 関数を定義します。 log_format
ディレクティブは、各ログ行に$access_log_headers
の値を書き込むkvpairsという新しい形式を定義します。
サーバー
ブロックは、すべてのリクエストをhttps://www.example.comに転送する単純な HTTP リバース プロキシを定義します。 access_log
ディレクティブは、すべてのリクエストがkvpairs形式でログに記録されることを指定します。
次に、ログ エントリを準備する JavaScript コードを見てみましょう。
kvAccess
関数からの戻り値 (ログ エントリ) は、 rawheader_logging.confのjs_set
構成ディレクティブに渡されます。 NGINX 変数はオンデマンドで評価され、変数の値が必要なときにjs_set
によって定義された JavaScript 関数が実行されることに注意してください。 この例では、 $access_log_headers が
log_format
ディレクティブで使用されているため、ログ時にkvAccess()
が実行されます。 マップ
または書き換え
ディレクティブの一部として使用される変数 (この例では示されていません) は、以前の処理フェーズで対応する JavaScript の実行をトリガーします。
NGINX JavaScript 強化ログ ソリューションが実際に動作している様子は、リクエストをリバース プロキシに渡し、結果のログ ファイル エントリ ( in.
プレフィックスの付いたリクエスト ヘッダーとout.
プレフィックスの付いたレスポンス ヘッダーを含む) を観察することで確認できます。
$ curl http://127.0.0.1/ $ tail --lines=1 /var/log/nginx/access_headers.log 2021-04-23T10:08:15+00:00 client=172.17.0.1 method=GET uri=/index.html status=200 in.Host=localhost:55081 in.User-Agent=curl/7.64.1 in.Accept=*/* out.Content-Type=text/html out.Content-Length=612 out.ETag=\x22606339ef-264\x22 out.Accept-Ranges=bytes
NGINX JavaScript の有用性の多くは、NGINX 内部へのアクセスによって実現されます。 この例では、リクエスト ( r
) オブジェクトのいくつかのプロパティを利用します。 Stream NGINX JavaScript モジュール (TCP および UDP アプリケーション用) は、独自のプロパティ セットを持つセッション オブジェクト ( s
)を利用します。 HTTP と TCP/UDP の両方に対する NGINX JavaScript ソリューションの他の例については、 「NGINX JavaScript モジュールの使用例」を参照してください。
NGINX JavaScript のユースケースについて、ぜひお聞かせください。下のコメント セクションでお知らせください。
NGINX JavaScript モジュールのその他の HTTP および TCP/UDP の使用例については、次のブログ投稿をご覧ください。
auth_request
の拡張
[ngx_snippet name=’njs-enable-instructions’]
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"