1W http长连接的时候 liunx 内存好像存在泄露

209 views
Skip to first unread message

Jakin

unread,
Aug 7, 2013, 8:57:38 AM8/7/13
to openresty
hi~  春哥 救命啊
 
代码如下
 
ngx.header.content_type = "text/plain"
cache = ngx.shared.cache
_DIR = "/home/nginx/servers/lua/"
local parser = require "redis.parser"
dofile(_DIR .. "function.lua")
uid = 1000
ran = math.random(1,1000)
cache:set('ran:' .. uid,ran,3000)
while 1 do
    local ut = cache:get('ran:' .. uid)
    if ut ~= ran then
        ngx.say('ut')
        ngx.eof()
    end
    local req = parser.build_query({'rpush', 'some-key', 'some-value'})
    local status,body = red_open(req)
    local data = parser.parse_reply(body)
    local json = '{"e":1,"type":2,"title":"标题信息","msg":"内容信"}'
    ngx.print(json)
    ngx.flush()
    ngx.sleep(20)
end
 
模拟了 1W http 长连接  因为 lua 代码里面用 while  1 do  所以 所以一直循环下去 所以一直hold住
现在发现个问题,就是查看 liunx 查看内存的时候 刚开始 1W 并发内存用了 1G 但是 随着时间内存越来越多
不知道这样的代码是不是有问题。是不是存在不合理的地方。。。。。。。。。。。。。。。。。。。。

Yichun Zhang (agentzh)

unread,
Aug 7, 2013, 2:39:02 PM8/7/13
to openresty
Hello!

2013/8/7 Jakin:
> 模拟了 1W http 长连接 因为 lua 代码里面用 while 1 do 所以 所以一直循环下去 所以一直hold住
> 现在发现个问题,就是查看 liunx 查看内存的时候 刚开始 1W 并发内存用了 1G 但是 随着时间内存越来越多
> 不知道这样的代码是不是有问题。是不是存在不合理的地方
>

你这种摸拟方式本身是极不合理的。Nginx
的内存分配方式利用了单个请求不会无限制地执行过长时间来进行优化,所以在单个请求的生命期内部,较小的内存块是不予释放的。

显然,你应当通过 ab、weighttp 或者 http_load 这样的工具来产生大量而持续的客户端流量。

Regards,
-agentzh

秋叶

unread,
Aug 7, 2013, 9:38:58 PM8/7/13
to open...@googlegroups.com
感谢春哥热情解答, 在这里再次问问 我们这边是想模拟 http长连接来减少 每次连接给服务器带来的带宽损耗 还有保证数据的及时性,nginx_lua
能否实现 Comet 的 Long Polling  

在 2013年8月8日星期四UTC+8上午2时39分02秒,agentzh写道:

Yichun Zhang (agentzh)

unread,
Aug 7, 2013, 9:53:22 PM8/7/13
to openresty
Hello!

2013/8/7 秋叶:
> 感谢春哥热情解答, 在这里再次问问 我们这边是想模拟 http长连接来减少 每次连接给服务器带来的带宽损耗 还有保证数据的及时性,nginx_lua
> 能否实现 Comet 的 Long Polling
>

即使是 long poll,也并不是在一个下游连接上面无限制地向后端 redis 发送无数多次请求(你们的例子其实是 server
端的“short poll”)。事实上,对于 long poll,
绝大部分时间都花费在了等待上,而单个请求内部的活动其实是极少的。比如,使用 redis 的时候,可以直接等待在 blpop
这样的命令上面,而不是使用热循环,以很高的频率去反复请求 redis.

ngx_lua 适合实现 comet 性质的服务,有些用户就是这么用的。不过需要同时设置 lua_check_client_abort:

http://wiki.nginx.org/HttpLuaModule#lua_check_client_abort

这样,当客户端提前断开连接时,服务器端也可以及时结束请求的处理周期。

Regards,
-agentzh

秋叶

unread,
Aug 8, 2013, 3:42:24 AM8/8/13
to open...@googlegroups.com
根据春哥给出的建议 我把测试代码改成这样  并且设置了 lua_check_client_abort 内存问题已经解决了,感谢下春哥 ,不过我模拟1W 并发的时候还是出问题了 囧
我让redis 连接池 设置成 10000   我观察错误日志发现大量的   

2013/08/08 15:22:44 [error] 22329#0: *186532 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 59.42.226.15, server: localhost, request: "GET /cm HTTP/1.0", subrequest: "/redis", upstream ...
013/08/08 15:17:36 [error] 22333#0: *38417 recv() failed (104: Connection reset by peer) while reading response header from upstream  ........

疑问难道 redis 无法承受那么大的并发吗?  我在redis INFO 打印发现 连接数已经达到1W  但是系统目标是想承受住10W 并发的连接 看来是无法 一两台服务可以搞定的吧?? 项目比较急 15号要弄上去,按照先上线后优化原则,但是又怕大方向是错的。

ngx.header.content_type = "text/plain"
local parser = require "redis.parser"          

local query = parser.build_query({'BLPOP','job',59})
local data = ngx.location.capture("/redis",{ args = { query = query } })
local body = parser.parse_reply(data.body)
ngx.say(data.status)
if data.status == 200 then
        if body == nil then
                ngx.say('no')
        else
                local json = '{"e":1,"type":2,"title":"标题信息","msg":"内容信息内容信息内容信息内容信息","starttime":1111111111,"TC"=>"y"}'
                ngx.print(json)
        end
end





在 2013年8月8日星期四UTC+8上午9时53分22秒,agentzh写道:
Message has been deleted

Yichun Zhang (agentzh)

unread,
Aug 8, 2013, 2:38:14 PM8/8/13
to openresty
Hello!

2013/8/8 秋叶:
> 根据春哥给出的建议 我把测试代码改成这样 并且设置了 lua_check_client_abort 内存问题已经解决了,感谢下春哥 ,不过我模拟1W
> 并发的时候还是出问题了 囧
> 我让redis 连接池 设置成 10000 我观察错误日志发现大量的
>
[...]
> 疑问难道 redis 无法承受那么大的并发吗? 我在redis INFO 打印发现 连接数已经达到1W

Redis 默认有 10000 客户端并发数的限制。你可以使用 --maxclients N 选项提高此限制,见 Redis 的这一篇官方文档:

http://redis.io/topics/clients

当然,你需要使用 Redis 2.6 以上的版本,因为 Redis 2.4 是硬编码的上限值。

此外,我还有如下建议:

1. 使用 unix domain socket 而不是 TCP socket 来连接 redis,以免遇到临时端口耗尽的问题。

2. 使用 lua-resty-redis 库来替换你现在的 ngx.location.capture + ngx_redis2 +
lua-redis-parser 的组合:

https://github.com/agentzh/lua-resty-redis

如果你使用的是 ngx_openresty 软件包的话,这个库也是默认安装的。使用这个库要比使用子请求高效和轻便不少。而且你仍然可以使用 redis 连接池:

https://github.com/agentzh/lua-resty-redis#set_keepalive

3. 如果业务模型允许的话,可以考虑在一台机器上运行多个 redis 实例,即进行水平分割,毕竟 redis 是单线程应用,多 redis
实例可以利用到系统的多个 CPU 核。

Best regards,
-agentzh

千歳

unread,
Aug 8, 2013, 2:56:58 PM8/8/13
to open...@googlegroups.com
是否有配置对redis的upstream?以及upstream有没有做keepalive?
在benchmarking的时候,nginx、redis的cpu是多少,最好跑一张火焰图看看,我生产环境上到30k hashset没有遇到问题

在 2013年8月8日星期四UTC+8下午3时42分24秒,秋叶写道:

秋叶

unread,
Aug 9, 2013, 4:06:13 AM8/9/13
to open...@googlegroups.com
按照春哥的提供的方案解决了 问题了,感谢春哥,春哥 好像没有解决不了的问题一样  : )

在 2013年8月9日星期五UTC+8上午2时38分14秒,agentzh写道:
Reply all
Reply to author
Forward
0 new messages