OpenResty におけるリクエスト間のデータ共有
このチュートリアルでは、OpenResty アプリケーションサービスの異なる HTTP リクエスト間でデータを共有する方法を段階的に説明します。ここでは 2 つのアプローチを取り上げます。単一のワーカープロセス内で共有するための Lua モジュールレベル変数と、すべてのワーカープロセス間で共有するための lua_shared_dict です。本記事は OpenResty チュートリアルシリーズの一部です。OpenResty が初めての方は、まず Hello World HTTP の例から始めてください。
プロジェクトのセットアップ
cd ~/
mkdir data-share
cd data-share/
mkdir conf logs lua
tree
まず、テストアプリケーションのディレクトリ構造を準備します。
方法 1:Lua モジュールレベル変数
リクエスト間でデータを共有する最も簡単な方法は、lua/my-module.lua という名前のカスタム Lua モジュールを使用することです。
以下の編集を行います:
- このモジュールのトップレベルにグローバルカウンター変数を追加します。
- 次に、
mainという名前のモジュール関数内で常にこのカウンターをインクリメントします。 - そして、新しいカウンター値を返します。
local _M = {}
local counter = 0
function _M.main()
counter = counter + 1
return counter
end
return _M
Nginx の設定
次に、nginx 設定ファイル conf/nginx.conf を作成します。
以下の編集を行います:
- ここで、Lua モジュールを探す場所を指定します。
- 次に、ローカルの 8080 ポートでリッスンするサーバーを定義します。
- ルートロケーションには
content_by_lua_blockがあります。 - Lua モジュールをロードし、その
main関数を呼び出します。 - 返されたカウンター値をレスポンスボディとして出力します。
worker_processes 1;
events {
worker_connections 1024;
}
http {
lua_package_path "$prefix/lua/?.lua;;";
server {
listen 8080;
location / {
default_type text/plain;
content_by_lua_block {
local mod = require "my-module"
local cnt = mod.main()
ngx.say("counter = ", cnt)
}
}
}
}
ディレクトリ構造を確認しましょう。
tree .
問題なさそうですね。
起動とテスト
sudo を使用せずに この OpenResty アプリケーションを起動します。
openresty -p $PWD/
ここでは、1 つのワーカープロセスのみを有効にしています。
ps aux|grep nginx|grep -v tmp
curl を使用してサーバーに HTTP リクエストを送信します。
curl 'http://127.0.0.1:8080/'
カウンターの値は 1 です。
もう一度試してみましょう:
今度は 2 になりました。
これは継続的に増加していきます。
仕組み:アップバリューと LuaJIT VM
この counter Lua 変数が共有されているのは、Lua モジュール関数のアップバリュー(upvalue)として機能しているためです。
cat lua/my-module.lua
そして、Lua モジュールはグローバルな LuaJIT 仮想マシン内でキャッシュされ、共有されています。
resty -Ilua -e 'require "my-module" print(package.loaded["my-module"].main)'
ご覧のとおり、キャッシュされた Lua モジュールに直接アクセスすることもできます。
package.loaded グローバルテーブルには、ロードされたすべての Lua モジュールが保存されています。
resty -e 'for k, v in pairs(package.loaded) do print(k) end'
ここでは、ほとんどのモジュールが標準モジュールです。
制限:データはワーカープロセス間で共有されない
これらのデータは異なる nginx ワーカープロセス間で共有できません。
ここでは問題ありません。1 つのワーカープロセスのみが設定されているからです。
しかし、通常は複数の CPU コアを活用するために複数のワーカープロセスを有効にします。
worker_processes 4;
その場合、各ワーカープロセスが独自のカウンターを持つことになります。
設定をテストし、サーバーをリロードしてみましょう。
openresty -p $PWD/ -t
kill -HUP `cat logs/nginx.pid`
これで 4 つのワーカープロセスが動作しているはずです。
ps aux|grep nginx|grep -v tmp
適切なアプローチの選び方
2 つの共有メカニズムは、それぞれ異なるユースケースに適しています。
| Lua モジュール変数 | lua_shared_dict | |
|---|---|---|
| スコープ | 単一のワーカープロセス | すべてのワーカープロセス |
| 値の型 | 任意の Lua 型 | 文字列、数値、真偽値 |
| 典型的な用途 | 設定キャッシュ、ワーカーごとの LRU キャッシュ | カウンター、レート制限、共有フラグ |
HUP リロード後も保持されるか | いいえ | はい |
| 再起動後も保持されるか | いいえ | いいえ |
| アトミック操作 | 対象外 | 可能(incr、add、set) |
Lua モジュールによる方法は、主に Lua レベルのデータキャッシングに使用されます。OpenResty に付属の resty.lrucache Lua モジュールは、このようなシナリオのために設計されています。
restydoc resty.lrucache
このモジュールについては、後のチュートリアルで説明します。
方法 2:lua_shared_dict を使ったワーカー間のデータ共有
すべてのワーカープロセス間でカウンターを共有するには、http ブロック内で lua_shared_dict を使って共有メモリゾーンを宣言し、ngx.shared.DICT 経由でアクセスします(これらのゾーンが内部でどのように RAM を消費するかを理解するには、OpenResty と Nginx の共有メモリゾーンはどのように RAM を消費するのかを参照してください):
http {
lua_shared_dict my_counter 1m;
server {
listen 8080;
location / {
default_type text/plain;
content_by_lua_block {
local dict = ngx.shared.my_counter
local newval, err = dict:incr("counter", 1)
if not newval then
dict:add("counter", 0)
newval = dict:incr("counter", 1)
end
ngx.say("counter = ", newval)
}
}
}
}
このカウンターは、稼働中のワーカープロセス数に関係なく正しくインクリメントされ、その値は HUP リロード後も保持されます。有効期限(ttl)、エビクション動作、リスト操作を含む完全な ngx.shared.DICT API については、専用のチュートリアルで取り上げます。
restydoc -s lua_shared_dict
restydoc -s ngx.shared.DICT
今回取り上げたいのは以上です。ハッピーハッキング!
このチュートリアルが気に入っていただけましたら、このブログサイトと私たちの YouTube チャンネルをご購読ください。ありがとうございます!
本記事は OpenResty チュートリアルシリーズの一部であり、インストールから本番運用に向けた技術までを段階的に解説するガイドです。続けて OpenResty での HTTP レスポンスのストリーミング出力をお読みください。
著者について
章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。
章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しております。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」、「動的トレーシング」、「機械プログラミング」 の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っております。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立いたしました。同社の主力製品である OpenResty XRay(動的トレーシング技術を利用した非侵襲的な障害分析および排除ツール)と OpenResty Edge(マイクロサービスおよび分散トラフィックに最適化された多機能ゲートウェイソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ております。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しております。
翻訳
英語版の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!































