aleph

dergutemoritz 2023-09-26T09:10:00.418979Z

Question: Does Aleph apply backpressure on outbound traffic anywhere? I know that it does so for inbound traffic (by toggling autoread) but so far I haven't seen anything for outbound traffic. Looks like writes are just queued without bounds 🤔

dergutemoritz 2023-09-27T14:27:27.607549Z

This can of course be implemented in user code but it seems like a dangerous default..! Then again, Netty also punts this (see e.g. https://github.com/netty/netty/pull/6662).

Matthew Davidson 2023-09-28T08:06:59.087209Z

Well, both TCP and HTTP/2 advertise windows, but how does that manifest in Netty/Aleph? As you've noted, it doesn't directly; Netty just keeps queueing up whatever you feed it. See: • https://stackoverflow.com/questions/35569017/difference-between-server-side-and-client-side-high-and-low-write-watermarks-opt • https://github.com/netty/netty/issues/10254 • io.netty.handler.traffic package Backpressure/throttling has to be implemented in consumer code, and broadly, it seems like there's two options: 1. All writes return a future/promise that won't be resolved until finished, but we don't necessarily want to chain callbacks onto those, because it's (a) difficult to relate to underlying congestion windows without counting bytes ourselves, and (b) tricky to coordinate with multiple Aleph/Manifold threads. 2. We listen for changes in the Channel's writability state, since Netty uses that itself to throttle/block, and hold off on any flushes until it's writable. In the HTTP2 code, I already added a writable? AtomicBoolean for disabling the user handler from writing after an error, but we could use something similar for backpressure. We can check Channel writability, and if not writable, set a flag to call .flush() when .channelWritabilityChanged(true) is fired. The only catch with that is, we want to block the .write() -calling code, not just the .flush(). It does no good to respect Netty writability if some user handler is still consuming memory without bound.

Matthew Davidson 2023-09-28T11:01:14.964649Z

New issue for this: https://github.com/clj-commons/aleph/issues/691

dergutemoritz 2023-09-28T12:33:36.241819Z

Thanks for the comprehensive writeup!

dergutemoritz 2023-09-28T12:33:41.538679Z

And for confirming

dergutemoritz 2023-09-28T12:34:38.505329Z

I'll experiment with the options you pointed to in my application

dergutemoritz 2023-09-28T12:34:48.089419Z

as it stands, it's a bit of a DoS vector 😕

dergutemoritz 2023-09-28T12:35:10.812939Z

especially in a raw TCP server

Matthew Davidson 2023-10-02T06:50:21.459549Z

Fundamentally, users also have to respect backpressure signals and deal with some of it in their own handlers if they want the best possible response. There's only so much aleph/manifold/netty can do for you, especially if there are inputs coming from outside that aleph/netty aren't aware of.