OpenResty FAQ | OpenRestyの実践的な使い方

API7.ai

February 10, 2023

OpenResty (NGINX + Lua)

  1. OpenResty、API Gateway、Luaに関するQ&A
  2. OpenResty FAQ | 特権プロセスの権限、実行フェーズなど
  3. OpenResty FAQ | テスト用ネットワーク構造、SSL関連機能、DSL、abツール
  4. OpenResty FAQ | 動的ロード、NYI、共有ディクショナリのキャッシュ

これで、OpenRestyとマイクロサービスAPIゲートウェイの最後のセクションを終えました。遅れずに積極的に学び、実践し、熱心に意見を残してくれた皆さん、おめでとうございます。

ここでは、いくつかの典型的で興味深い質問を選んで共有します。今日はこの5つの質問を見ていきましょう。

質問1: OpenRestyの実践的な使い方

説明: コースはほぼ終わり、基本的に理解できますが、自分の実践はまだ少ないです(現在仕事では使っていません)。仕事で使えないためです。しかし、これは非常に役立つシリーズ記事です。著者が共有を続けてくれたことに感謝し、後で仕事で紹介します。

仕事でOpenRestyを導入する話をしたいと思います。これは議論に値するトピックです。

OpenRestyはNGINXをベースにしており、lua-nginx-module Cモジュールと多数のlua-restyライブラリを追加しています。そのため、OpenRestyはNGINXの良い代替手段であり、OpenRestyを使い始める最も安価な方法です。もちろん、この置換プロセスにはリスクが伴うため、以下の3点に注意する必要があります。

まず、オンラインのNGINXバージョンがOpenRestyのメインバージョンと同じであることを確認してください。例えば、OpenResty 1.15.8.1はNGINX 1.15.8を使用しています。現在のオンラインNGINXバージョンがOpenRestyの最新バージョンよりも高い場合、OpenRestyへの切り替えには注意が必要です。OpenRestyはまだアップグレードが遅く、NGINXのメインバージョンよりも6ヶ月から1年遅れています。オンラインのNGINXバージョンがOpenRestyと同じかそれ以下の場合、アップグレードの前提条件が整っています。

次に、テストです。テストは最も重要な側面の1つです。OpenRestyを使ってNGINXを置き換えるリスクは少ないですが、リスクは依然として存在します。例えば、カスタムCモジュールをコンパイルする必要があるか、OpenRestyが依存するopensslのバージョン、OpenRestyがNGINXに適用するパッチがビジネスに影響を与えるかどうかなどです。これらの検証のために、一部のビジネストラフィックを複製する必要があります。

最後に、トラフィックの切り替えです。基本的な検証が完了した後、実際のトラフィックのカナリアリリースをオンラインで検証する必要があります。迅速にロールバックするために、新しいサーバーをいくつか開いてOpenRestyをデプロイし、元のNGINXサービスを直接置き換えないようにします。問題がなければ、バイナリファイルをホットアップグレードするか、LBからNGINXを徐々に削除して置き換えることでアップグレードできます。

NGINXの置き換え以外に、OpenRestyには他にも2つの簡単なエントリーポイントがあります:WAFとAPIゲートウェイです。これらは高いパフォーマンスと動的な要件を持つシナリオであり、すぐに使えるオープンソースプロジェクトがあります。これらについては以前に一部紹介しました。

ビジネスレベルでOpenRestyをさらに深める場合、技術以外の要因も考慮する必要があります。例えば、OpenResty関連のエンジニアを簡単に採用できるか、OpenRestyを会社の既存の技術システムに統合できるかなどです。

一般的には、NGINXの置き換えから始めて、徐々にOpenRestyを使い広げていくのが良いアイデアです。

質問2: OpenRestyのデータベースカプセル化

説明: 前回の記事によると、..(文字列連結演算子)はできるだけ使わないようにすべきで、特にコードのホットパスではそうです。しかし、データベースアクセスを扱う際、変数を挿入してSQL文を動的に構築する必要があります。これは一般的な使用シナリオだと思います。しかし、この要件に対して、文字列連結が最も簡単な方法に思え、他にシンプルで高性能な方法が思い浮かびません。

まず、SystemTapや以前の記事で紹介した他のツールを使って、SQL文の連結がシステムのボトルネックかどうかを分析できます。ボトルネックでない場合は、最適化する必要はありません。畢竟、早すぎる最適化は諸悪の根源です。

もしSQL文の連結がボトルネックである場合、データベースのprepare文を使って最適化するか、配列を使って連結することができます。しかし、lua-resty-mysqlprepareサポートはTODO状態なので、配列連結しか使えません。これは一部のlua-restyライブラリに共通する問題で、ほとんどの機能を実装して正常に動作しますが、更新が遅れています。データベースのprepare文以外に、lua-resty-redisclusterをサポートしていません。

文字列連結とlua-restyライブラリは、OpenRestyがDSLで完全に解決したい問題です。コンパイラ技術を使って自動的に配列を生成し、文字列を連結し、これらの詳細を上層ユーザーから隠します。DSL wirelangを使って、さまざまなlua-restyネットワーク通信ライブラリを自動生成し、手書きの必要をなくします。

これは素晴らしいように聞こえますが、1つの問題に直面しなければなりません:自動生成されたコードは開発者にとってフレンドリーではありません。生成されたコードを学んだり変更したりしたい場合、コンパイラ技術とオープンソースでないかもしれないDSLを学ぶ必要があり、コミュニティに参加する障壁がますます高くなります。

質問3: OpenRestyのWebフレームワーク

説明: OpenRestyでWebプロジェクトを作りたいのですが、主に成熟したフレームワークが見つからず、多くの車輪を再発明する必要があるため、苦労しています。例えば、データベース操作の問題です。動的にSQL文を構築し、連続操作を行うことができるクラスライブラリが見つかりませんでした。そこで、著者に良いWebフレームワークを推薦していただけませんか?

awesome-restyリポジトリでは、Webフレームワークの特別なカテゴリがあり、20のオープンソースプロジェクトがありますが、ほとんどが停滞しています。その中で、Lapislorvanillaの3つのプロジェクトを試して、どれがより適しているか見てみてください。

確かに、強力なWebフレームワークがないと、OpenRestyは大規模なプロジェクトを扱うのに圧倒されます。これが、ビジネスシステムでOpenRestyを使う人が少ない理由の1つです。

質問4: レスポンスボディを変更した後、レスポンスヘッダーのcontent-lengthを変更する方法

説明: レスポンスボディの内容を変更する必要がある場合、ボディフィルターでしか変更できませんが、これによりボディの長さとcontent-lengthの長さが一致しなくなります。どうすればよいですか?

この場合、ボディフィルターフェーズの前にヘッダーフィルターフェーズでcontent-lengthレスポンスヘッダーをnilに設定し、返さずにストリーミング出力する必要があります。

以下はサンプルコードです:

server {
    listen 8080;
    location /test {
            proxy_pass http://api7.ai;
            header_filter_by_lua_block {
                     ngx.header.content_length = nil
            }
            body_filter_by_lua_block {
                    ngx.arg[1] = ngx.arg[1] .. "abc"
            }
     }
}

このコードからわかるように、ボディfilterフェーズでは、ngx.arg[1]がレスポンスボディを表します。これに文字列abcを追加すると、レスポンスヘッダーのcontent-lengthが不正確になるため、ヘッダーフィルターフェーズで無効にすることができます。

また、この例はOpenRestyのさまざまなフェーズがどのように連携するかを示しており、皆さんに気づいて考えてもらいたいと思います。

質問5: OpenRestyのLuaパッケージパス

説明: lua_package_pathはLuaの依存関係の検索パスとして設定されているようです。content_by_lua_fileの場合、実験してみたところ、ディレクティブで提供されたファイルの相対パスに基づいてプレフィックスの下でのみ検索し、lua_package_pathの下では検索しないようです。私の理解が正しいかどうかわかりません。

lua_package_pathはLuaモジュールをロードするために使用されます。例えば、require 'cjson'を呼び出すと、lua_package_pathで指定されたディレクトリにcjsonモジュールを探しに行きます。一方、content_by_lua_fileの後にはディスク上のファイルパスが続きます。

location /test {
     content_by_lua_file /path/test.lua;
 }

これが絶対パスではなく相対パスである場合。

 content_by_lua_file path/test.lua;

OpenRestyの起動時に指定された-pディレクトリを使って絶対パスを取得します。

最後に、コメント欄に質問を書き続けてください。私は引き続き回答します。コミュニケーションとQ&Aを通じて、学んだことを得られるものに変えるお手伝いができればと思います。この記事を転送して、一緒にコミュニケーションと改善を進めましょう。