Nginx + Lua + Redis。 セッションを効果的に処理し、データを提供します

画像

ユーザーが認証され、データにアクセスする権利があることを確認しながら、 phpのような重い言語を使用せずにキャッシュして配布したいデータがあるとします。 今日は、 nginx lua redis bundleを使用してこのタスクを完了し、サーバーから負荷を取り除き、サーバーによる情報転送の速度を数十倍にする方法を説明します。



まず、 nginx_lua_moduleモジュールでnginxをビルドする必要があります



インストール手順
luaコンパイラーをインストールする(バージョン2.0または2.1)



luaJitをダウンロードして組み立てる

make && sudo make install
      
      







nginx開発キットを使用してnginxをビルドするには、 http_rewrite_moduleが必要です 。これには、 pcreライブラリが必要です。 したがって、それをインストールします

 sudo apt-get update sudo apt-get install libpcre3 libpcre3-dev
      
      







依存モジュールとnginx自体をダウンロードします

nginx開発キット

nginx luaモジュール

nginx



nginxを構成してインストールする

 export LUAJIT_LIB=/usr/local/lib //    lua export LUAJIT_INC=/usr/local/include/luajit-2.1 //  luaJit ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-ld-opt="-Wl,-rpath,/path/to/lua/lib" //    Lua --add-module=/path/to/ngx_devel_kit //  nginx devel kit --add-module=/path/to/lua-nginx-module //   nginx lua module --without-http_gzip_module make -j2 sudo make install
      
      







luaライブラリをダウンロードしてredis lua redis lib操作し、コマンドでluaライブラリフォルダーにコピーします

 sudo make install
      
      







lua redisライブラリーをnginx構成に接続します



 http { ... lua_package_path lua_package_path "/path/to/lib/lua/resty/redis.lua;;"; //    lua redis ... }
      
      







それだけです nginxによって実行されるスクリプトをluaで作成できるようになりました





キャッシュされたデータを迅速かつ効率的に返すために、キャッシュのウォームアップ時にすぐに最も頻繁に使用されるデータをredisに配置し、使用頻度の低いデータを要求に応じて配置します。 nginx側でluaを使用してデータを提供します。 Phpはこのバンドルに参加しません。これにより、データ出力が高速化され、サーバーのメモリ使用量が大幅に削減されます。



これを行うには、 Luaスクリプトを作成します



search.lua
 local string = ngx.var.arg_string --    GET  if string == nil then ngx.exec("/") --   ,    end local path = "/?string=" .. string local redis = require "resty.redis" --      redis local red = redis:new() red:set_timeout(1000) -- 1 sec local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.exec(path) --     redis,    end res, err = red:get("search:" .. string); --    redis if res == ngx.null then ngx.exec(path) --   ,    else ngx.header.content_type = 'application/json' ngx.say(res) --   ,    end
      
      









このファイルをnginx.confに含めてnginxをリロードします



 location /search-by-string { content_by_lua_file lua/search.lua; }
      
      







さて、クエリ/ search-by-string?String = smthの場合、 luaは redisに接続し、 検索でデータを見つけようとします:smth key 。 データがない場合、リクエストはphpによって処理されます。 ただし、データがすでにキャッシュされており、 redisにある場合、すぐにユーザーに提供されます。



しかし、ユーザーが認証され、同時に特定の役割を持っている場合にのみデータを提供する必要がある場合はどうでしょうか?



この場合、セッションをredisに保存し、コンテンツを送信する前にセッションデータに従ってユーザーのロールを確認できます。



なぜなら 私はSymfony2フレームワークで作業しているため、小さなバンドルnginx-session-handlerがそのために作成されました。これを使用して、セッションをredisに正確に保存できます。



redisでは、データはハッシュ値として保存されます:

phpsession-セッションのキープレフィックス

php-session - phpセッション自体

user-role-ユーザーロール。



次に、このデータを処理するluaスクリプトを作成する必要があります。



session.lua
 local redis = require "resty.redis" --      redis local red = redis:new() red:set_timeout(1000) -- 1 sec local ok, err = red:connect("127.0.0.1", 6379) if not ok then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --    , end --      500 local phpsession = ngx.var.cookie_PHPSESSID --  id   cookie  local ROLE_ADMIN = "ROLE_ADMIN" -- ,     if phpsession == ngx.null then ngx.exit(ngx.HTTP_FORBIDDEN) --   cookie  (  ), end --      403 local res, err = red:hget("phpsession:" .. phpsession, "user-role") --    --  redis  id  if res == ngx.null or res ~= ROLE_ADMIN then ngx.exit(ngx.HTTP_FORBIDDEN) --   (   )  end --     ,   , --      403
      
      









CookieからユーザーのセッションIDを取得し、 HGET phpsession:id user-roleのリクエストでredisからセッションIDによってユーザーロールを取得しようとします。 ユーザーがセッションの有効期限が切れている場合、認証されていないか、ロールROLE_ADMINを持っていない場合、サーバーは403コードを返します。



このセッション処理スクリプトをデータ取得スクリプトの前に追加すると、ROLE_ADMINロールを持つ認証済みユーザーのみがデータを受信できるようになります。



実際、複数の場所nginxにはセッション処理スクリプトが必要になります。 別の場所に同じコードを記述しないために、必要な場所にこのファイルを接続します。



まず、セッション処理スクリプトを少し書き直しましょう。



session.lua
 local _M = {} --  function _M.handle() --            local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) -- 1 sec local ok = red:connect("127.0.0.1", 6379) if not ok then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local phpsession = ngx.var.cookie_PHPSESSID local ROLE_ADMIN = "ROLE_ADMIN" if phpsession == ngx.null then ngx.exit(ngx.HTTP_FORBIDDEN) end local res = red:hget("phpsession:" .. phpsession, "user-role") if res == ngx.null or res ~= ROLE_ADMIN then ngx.exit(ngx.HTTP_FORBIDDEN) end end return _M --    
      
      









ここで、 luaJitコンパイラーを使用してsession.luaからsession.oファイルを収集し、このファイルでnginxを収集する必要があります。



luaコンパイラーコマンドを実行して、session.oファイルをビルドします

 /path/to/luajit/bin/luajit -bg session.lua session.o
      
      







nginxアセンブリの構成に行を追加します



 --with-ld-opt="/path/to/session.o"
      
      







nginxのビルド(上記のnginxのビルド方法)



その後、ファイルを任意のluaスクリプトに接続し、handle()関数を呼び出してユーザーセッションを処理できます。



 local session = require "session" session.handle()
      
      







最後に、比較のための小さなテスト。



コンピュータ構成
プロセッサー:Intel Xeon CPU X3440 @ 2.53GHz×8

メモリ:7.9 GiB



Redisからphpまたはluaデータを取得するテスト



ab -n 100 -c 100 php
サーバーソフトウェア:nginx / 1.9.4



同時実行レベル:100

テストにかかった時間:3.869秒

完全なリクエスト:100

失敗したリクエスト:0

1秒あたりのリクエスト:25.85 [#/秒](平均)

リクエストあたりの時間:3868.776 [ms](平均)

リクエストごとの時間:38.688 [ms](平均、すべての同時リクエスト全体)

転送速度:6.66 [Kバイト/秒]受信



接続時間(ミリ秒)

最小平均[±sd]最大中央値

接続:1 3 1.1 3 5

処理:155 2116 1053.7 2191 3863

待機中:155 2116 1053.7 2191 3863

合計:160 2119 1052.6 2194 3864



特定の時間内に処理されたリクエストの割合(ミリ秒)

50%2194

66%2697

75%3015

80%3159

90%3504

95%3684

98%3861

99%3864

100%3864(最長リクエスト)



ab -n 100 -c 100 lua
サーバーソフトウェア:nginx / 1.9.4



同時実行レベル:100

テストにかかった時間:0.022秒

完全なリクエスト:100

失敗したリクエスト:0

1秒あたりのリクエスト:4549.59 [#/ sec](平均)

リクエストあたりの時間:21.980 [ms](平均)

リクエストごとの時間:0.220 [ms](平均、すべての同時リクエスト全体)

転送速度:688.66 [Kバイト/秒]受信



接続時間(ミリ秒)

最小平均[±sd]最大中央値

接続:2 4 0.9 4 6

処理:3 13 1.6 13 14

待機中:3 13 1.6 13 14

合計:9 17 1.3 18 18



特定の時間内に処理されたリクエストの割合(ミリ秒)

50%18

66%18

75%18

80%18

90%18

95%18

98%18

99%18

100%18(最長リクエスト)



1秒あたりのリクエスト数の差は175倍です。



他のパラメーターを使用した同じテスト

ab -n 10000 -c 100 php
サーバーソフトウェア:nginx / 1.9.4



同時実行レベル:100

テストにかかった時間:343.082秒

完全なリクエスト:10000

失敗したリクエスト:0

1秒あたりのリクエスト:29.15 [#/ sec](平均)

リクエストあたりの時間:3430.821 [ms](平均)

リクエストあたりの時間:34.308 [ms](平均、すべての同時リクエスト全体)

転送速度:7.51 [キロバイト/秒]受信



接続時間(ミリ秒)

最小平均[±sd]最大中央値

接続:0 0 0.3 0 4

処理:167 3414 197.5 3408 4054

待機中:167 3413 197.5 3408 4054

合計:171 3414 197.3 3408 4055



特定の時間内に処理されたリクエストの割合(ミリ秒)

50%3408

66%3438

75%3458

80%3474

90%3533

95%3633

98%3714

99%3866

100%4055(最長リクエスト)



ab -n 10000 -c 100 lua
サーバーソフトウェア:nginx / 1.9.4



同時実行レベル:100

テストにかかった時間:0.899秒

完全なリクエスト:10000

失敗したリクエスト:0

1秒あたりのリクエスト:11118.29 [#/秒](平均)

リクエストあたりの時間:8.994 [ms](平均)

リクエストあたりの時間:0.090 [ms](平均、すべての同時リクエスト全体)

転送速度:1682.94 [Kバイト/秒]受信



接続時間(ミリ秒)

最小平均[±sd]最大中央値

接続:0 0 0.4 0 5

処理中:1 9 3.4 7 19

待機中:1 9 3.5 7 18

合計:2 9 3.4 7 21



特定の時間内に処理されたリクエストの割合(ミリ秒)

50%7

66%13

75%13

80%13

90%13

95%13

98%13

99%15

100%21(最長リクエスト)



1秒あたりのリクエスト数の差は381回です。



私の記事がお役に立てば幸いです。 あなたが提案、コメントを持っているか、より良い方法を知っているなら-書いてください。



All Articles