Skip to content

Commit 12b10cc

Browse files
php-cpmthibaultcha
authored andcommitted
feature: implemented the 'red:set_timeouts()' method.
Signed-off-by: Thibault Charbonnier <[email protected]>
1 parent 749d591 commit 12b10cc

File tree

5 files changed

+151
-12
lines changed

5 files changed

+151
-12
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ install:
4949
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git
5050

5151
script:
52+
- sudo iptables -A OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP
5253
- cd luajit2/
5354
- make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1)
5455
- sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1)

README.markdown

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Table of Contents
1414
* [new](#new)
1515
* [connect](#connect)
1616
* [set_timeout](#set_timeout)
17+
* [set_timeouts](#set_timeouts)
1718
* [set_keepalive](#set_keepalive)
1819
* [get_reused_times](#get_reused_times)
1920
* [close](#close)
@@ -72,7 +73,7 @@ Synopsis
7273
local redis = require "resty.redis"
7374
local red = redis:new()
7475

75-
red:set_timeout(1000) -- 1 sec
76+
red:set_timeouts(1000, 1000, 1000) -- 1 sec
7677

7778
-- or connect to a unix domain socket file listened
7879
-- by a redis server:
@@ -233,15 +234,32 @@ An optional Lua table can be specified as the last argument to this method to sp
233234
[Back to TOC](#table-of-contents)
234235

235236
set_timeout
236-
----------
237+
-----------
237238
`syntax: red:set_timeout(time)`
238239

239240
Sets the timeout (in ms) protection for subsequent operations, including the `connect` method.
240241

242+
Since version `v0.28` of this module, it is advised that
243+
[set_timeouts](#set_timeouts) be used in favor of this method.
244+
241245
[Back to TOC](#table-of-contents)
242246

243-
set_keepalive
247+
set_timeouts
244248
------------
249+
`syntax: red:set_timeouts(connect_timeout, send_timeout, read_timeout)`
250+
251+
Respectively sets the connect, send, and read timeout thresholds (in ms), for
252+
subsequent socket operations. Setting timeout thresholds with this method
253+
offers more granularity than [set_timeout](#set_timeout). As such, it is
254+
preferred to use [set_timeouts](#set_timeouts) over
255+
[set_timeout](#set_timeout).
256+
257+
This method was added in the `v0.28` release.
258+
259+
[Back to TOC](#table-of-contents)
260+
261+
set_keepalive
262+
-------------
245263
`syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size)`
246264

247265
Puts the current Redis connection immediately into the ngx_lua cosocket connection pool.
@@ -348,8 +366,8 @@ Reading a reply from the redis server. This method is mostly useful for the [Red
348366
local red = redis:new()
349367
local red2 = redis:new()
350368

351-
red:set_timeout(1000) -- 1 sec
352-
red2:set_timeout(1000) -- 1 sec
369+
red:set_timeouts(1000, 1000, 1000) -- 1 sec
370+
red2:set_timeouts(1000, 1000, 1000) -- 1 sec
353371

354372
local ok, err = red:connect("127.0.0.1", 6379)
355373
if not ok then
@@ -417,7 +435,7 @@ Adds new redis commands to the `resty.redis` class. Here is an example:
417435

418436
local red = redis:new()
419437

420-
red:set_timeout(1000) -- 1 sec
438+
red:set_timeouts(1000, 1000, 1000) -- 1 sec
421439

422440
local ok, err = red:connect("127.0.0.1", 6379)
423441
if not ok then
@@ -450,7 +468,7 @@ commands like `GET` and `SET`. So one can just invoke the `auth` method on your
450468
local redis = require "resty.redis"
451469
local red = redis:new()
452470

453-
red:set_timeout(1000) -- 1 sec
471+
red:set_timeouts(1000, 1000, 1000) -- 1 sec
454472

455473
local ok, err = red:connect("127.0.0.1", 6379)
456474
if not ok then
@@ -487,7 +505,7 @@ This library supports the [Redis transactions](http://redis.io/topics/transactio
487505
local redis = require "resty.redis"
488506
local red = redis:new()
489507

490-
red:set_timeout(1000) -- 1 sec
508+
red:set_timeouts(1000, 1000, 1000) -- 1 sec
491509

492510
local ok, err = red:connect("127.0.0.1", 6379)
493511
if not ok then
@@ -574,7 +592,7 @@ Check List for Issues
574592

575593
1. Ensure you configure the connection pool size properly in the [set_keepalive](#set_keepalive) . Basically if your NGINX handle `n` concurrent requests and your NGINX has `m` workers, then the connection pool size should be configured as `n/m`. For example, if your NGINX usually handles 1000 concurrent requests and you have 10 NGINX workers, then the connection pool size should be 100.
576594
2. Ensure the backlog setting on the Redis side is large enough. For Redis 2.8+, you can directly tune the `tcp-backlog` parameter in the `redis.conf` file (and also tune the kernel parameter `SOMAXCONN` accordingly at least on Linux). You may also want to tune the `maxclients` parameter in `redis.conf`.
577-
3. Ensure you are not using too short timeout setting in the [set_timeout](#set_timeout) method. If you have to, try redoing the operation upon timeout and turning off [automatic error logging](#automatic-error-logging) (because you are already doing proper error handling in your own Lua code).
595+
3. Ensure you are not using too short timeout setting in the [set_timeout](#set_timeout) or [set_timeouts](#set_timeouts) methods. If you have to, try redoing the operation upon timeout and turning off [automatic error logging](#automatic-error-logging) (because you are already doing proper error handling in your own Lua code).
578596
4. If your NGINX worker processes' CPU usage is very high under load, then the NGINX event loop might be blocked by the CPU computation too much. Try sampling a [C-land on-CPU Flame Graph](https://github.com/agentzh/nginx-systemtap-toolkit#sample-bt) and [Lua-land on-CPU Flame Graph](https://github.com/agentzh/stapxx#ngx-lj-lua-stacks) for a typical NGINX worker process. You can optimize the CPU-bound things according to these Flame Graphs.
579597
5. If your NGINX worker processes' CPU usage is very low under load, then the NGINX event loop might be blocked by some blocking system calls (like file IO system calls). You can confirm the issue by running the [epoll-loop-blocking-distr](https://github.com/agentzh/stapxx#epoll-loop-blocking-distr) tool against a typical NGINX worker process. If it is indeed the case, then you can further sample a [C-land off-CPU Flame Graph](https://github.com/agentzh/nginx-systemtap-toolkit#sample-bt-off-cpu) for a NGINX worker process to analyze the actual blockers.
580598
6. If your `redis-server` process is running near 100% CPU usage, then you should consider scale your Redis backend by multiple nodes or use the [C-land on-CPU Flame Graph tool](https://github.com/agentzh/nginx-systemtap-toolkit#sample-bt) to analyze the internal bottlenecks within the Redis server process.

lib/resty/redis.lua

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ if not ok or type(new_tab) ~= "function" then
2222
end
2323

2424

25-
local _M = new_tab(0, 54)
25+
local _M = new_tab(0, 55)
2626

2727
_M._VERSION = '0.27'
2828

@@ -72,7 +72,18 @@ function _M.set_timeout(self, timeout)
7272
return
7373
end
7474

75-
return sock:settimeout(timeout)
75+
sock:settimeout(timeout)
76+
end
77+
78+
79+
function _M.set_timeouts(self, connect_timeout, send_timeout, read_timeout)
80+
local sock = rawget(self, "_sock")
81+
if not sock then
82+
error("not initialized", 2)
83+
return
84+
end
85+
86+
sock:settimeouts(connect_timeout, send_timeout, read_timeout)
7687
end
7788

7889

t/count.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ __DATA__
4040
--- request
4141
GET /t
4242
--- response_body
43-
size: 54
43+
size: 55
4444
--- no_error_log
4545
[error]

t/sanity.t

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,3 +858,112 @@ failed to connect: connection refused
858858
--- timeout: 3
859859
--- no_error_log
860860
[alert]
861+
862+
863+
864+
=== TEST 16: set_timeouts() connect timeout
865+
--- http_config eval: $::HttpConfig
866+
--- config
867+
location /t {
868+
content_by_lua_block {
869+
local redis = require "resty.redis"
870+
local red = redis:new()
871+
872+
red:set_timeouts(100, 1000, 1000) -- 0.1 sec
873+
874+
local ok, err = red:connect("127.0.0.2", 12345)
875+
if not ok then
876+
ngx.say("failed to connect: ", err)
877+
end
878+
}
879+
}
880+
--- request
881+
GET /t
882+
--- response_body
883+
failed to connect: timeout
884+
--- no_error_log
885+
[alert]
886+
887+
888+
889+
=== TEST 17: set_timeouts() send timeout
890+
--- http_config eval: $::HttpConfig
891+
--- config
892+
location /t {
893+
content_by_lua_block {
894+
local redis = require "resty.redis"
895+
local red = redis:new()
896+
897+
red:set_timeouts(1000, 100, 1000) -- 0.1 sec
898+
899+
local ok, err = red:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT)
900+
if not ok then
901+
ngx.say("failed to connect: ", err)
902+
return
903+
end
904+
905+
local res, err = red:flushall()
906+
if not res then
907+
ngx.say("failed to flushall: ", err)
908+
return
909+
end
910+
911+
ngx.say("flushall: ", res)
912+
913+
local res, err = red:blpop("key", 1)
914+
if err then
915+
ngx.say("failed to blpop: ", err)
916+
end
917+
918+
red:close()
919+
}
920+
}
921+
--- request
922+
GET /t
923+
--- response_body
924+
flushall: OK
925+
failed to blpop: timeout
926+
--- no_error_log
927+
[alert]
928+
929+
930+
931+
=== TEST 18: set_timeouts() read timeout
932+
--- http_config eval: $::HttpConfig
933+
--- config
934+
location /t {
935+
content_by_lua_block {
936+
local redis = require "resty.redis"
937+
local red = redis:new()
938+
939+
red:set_timeouts(1000, 1000, 100) -- 0.1 sec
940+
941+
local ok, err = red:connect("127.0.0.1", $TEST_NGINX_REDIS_PORT)
942+
if not ok then
943+
ngx.say("failed to connect: ", err)
944+
return
945+
end
946+
947+
local res, err = red:flushall()
948+
if not res then
949+
ngx.say("failed to flushall: ", err)
950+
return
951+
end
952+
953+
ngx.say("flushall: ", res)
954+
955+
local res, err = red:blpop("key", 1)
956+
if err then
957+
ngx.say("failed to blpop: ", err)
958+
end
959+
960+
red:close()
961+
}
962+
}
963+
--- request
964+
GET /t
965+
--- response_body
966+
flushall: OK
967+
failed to blpop: timeout
968+
--- no_error_log
969+
[alert]

0 commit comments

Comments
 (0)