openresty / lua-nginx-module

Embed the Power of Lua into NGINX HTTP servers
https://openresty.org/
11.34k stars 2.03k forks source link

bug: memory leak when collecting response body chunks #2346

Open shreemaan-abhishek opened 3 months ago

shreemaan-abhishek commented 3 months ago

Loading large response body with size > 300 MB into memory causes leak.

The purpose of collecting response body chunks is to record them in logs in the log phase.

Steps to reproduce:

events { worker_connections 1024; }

http {

server {
    listen       8080;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;

        body_filter_by_lua_block {

            local body_buffer
            local chunk, eof = ngx.arg[1], ngx.arg[2]

            local ctx = ngx.ctx
            if not ctx._body_buffer then
                ctx._body_buffer = {}
            end

            if type(chunk) == "string" and chunk ~= "" then
                body_buffer = ctx._body_buffer
                if not body_buffer then
                    body_buffer = {
                        chunk,
                        n = 1
                    }
                    ctx._body_buffer = body_buffer
                else
                    local n = (body_buffer.n or 1) + 1
                    body_buffer.n = n
                    body_buffer[n] = chunk
                end
            end

            if eof then
                body_buffer = ctx._body_buffer
                if not body_buffer then
                    return chunk
                end

                body_buffer = table.concat(body_buffer, "", 1, body_buffer.n)
                ctx._body_buffer = nil
            end

        }
    }
}

upstream backend {
    server 192.168.253.1:8081;
}

}


- the upstream should respond with a response body of size >= 300MB.
- start openresty
- check memory usage using `top`
![image](https://github.com/openresty/lua-nginx-module/assets/61597896/78df496e-5305-47e2-ac6b-40f967056610)
- send a request:
```shell
curl http://127.0.0.1:8080/ --output tmpfile

version:

nginx version: openresty/1.25.3.1
built by gcc 13.2.0 (Ubuntu 13.2.0-23ubuntu4)
built with OpenSSL 3.0.13 30 Jan 2024
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-debug --with-cc-opt='-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC -O2 -DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC -O2 -DNGX_LUA_ABORT_AT_PANIC' --add-module=../ngx_devel_kit-0.3.3 --add-module=../echo-nginx-module-0.63 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.33 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.09 --add-module=../srcache-nginx-module-0.33 --add-module=../ngx_lua-0.10.26 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.37 --add-module=../array-var-nginx-module-0.06 --add-module=../memc-nginx-module-0.20 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.9 --add-module=../rds-json-nginx-module-0.16 --add-module=../rds-csv-nginx-module-0.09 --add-module=../ngx_stream_lua-0.0.14 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib --with-stream --without-pcre2 --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_ssl_module
zhuizhuhaomeng commented 3 months ago

It appears to be caused by Lua GC not reclaiming the Lua string in time or Lua GC not returning memory to the OS. Our private library luajit-plus improves memory usage in this case. Subscribing to OpenResty XRay gives you access to our luajit-plus private library.