Skip to content

Memory leak when using client.clone() for server (proxy) #1315

Closed
@klausi

Description

@klausi

I'm writing a reverse proxy and use the HTTP client to connect to any upstream server. Code is in https://github.com/klausi/rustnish/blob/goal-06/src/lib.rs#L150 . The server is leaking memory so I must be doing something wrong.

Steps to reproduce:

  1. Make sure you have any upstream HTTP service running locally on port 80, for example the default Apache install on Ubuntu which will give you a dummy page at http://localhost/

    sudo apt install apache2
    
  2. Run rustnish reverse proxy on port 9090:

    git clone --branch goal-06 [email protected]:klausi/rustnish.git
    cd rustnish
    cargo run --release
    
  3. Get PID of rustnish process and memory usage:

    ps aux | grep rustnish
    

    The 6th column is the memory usage of the process, something like 20124 (~20MB)

  4. Fire 1 million requests at the reverse proxy with Apache Bench:

    ab -c 4 -n 1000000 http://localhost:9090/
    

    (This takes ~130 seconds on my computer)

  5. Check memory usage again:

    ps aux | grep rustnish
    

    The 6th column should show something like 284920, which is ~280MB!

So although we do not cache any requests or keep them around otherwise memory usage is growing without freeing up anymore.

One solution to the problem is this patch:

diff --git a/src/lib.rs b/src/lib.rs
index 520dd24..a591b99 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -170,7 +170,6 @@ pub fn start_server_background(
             let http = Http::new();
             let listener = TcpListener::bind(&address, &handle)
                 .chain_err(|| format!("Failed to bind server to address {}", address))?;
-            let client = Client::new(&handle);
 
             let server = listener.incoming().for_each(move |(sock, addr)| {
                 http.bind_connection(
@@ -180,7 +179,7 @@ pub fn start_server_background(
                     Proxy {
                         port: port,
                         upstream_port: upstream_port,
-                        client: client.clone(),
+                        client: Client::new(&handle),
                     },
                 );
                 Ok(())

Avoiding the client.clone() call fixes the memory leak but degrades the runtime performance. Apache Bench with 1 million requests took 220 seconds instead of 130 seconds before. So the client_clone() call seems to be the right thing to do, but the clones are not dropped correctly when one request handling is done?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-clientArea: client.C-bugCategory: bug. Something is wrong. This is bad!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions