
Suppose you have data that you want to cache and give away without using heavy languages like 
php , while checking that the user is authenticated and has the right to access the data. Today I will tell you how, using the 
nginx lua redis bundle , to accomplish this task, 
unload the server and increase the speed at which the server returns information tenfold.
First you need to build 
nginx with the 
nginx_lua_module module 
.Installation InstructionsInstall the 
lua compiler (version 2.0 or 2.1)
Download 
luaJit and collect it.
make && sudo make install 
')
To build 
nginx with the 
nginx devel kit, you need the 
http_rewrite_module , which in turn requires the 
pcre library. Therefore, install it
 sudo apt-get update sudo apt-get install libpcre3 libpcre3-dev 
Download dependent modules and 
nginx itself
nginx devel kitnginx lua modulenginxConfigure and install 
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 
Download the 
lua library to work with 
redis lua redis lib and copy it to the 
lua library folder with the command
 sudo make install 
Let's connect the 
lua redis library to the 
nginx configuration
 http { ... lua_package_path lua_package_path "/path/to/lib/lua/resty/redis.lua;;"; //    lua redis ... } 
Everything. Now you can write scripts on 
lua that will be executed 
nginx In order to quickly and efficiently give cached data, we will put the most frequently used ones in 
redis right after warming up the cache, and we will put less used ones on request. We will give data using 
lua on the side of 
nginx . 
Php will not be involved in this bundle, which will speed up data output and will take up much less memory from the server.
To do this, write the 
Lua script.
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 
 Connect this file to nginx.conf and reboot 
nginx location /search-by-string { content_by_lua_file lua/search.lua; } 
Now when you query 
/ search-by-string? String = smth lua will connect to 
redis and try to find the data using the 
search: smth key . If there is no data, the request will process 
php . But if the data is already cached and are in 
redis , they will immediately be given to the user.
But what if we need to give data only if the user is authenticated and at the same time has a certain role?
In this case, you can store the session in 
redis and before giving the content, check the user's role according to the session.
Since I work with the 
Symfony2 framework, then a small 
nginx-session-handler bundle was written for it, with which you can store the session in 
redis exactly as it 
suits us.
In 
redis, the data will be stored as a hash value:
phpsession - session key prefix
php-session - 
php session itself
user-role - user role.
Now you need to write a lua script to process this data:
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 
 We retrieve the session id of the user from the cookie, trying to get the role of the user by its session id from the 
redis at the request of 
HGET phpsession: id user-role . If the user has expired the session, he is not authenticated, or he does not have the role of ROLE_ADMIN, the server will return the code 403.
We add this session processing script to our data retrieval script and now only authenticated users with the ROLE_ADMIN role can receive data.
In fact, a session processing script will be required for multiple 
nginx locations. In order not to write the same code in different places, we will include this file where we need it.
First, let's rewrite our session processing script.
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 --     
 Now you need to build the session.o file from session.lua using the 
luaJit compiler and build 
nginx with this file.
Compile the session.o file by executing the 
lua compiler command
 /path/to/luajit/bin/luajit -bg session.lua session.o 
Add a line to the configuration to build 
nginx --with-ld-opt="/path/to/session.o" 
and collect 
nginx (how to build nginx described above)
After that, you can connect the file to any 
lua script and call the handle () function to process the user session
 local session = require "session" session.handle() 
At the end of a small test for comparison.
computer configurationProcessor: Intel Xeon CPU X3440 @ 2.53GHz × 8
Memory: 7.9 GiB
 Tests that extract data from 
redis using 
php or 
luaab -n 100 -c 100 phpServer Software: nginx / 1.9.4
Concurrency Level: 100
Time taken for tests: 3.869 seconds
Complete requests: 100
Failed requests: 0
Requests per second: 25.85 [# / sec] (mean)
Time per request: 3868.776 [ms] (mean)
Time per request: 38.688 [ms] (mean, across all concurrent requests)
Transfer rate: 6.66 [Kbytes / sec] received
Connection Times (ms)
min mean [± sd] median max
Connect: 1 3 1.1 3 5
Processing: 155 2116 1053.7 2191 3863
Waiting: 155 2116 1053.7 2191 3863
Total: 160 2119 1052.6 2194 3864
Percentage of the requests served within a certain time (ms)
50% 2194
66% 2697
75% 3015
80% 3159
90% 3504
95% 3684
98% 3861
99% 3864
100% 3864 (longest request)
 ab -n 100 -c 100 luaServer Software: nginx / 1.9.4
Concurrency Level: 100
Time taken for tests: 0.022 seconds
Complete requests: 100
Failed requests: 0
Requests per second: 4549.59 [# / sec] (mean)
Time per request: 21.980 [ms] (mean)
Time per request: 0.220 [ms] (mean, across all concurrent requests)
Transfer rate: 688.66 [Kbytes / sec] received
Connection Times (ms)
min mean [± sd] median max
Connect: 2 4 0.9 4 6
Processing: 3 13 1.6 13 14
Waiting: 3 13 1.6 13 14
Total: 9 17 1.3 18 18
Percentage of the requests served within a certain time (ms)
50% 18
66% 18
75% 18
80% 18
90% 18
95% 18
98% 18
99% 18
100% 18 (longest request)
 The difference in the "number of requests per second" is 175 times.
The same test with other parameters
ab -n 10000 -c 100 phpServer Software: nginx / 1.9.4
Concurrency Level: 100
Time taken for tests: 343.082 seconds
Complete requests: 10,000
Failed requests: 0
Requests per second: 29.15 [# / sec] (mean)
Time per request: 3430.821 [ms] (mean)
Time per request: 34.308 [ms] (mean, across all concurrent requests)
Transfer rate: 7.51 [Kbytes / sec] received
Connection Times (ms)
min mean [± sd] median max
Connect: 0 0 0.3 0 4
Processing: 167 3414 197.5 3408 4054
Waiting: 167 3413 197.5 3408 4054
Total: 171 3414 197.3 3408 4055
Percentage of the requests served within a certain time (ms)
50% 3408
66% 3438
75% 3458
80% 3474
90% 3533
95% 3633
98% 3714
99% 3866
100% 4055 (longest request)
 ab -n 10000 -c 100 luaServer Software: nginx / 1.9.4
Concurrency Level: 100
Time taken for tests: 0.899 seconds
Complete requests: 10,000
Failed requests: 0
Requests per second: 11118.29 [# / sec] (mean)
Time per request: 8.994 [ms] (mean)
Time per request: 0.090 [ms] (mean, across all concurrent requests)
Transfer rate: 1682.94 [Kbytes / sec] received
Connection Times (ms)
min mean [± sd] median max
Connect: 0 0 0.4 0 5
Processing: 1 9 3.4 7 19
Waiting: 1 9 3.5 7 18
Total: 2 9 3.4 7 21
Percentage of the requests served within a certain time (ms)
50% 7
66% 13
75% 13
80% 13
90% 13
95% 13
98% 13
99% 15
100% 21 (longest request)
 The difference in the "number of requests per second" is 381 times.
Hope my article was helpful. If you have any wishes, remarks or you know how to do better - write.