ninenines / gun

HTTP/1.1, HTTP/2, Websocket client (and more) for Erlang/OTP.
ISC License
898 stars 231 forks source link

Sending a lot of requests from short-lived processes #162

Closed gaynetdinov closed 6 years ago

gaynetdinov commented 6 years ago

Hello. Thanks for the gun!

I have a back-pressure system written in Elixir using GenStage where I send a lot of requests from dynamically spawned processes. After request is made, the processes dies normally and then later a new process is started which again makes another request. So I have ~500 processes which are spawned, make a requests, die and then new ones are spawned, they again make requests and they die and so on.

With such approach, as I understand, I'd constantly open and close gun connections. So when processes is stared and request is made, a gun connection is made, then when process dies, the connection also dies (because when owner is dead, gun worker dies https://github.com/ninenines/gun/pull/73).

Would such approach lead to a huge overhead because of constant reconnection to the same host? Can you recommend a proper way to deal with such issue? For example using a pool of connections and use those connections somehow in workers which send actual requests.

Thanks in advance.

essen commented 6 years ago

Yeah pool of connections works well. Gun makes that easier with the reply_to request option which allows you to have the worker own the Gun connection and then let Gun send and receive messages directly to/from the original caller rather than have the messages pass through the worker.

gaynetdinov commented 6 years ago

Thanks for the quick reply. I wonder how much harm would constant reconnect make, would it lead to some memory leaks or failed requests? Or it would only make my app send requests slower?

essen commented 6 years ago

The reconnect can be expensive depending on the protocol and distance (TLS has always been quite expensive for this, but whenever TLS 1.3 gets widely deployed and is included in OTP, it will not necessarily be as bad as it once was).

Starting/stopping the process is probably not that bad, some logging if SASL is involved, and some extra logging if your calling process forgets to call gun:close.

Other than the connection cost I see pools as being more useful for limiting the number of open sockets than anything. But if you already have a limited number of processes then that's not a concern.

I'd start simple, open, request, close and if necessary only introduce pools later if necessary.

gaynetdinov commented 6 years ago

I see. And the last question: if a process is going to die anyways, it does not need to call gun:close, right?

essen commented 6 years ago

It should because when the Gun connection detects the owner process is gone it exits with reason {owner_gone, Reason} and that typically produces a log entry, at least when SASL is enabled.

gaynetdinov commented 6 years ago

Cool. Thanks for your support!