Re: ngx.socket.tcp循环调用内存没有释放?

132 views
Skip to first unread message
Message has been deleted
Message has been deleted

Junlong Li

unread,
Dec 16, 2024, 2:16:01 AM12/16/24
to openresty
截图的代码让阅读变得困难,应该直接发送文本的代码。

On Monday, December 16, 2024 at 3:13:44 PM UTC+8 mayux...@gmail.com wrote:
Hello,
最近在测试中发现,我在使用openresty搭建服务器,使用while循环读取downstream的请求时,每读一次,就使用ngx.socket.tcp和upstream建立连接,发送数据,接收数据,然后发回downstream,在多次测试中发现,随着下游数据不断发送,openresty不断和上游进行交互的情况下,openresty使用的内存不断增加,并且不会释放;查看了内存,内存增长的数据,都是存放的上游连接的相关信息,想问一下,sock:close关闭不会把连接的全部数据都释放么?
QQ截图20241216142616.png

yuxi ma

unread,
Dec 16, 2024, 3:31:44 AM12/16/24
to openresty
Hello,
最近在测试中发现,我在使用openresty搭建服务器,
使用while循环读取downstream的请求时,每读一次,就使用ngx.socket.tcp和upstream建立连接发送数据,并接收响应的数据返回给下游,具体配置如下

配置文件:
```
user root;
daemon off;
master_process off;
worker_processes  1;
worker_rlimit_nofile 65536;
error_log  log/error.log  debug;

pid log/MASd.pid;

events {
        use epoll;
        accept_mutex off;
        multi_accept off;
        worker_connections  2048;
}

stream {
    log_format format '$time_odbc_style $remote_addr:$remote_port';

    limit_conn_zone $binary_remote_addr zone=addr1:10m;

    lua_gc_pause 200;
    server {
        access_log log/udp_access.log format;

        listen 0.0.0.0:10000 backlog=3145728;
        set $backend_server "10.0.229.85:12345";

        set $client_read_timeout "15000";

        set $backend_connect_timeout "1000";

        lua_code_cache on;
        lua_socket_log_errors off;
        content_by_lua_file lua/handle.lua;
        limit_conn addr1 10;
        allow 10.0.0.0/8;

        deny all;
    }
}
```

lua:
```
-- 全局配置
local config = {
    client_read_timeout = tonumber(ngx.var.client_read_timeout) or 10,
    backend_connect_timeout = tonumber(ngx.var.backend_connect_timeout) or 10,
    backend_server = ngx.var.backend_server or "127.0.0.1:8080",
}

-- 工具函数
local function count(tbl)
    local n = 0
    for _ in pairs(tbl) do n = n + 1 end
    return n
end

local function split(input, delimiter)
    local result = {}
    if not delimiter or delimiter == "" then
        return {input}
    end

    for match in (input .. delimiter):gmatch("(.-)" .. delimiter) do
        table.insert(result, match)
    end

    return result
end

local function explode(delimiter, input)
    local result = {}
    if not delimiter or delimiter == "" then
        return {input}
    end

    for match in (input .. delimiter):gmatch("(.-)" .. delimiter) do
        table.insert(result, match)
    end

    return result
end

local function receive_until_null(sock, timeout)
    sock:settimeouts(1000, 1000, 1000)
    local data, err = sock:receiveany(2 * 1024)
   
    if not data then
        return nil, err
    end
   
    return data, nil
end

local function send_and_receive(server, data, timeout)
    local ip, port = server:match("([^:]+):(%d+)")
    port = tonumber(port)

    local sock = ngx.socket.tcp()
    sock:settimeout(timeout)

    local ok, err = sock:connect(ip, port - 3)
    if not ok then
        return nil, "Connection error: " .. (err or "unknown")
    end
   
    local _, send_err = sock:send(data)
    if send_err then
        return nil, "Send error1: " .. (send_err or "unknown")
    end

    local response, recv_err = receive_until_null(sock, timeout)
    -- sock:setkeepalive(6000, 10)
    sock:close()
    sock = nil
    collectgarbage("collect")

    if recv_err then
        return nil, recv_err
    end

    return response, nil
end

-- 构造响应
local function construct_error(err_code, err_msg)
    return string.format("ERR|%d|%s", err_code, err_msg)
end

local function construct_response(fid, data)
    return string.format("RES|%s|%s", fid, data)
end

local function handle_function(payload)
    local response, err = send_and_receive(config.backend_server, payload, config.backend_connect_timeout)
    if not response then
        return construct_error(500, err), nil
    end
    return response, nil
end

-- 请求分发
local function process_request(payload)
        return handle_function(payload)
end

-- 主逻辑
local function main()
    local client = ngx.req.socket()
    client:send("sock conn success")
    while true do
        local payload, err = receive_until_null(client, config.client_read_timeout)
        if err == "closed" then
            break
        end
   
        if payload ~= nil then
            local response, err = process_request(payload)
            client:send(response .. "\0")
        end
       
        ngx.flush()
        collectgarbage("collect")
        ngx.sleep(0.01);
    end
end

main()
```


上游服务配置:
```
stream {
    server {
        listen 12345;
        listen 12342;

        content_by_lua_block {
            local sock = ngx.req.socket()
            sock:settimeouts(6000, 6000, 60000)
            local data, err = sock:receiveany(2048*2)

            local response = "A|6011| |Y| |||||||||||"

            ngx.print(response)
        }
    }
}
```
Message has been deleted

Junlong li

unread,
Dec 16, 2024, 3:44:48 AM12/16/24
to openresty
看起来这个会不断的创建新的 cosocket 上游连接,这种会导致内存不断累积。+

yuxi ma

unread,
Dec 19, 2024, 4:15:14 AM12/19/24
to open...@googlegroups.com
从接口调用来说 ,close是应该把内存进行释放;那么这个算是一个内存泄露?亦或者是内存使用不当?

Junlong li <zhuizhu...@gmail.com> 于2024年12月16日周一 16:44写道:
--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
---
您收到此邮件是因为您订阅了Google群组上的“openresty”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到openresty+...@googlegroups.com
如需查看此讨论,请访问 https://groups.google.com/d/msgid/openresty/72c088a5-6f18-4de2-a027-417872cbee96n%40googlegroups.com

yuxi ma

unread,
Dec 19, 2024, 4:15:14 AM12/19/24
to openresty
经过调试发现,在openresty与下游进行交互,和与上游进行交互所使用的 r 是同一个 r,所以r->pool只有在整个lua代码退出时才会释放,故此导致内存不断累积

```
Breakpoint 1.2, ngx_stream_lua_socket_tcp_receiveany (L=0x7ffff7ef3270) at ../ngx_stream_lua-0.0.9/src/ngx_stream_lua_socket_tcp.c:2336
2336        r = ngx_stream_lua_get_req(L);
(gdb)
2337        if (r == NULL) {
(gdb) p r
$1 = (ngx_stream_lua_request_t *) 0x96e7e0
...
Breakpoint 2, ngx_stream_lua_socket_tcp_connect (L=0x7ffff7ef3270) at ../ngx_stream_lua-0.0.9/src/ngx_stream_lua_socket_tcp.c:884
884         n = lua_gettop(L);
(gdb) n
885         if (n != 2 && n != 3 && n != 4) {
(gdb)
890         r = ngx_stream_lua_get_req(L);
(gdb)
891         if (r == NULL) {
(gdb) p r
$2 = (ngx_stream_lua_request_t *) 0x96e7e0

```

yuxi ma

unread,
Dec 19, 2024, 4:15:17 AM12/19/24
to openresty
从接口调用来说 ,close是应该把connect的内存进行释放;是有别的什么原因导致内存不断累积么?或者说这个算是一个内存泄露?亦或者是内存使用不当?

在2024年12月16日星期一 UTC+8 16:44:48<Junlong li> 写道:

Junlong li

unread,
Dec 22, 2024, 10:13:24 PM12/22/24
to openresty
目前的情况下,你可以通过定时关闭 client request 来释放内存。
比如 当前 request 已经执行了 10000次  的 上游连接,那么就关闭当前 request.
Reply all
Reply to author
Forward
0 new messages