Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High Memory usage for DelegatingHandler.init/1 #339

Open
jaronoff97 opened this issue Apr 10, 2024 · 24 comments
Open

High Memory usage for DelegatingHandler.init/1 #339

jaronoff97 opened this issue Apr 10, 2024 · 24 comments

Comments

@jaronoff97
Copy link

Hello! I'm using bandit as my websocket adapter for a phoenix project where I'm streaming data from a server to the client and I'm noticing incredibly high memory usage. When i look at the dashboard's process tab I can see it's caused by the DelegatingHandler.init/1...
Screenshot 2024-04-10 at 12 23 33 PM
Screenshot 2024-04-10 at 12 22 48 PM

I would expect init to only be called once, so I'm surprised to see it present here

@jaronoff97
Copy link
Author

FWIW, i am streaming a HUGE amount of data from the server to the client, but I would expect the socket to transfer it and then drop it.

@mtrudel
Copy link
Owner

mtrudel commented Apr 10, 2024

Interesting! Versions of Bandit and Thousand Island?

@jaronoff97
Copy link
Author

https://github.com/jaronoff97/tails/blob/main/mix.exs#L54 :)

also, it's totally possible this is expected btw for a very high load socket but wanted a gut check because this seemed really high

@mtrudel
Copy link
Owner

mtrudel commented Apr 10, 2024

It's not expected that Bandit's memory usage grows long-term based on the volume of data sent (either by HTTP or WebSocket). There may be places in the lower networking stack that are keeping some buffers around, but they should not be growing without bound. Part of me wonders if it isn't in Phoenix's channels code.

A couple things that would help:

  • Can you try with Cowboy? Does the same issue occur?
  • Can you run :sys.get_state/2 (or your observer equivalent) on the Bandit process in question (the same one you highlight in your screenshot) and dump here (note that there may be session info in there, so redact / send to me privately if needed)
  • Can you try disabling websocket compression to see if that makes a difference?

@jaronoff97
Copy link
Author

i will attempt all this when i get a chance :) pretty slammed rn. FWIW i swapped from cowboy to bandit because the bandit performance was noticeably better, but I did see similar issues there. Maybe it is something in phoenix... are there traces i can emit from the system?

@mtrudel
Copy link
Owner

mtrudel commented Apr 12, 2024

If you think you've seen similar issues in Cowboy that's the first thing to validate. Given the relative complexity of Phoenix compared to Bandit/Cowboy I think it's much more likely the issue is there.

@aaronrenner
Copy link
Contributor

I also deployed bandit yesterday and saw memory usage triple compared to running cowboy a week ago (the dotted line)

Screenshot 2024-04-25 at 11 00 29 AM

I looked in LiveDashboard and saw the DelegatingHandler.init/1 processes with 60+ mb of memory. These processes used to use 20mb of memory with cowboy.
Screenshot 2024-04-25 at 12 36 39 PM

I can tell they're tied to websockets because they're either linked to absinthe or phoenix channel processes:
Screenshot 2024-04-25 at 12 37 26 PM

Screenshot 2024-04-25 at 12 40 00 PM

I'm running the following versions:

  • bandit: 1.5.0
  • thousand_island: 1.3.5

I haven't disabled compression yet, but I'll try that next.

@aaronrenner
Copy link
Contributor

I disabled websocket compression with the following configuration and it did cause a little dip in memory usage, but not much.

config :my_app_web, MyAppWeb.Endpoint,
  adapter: Bandit.PhoenixAdapter,
  http: [
    websocket_options: [
      compress: false
    ]
  ]

The dotted line is the cowboy memory usage from a week ago.

Screenshot 2024-04-25 at 6 23 49 PM

Other than the increased memory usage on web sockets, bandit has been performing well for us.

@mtrudel
Copy link
Owner

mtrudel commented Apr 26, 2024

Sorry for the late response!

I think this may rhyme with #313 and #322. I've pushed up a branch that does a GC pass before switching the handler from HTTP/1 to WebSocket; would you be able to test

{:bandit, "~> 1.0", github: "mtrudel/bandit", branch: "gc_on_websocket"}

and see if that improves matters?

@aaronrenner
Copy link
Contributor

Thanks @mtrudel. That helped significantly.

Screenshot 2024-05-01 at 11 51 06 AM

You can see where I deployed and how it settled at 3.2gb of memory instead of 6.5gb. The top line is the memory usage from the same time yesterday and the bottom line is memory usage from a month ago when we were still running cowboy. I'm also still running with websocket compression off.

@mtrudel
Copy link
Owner

mtrudel commented May 1, 2024

Good news, but it seems like we still have work to do! Now that I know this line is producing good results, let me try adding a few more things to this branch for experimentation. We should be able to get well below the Cowboy line, all else being equal.

@mtrudel
Copy link
Owner

mtrudel commented May 1, 2024

Actually, could you switch back to cowboy for a spell just to make sure that all things are equal? It's not impossible that that growth in memory usage is due to something other than Bandit/Cowboy.

@mtrudel
Copy link
Owner

mtrudel commented May 1, 2024

It'd also be useful to know what things look like with compression re-enabled

@aaronrenner
Copy link
Contributor

Here's the difference in memory usage going from Bandit back to cowboy.
Screenshot 2024-05-01 at 1 10 43 PM

In our case it's still about 1Gb difference.

@mtrudel
Copy link
Owner

mtrudel commented May 1, 2024

This is all / predominantly websocket load?

@aaronrenner
Copy link
Contributor

These servers are handling websocket + graphql requests. The majority of the load is graphQL requests, but when I look at LiveDashboard, all of the processes with high memory usage are websockets.

@mtrudel
Copy link
Owner

mtrudel commented May 3, 2024

@aaronrenner try the
{:bandit, "~> 1.0", github: "mtrudel/bandit", branch: "gc_on_websocket"}

branch again? I've added pict filtering between requests

@mtrudel
Copy link
Owner

mtrudel commented May 14, 2024

@jaronoff97 would you be able to take a look at phoenix 1.5.2 and see to what extent this resolves your issues? I've been working with @aaronrenner on Slack and think we've solved his issues (at least these ones), and I'd like get this issue moved along for your original query

@mtrudel
Copy link
Owner

mtrudel commented May 14, 2024

I have a lead on the remaining performance deficit that @aaronrenner identifies in his most recent post above; I can identify a similar spread in memory usage (an extra 20-25% over Cowboy) and reproduce it locally. Working it over on #345.

@jaronoff97
Copy link
Author

jaronoff97 commented May 14, 2024

@mtrudel sure! I'll give that a try and run a load test and get back to you by tomorrow! Thank you :D

@mtrudel
Copy link
Owner

mtrudel commented May 14, 2024

My hunch is that you'll see the same gain @aaronrenner did, but that there will still be a ~20-25% deficit vs Cowboy (that's what I'm working on now).

If you have any similarly comparative graphs for CPU & scheduler utilization that would also be appreciated.

@ryanwinchester
Copy link
Contributor

@jaronoff97 would you be able to take a look at phoenix 1.5.2

phoenix bandit 1.5.2

@mtrudel
Copy link
Owner

mtrudel commented May 16, 2024

@aaronrenner when you posted your most recent chart on May 1 that showed an improvement but still a ~1Gb difference, do you know if you had compression enabled or not in the bandit & cowboy cases?

@aaronrenner
Copy link
Contributor

@mtrudel I just confirmed that compression was disabled for both cowboy (I believe this is the default) and bandit. The web server was changed via an environment variable in config/runtime.exs so here is the difference in the settings:

 case System.get_env("WEB_SERVER", "cowboy") do
    "bandit" ->
      config :my_app, MyAppWeb.Endpoint,
        adapter: Bandit.PhoenixAdapter,
        http: [
          websocket_options: [
            compress: false
          ]
        ]

    "cowboy" ->
      config :my_app, MyAppWeb.Endpoint, adapter: Phoenix.Endpoint.Cowboy2Adapter
  end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants