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回です。

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

Source: https://habr.com/ru/post/J270463/


All Articles