Hello!
On Fri, Jul 25, 2014 at 3:45 AM, Wangjingying wrote:
> 我们现在使用memcached.lua连接memcache, 在nginx环境下使用lua脚本连接memcached,
> 现在在压力测试的时候(100并发),会出现linux系统的所有端口被占用完的情况, 使用netstat
> –an命令查看,有很多的TIME_WAIT的状态, 压上100个并发,几分钟的时间 就有5万多个TIME_WAIT的状态, 脚本报错:cannot
> assign requested address, 请问这种情况怎么处理。
>
这个 cannot assign requested address 的错误清楚地指示了你把你系统的临时端口耗尽了(最多也就 6
万多个端口,而大多数 Linux 内核默认也就允许 3 万多个)。由于你的 nginx 到 memcached
的请求非常多,所以此时必须使用连接池。要不然的话,以 lua-resty-memcached 库的性能,全部使用 memcached
短连接必然很快会把几万个临时端口用尽。
>
>
> 后来我们加入了 如下 代码 local ok, err = memc:set_keepalive(10000, 100), 也是有问题。
>
你究竟配置了几个 nginx worker 进程?如果你配置了 10 个 worker,而你期望的后端并发度是 100 的话,则每个
worker 里的连接池的容量只应分配(最多) 10 个连接或者稍微更多一些。如果你给 set_keepalive 的第二个参数使用 100
的话,则 10 worker 一共会保持 1000 个长连接到 memcached,而你总的客户端并发度才 100,这无疑是巨大的浪费。
我在本地的 Linux x86_64 上使用最新的 OpenResty 1.7.2.1 (nginx 1.7.2 + ngx_lua
0.9.10 + lua-resty-memcached 0.13) 运行你提供的 location /HelloWorld
的示例,无法复现你看到的问题。
我把你的例子改成了一个独立的可以在所有人机器上直接运行的完整例子:
location /HelloWorld {
content_by_lua '
if clientIP == nil then
clientIP = ngx.req.get_headers()["X-Forwarded-For"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
-- ngx.say(clientIP)
local memcached = require "resty.memcached"
local memc, err = memcached:new()
if memc then
memc:set_timeout(5000) -- 5 sec
local ok, err = memc:connect("127.0.0.1", 11211)
if ok then
local memphvalue, err = memc:get("1_GRAY_1_15865297053")
if not memphvalue and err then
ngx.log(ngx.ERR, "failed to get value: ", err)
return ngx.exit(500)
end
ngx.say(memphvalue)
else
--ngx.exec("@hproduct_cluster")
ngx.log(ngx.ERR, "failed to connect: ", err)
return ngx.exit(500)
end
-- put it into the connection pool of size 60,
-- with 100 seconds max idle timeout
local ok, err = memc:set_keepalive(100000, 60)
if not ok then
ngx.log(ngx.ERR, "failed to set keep alive: ", err)
return ngx.exit(500)
end
else
ngx.log(ngx.ERR, "failed to get memcached: ", err)
return ngx.exit(500)
end
';
}
这里由于我配置了 2 个 nginx worker(即 worker_processes 2;),所以我分配的连接池容量是比 50
略多一些(连接池总是每 worker 的),60. (由于请求在各个 nginx worker 进程之间的分配并不会绝对均匀,所以比 50
略多一些)。
同时我对每一个 memcached 方法调用都进行了恰当的错误处理,特别是 set_keepalive().
毕竟这些方法调用并不一定总能成功。当错误发生时,将错误消息打印到 nginx 错误日志,并且返回 500
错误码,这样你在进行压测时,可以及时看到是否有(低级)错误发生。
我在我本地使用下面的命令保持压力 1 分 20 秒:
ab -c100 -k -n3000000 localhost:8080/HelloWorld
这里一个重要的细节是我在压测工具一侧也启用了长连接(即 HTTP keepalive),否则也很容易在 HTTP 客户端一侧把临时端口用尽。
在接近尾声但尚未结束(即保持稳定)之后,我使用 netstat 命令统计涉及 11211 端口的连接状态:
agentzh@w530 ~ $ netstat -nt|grep 11211|grep TIME_WAIT|wc -l
4
agentzh@w530 ~ $ netstat -nt|grep 11211|grep ESTABLISHED|wc -l
234
所以除以 2 之后(因为 11211 即可以作为源端口也可以作为目标端口,所以这里统计的数目是 x2),只有 2 个 TIME_WAIT
连接,117 个 ESTABLISHED 状态的连接。
> 这种是创建了socket连接,端口没有关闭的原因吗? 应该怎么处理呢?
>
当连接关闭后,会有较长时间处于 TIME_WAIT 状态,此时对应的临时端口并不能立即复用。所以我们应当尽量使用长连接并对之进行循环复用。
> 环境:
> Linux
> Nginx2.0.3
我很惊讶你居然用上了 nginx 2.0.3?! NGINX 2 只存在于 NGINX 公司内部,而且 2.0.0 根本没有发布,更不用说
2.0.3 了。你这里说的是 LuaJIT 的版本号吧?
哥们,咱能稍微仔细一些不?
> Lua5.1
可是你这里又说 Lua 5.1,你是指标准 Lua 5.1 解释器吗?你究竟用的是什么 Lua 实现?
> Memcache
你是说 memcached 服务器吧?
> Memcached.lua lua-resty-memcached
>
很奇怪你并没有给出 lua-resty-memcached 的版本。更没有给出 ngx_lua 模块的版本。
为避免不必要的麻烦,请直接使用最新的 OpenResty 软件包:
http://openresty.org/#Download
另外,lua-resty-memcached 正确的 require 的方式是
local memcached = require "resty.memcached"
而不是
local memcached = require "memcached"
你本身的 lua_package_path 设置或者 lua-resty-memcached 安装位置肯定有问题。如果你直接使用
OpenResty 软件包,也可以完全避免这样的麻烦,即使你没耐心仔细阅读 lua-resty-memcached 的文档。
另外,请在报告问题时,尽量提供最小化的独立的完整用例,尽量去掉不相干的东西。同时尽量附上你具体的操作步骤。这样别人可以尝试在自己环境里复现你看到的问题,以节约大家的宝贵时间。
最后,请加入 openresty 中文邮件列表并在那里讨论这样的问题:http://openresty.org/#Community 谢谢合作!
同时抄送该列表。
Best regards,
-agentzh