News for hackers. Stuff that matters.
Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @09:05AM (#35613454)
we are so stuck with this push request load balancing its crazy, if we just switch to pull instead of push things get much smoother, and resources get better utilized

you cant reliably guess if the instance where you will push your request actually has capacity to handle it, even using ML to guess it will still have thrashing properties

but if you just let instances pull work, things work out for themselves

sadly, the whole industry is stuck on http push

i was playing with it few years ago making a simple queue and wrote my ideas here: https://punkjazz.org/jack/we-got-it-all-wrong.txt and some basic benchmarks https://punkjazz.org/jack/we-got-it-all-wrong-2.txt

in the same time, there is so much tooling for http, and its so natural to use it, that it is actually hard to switch to another transport layer, so now the best we have is some naive bayesian classifiers in the LB and some exponential backoff

here is the difference i had in timings using io queue vs http for 2 endpoints, one fast and one slow (endpoints had the same code, just transport was different)

    2019/02/19 22:26:27 QUEUE ... 20000 messages, took: 29.95s, speed: 667.74 per second
    -   0+10=9711  48.55% ******************************
    -  10+ 5= 276  49.94% 
    -  15+ 8=  20  50.03% 
    -  23+12=  16  50.11% 
    -  35+18=3398  67.11% **********
    -  53+27=6549  99.85% ********************
    -  80+40=  30 100.00% 
    - 120+60=   0 100.00%
    - 180+90=   0 100.00%
    - 270+ 0=   0 100.00%


    2019/02/19 22:26:56 http ... 20000 messages, took: 29.55s, speed: 676.91 per second
    -   0+10=3274  16.37% ********************
    -  10+ 5=1523  23.98% *********
    -  15+ 8=4439  46.18% ****************************
    -  23+12=4756  69.96% ******************************
    -  35+18=3318  86.55% ********************
    -  53+27=2037  96.73% ************
    -  80+40= 581  99.64% ***
    - 120+60=  70  99.99% 
    - 180+90=   2 100.00% 
    - 270+ 0=   0 100.00%
you can see how the fast endpoint is always fast with the queue transport, but with classic push load balancing it spills latency a lot, because the instance is sometime busy servicing the slow request

PS: this post is absolutely amazing! and the animations are brilliant! thanks a lot for making it

Re:Load Balancing by Mavvie on Tuesday April 18, 2023 @09:35AM (#35613792)
So what do you think the disadvantage is of a pull approach? Presumably it's not just better or else tools would use it?
Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @09:59AM (#35614133)
i never ran this in prod, so not sure

i think the retries are a bit strange, and debugging was weirder as well, but its probably just me not used to it

even though i had multiple chances to use it in prod, i always go for http somehow, it just feels so familiar

also because of the way the REPLY_TO address:port worked in my experiments, sometimes having half open tcp connections really messes up things

Re:Load Balancing by jgtrosh on Tuesday April 18, 2023 @09:59AM (#35614134)
Not an expert in load balancing, but in similar problems (work sharing / work stealing, MPI get/put) it makes sense to pull only if you can pull fast enough to avoid incurring prohibitive latency at every request/message.

Multithreading-based work stealing à la Cilk relies on extremely cheap thread mechanisms and implementation to minimize communication.

In another similar situation, HPC switches are credit based so that until you hit congestion, you can “instantaneously” know if a remote is ready to receive.

This isn't a formal explanation, of course.

Edit: after some thought, that's not really the distinction that is made for load balancing. There's already knowledge of the remote state required for pushing to the last loaded queue. So the difference between pull and push is about having one queue vs several. In that sense it is like supermarkets that implement the more efficient one queue to every cashier Vs the more traditional one queue per cashier. In supermarkets there is a choice to make because there's other constraints, but just optimising for load balancing it's strictly better to have a single queue, if you only have one input.

Re:Load Balancing by rektide on Tuesday April 18, 2023 @10:52AM (#35614780)
Having enough workers to do the work shouldn't be any more constraining than it was before.

The article does nicely mention that simple round Robin actually has lower latency, because some traffic gets lucky & goes to under-utilized machines. Unfairness helps some traffic go faster. The queue is probably going to eliminate this, but the unfairness advantage comes at the cost of a lot of other traffic getting put into long queues on workers, so it wasn't really a good thing anyways. The p90+ is usually awful.

Re:Load Balancing by rektide on Tuesday April 18, 2023 @10:48AM (#35614731)
Making a high reliability queue that can also soak load spikes is non-trivial.

Now that we have hundreds of Gbps ethernet and TB of memory the idea has more merit, can scale pretty absurdly high with mundane systems. Or maybe you have sharding, which means now you have a load balancing problem again, of picking which work queue to take work from.

The HA bit is still hard. You have to to figure out if there's a netsplit (some folks can't connect to one server) or if one server really is gone. Probably just multicast to each queue all the incoming work & all the incoming pulls. Ideally each queue could also hear all the outgoing traffic. If ethernet capacity were unidirectional this would be great, box #2 could autonomously detect faults & take over. But ethernet is bidirectional, and now it needs all box #1's incoming traffic and it's outgoing traffic too. So instead maybe have the clients fail over. We can iterate on resign but HA is non-trivial.

Re:Load Balancing by toast0 on Tuesday April 18, 2023 @12:02PM (#35615818)
A pull approach seems difficult to manage when you have many layers in your load balancing.

In small setups, you may just have one layer with a single load balancer (well, hopefully at least a hot-warm pair), but larger setups often have multiple levels. There may be a network level traffic split to multiple frontend load balancers via something like ECMP; those frontends may connect directly to the origin hosts, or maybe there are frontends in many locations and they connect to backend load balancers near the origins.

In this bigger case, managing pull requests becomes difficult, because balancing may be unequal at earlier layers --- if your origin can handle N concurrent requests, so it sends N pulls, how many should it send to which of the upstreams, and if some upstreams get many requests and some get zero, those many requests will have unnecessary delay.

There's also unnecessary delay when at capacity between when one request finishes and the round trip of sending a pull and getting the next request.

But, it's always tradeoffs. It depends on the volume of requests, the typical time to process a request, behavior at or near capacity, etc.

I also think a pull based system is more work for the load balancer, and load balancers are harder to scale --- I prefer to move the work to the origins as much as possible, because it's typically easy to add more of those --- that's what the load balancer enables. But, that doesn't seem to be a commonly held opinion, direct server return is rarely available, load balancers commonly do TLS termination, and often intense traffic inspection and manipulation; again, there's tradeoffs.

Re:Load Balancing by dano on Tuesday April 18, 2023 @12:57PM (#35616606)
Nice to see someone mention direct server return or as BigIP called it nPath routing. This was an effective scaling method for handling small request that returned large payloads (audio and video files). I don't know how well known this configure is or whether it is still viable in an all TLS world.
Re:Load Balancing by toast0 on Tuesday April 18, 2023 @01:09PM (#35616782)
It doesn't seem particularly well known. It works fine with TLS, but the origin servers need to do the TLS termination (IMHO, this is better for security than having your load balancers do it, but it does mean you have to work harder on key distribution). On a non-DSR load balancer, doing TLS termination on the origins means the load balancer has less application data to work with (request path, response status code, etc) in making load balancing decisions, but for DSR, the load balancer never had any of that, so adding TLS doesn't disadvantage the load balancer any more.

TLS session establishment is expensive, so why would I want my load balancers to do it anyway? :P

Re:Load Balancing by blipvert on Tuesday April 18, 2023 @02:10PM (#35617603)
Should you wish to give DSR load balancing a go without having to invest in hardware/licenses you could try https://github.com/davidcoles/vc5

Put that in front of some HAProxy servers to do TLS termination and farm out requests to another layer of NGINX/uWSGI boxes and Robert is your cousins father.

Re:Load Balancing by adql on Wednesday April 19, 2023 @07:55AM (#35627028)
It kinda fell out of favour when even midrange server can do tens of gigabits of TLS traffic. So you need to be very big traffic wise to make it worth.
Re:Load Balancing by gbuk2013 on Tuesday April 18, 2023 @09:48AM (#35613976)
Moving to async model adds new set of operational challenges as well as some interesting failure scenarios. (Edit) Also, in practice you would need at least one more system to enqueue request into the broker, as the latter would typically not be exposed to the outside world.

Request/response on the other hand is much simpler to configure and operate.

Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @09:52AM (#35614032)
this is not async, its sync queue

the lb puts a request where it has some reply_to (ip:port) where it waits (blockingly) for response from whoever picked up the request, it just does now know who that is until a reply comes

Re:Load Balancing by gbuk2013 on Tuesday April 18, 2023 @10:05AM (#35614222)
If you have a queue then you have async model.

As an example of a failure scenario, how does your system distinguish between a request timeout, a response that didn’t get sent back because of network failure and the consumer crashing and losing the message?

Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @10:10AM (#35614273)
pretty much the same way a push load balancer does https://github.com/jackdoe/back-to-back/blob/master/broker/b...

    for {
      select {
      case reply := <-replyChannel:
       if reply.Uuid == r.message.Uuid {
        return reply
       }
      case <-timeout:
       return makeError(r.message, MessageType_ERROR_CONSUMER_TIMEOUT, "consumer timed out")
      }
     }
not much different than what you do with normal http timeouts, you send a request, sometimes a response comes sometimes it doesnt, up to the load balancer to decide if it wants to retry or error out

also, queue does not mean async model, it means a queue, there are many queues in http requests responses (e.g. the listen(2) backlog queue itself) and it does not make it async :)

EDIT: i dont have reply button to your 'what if there is modified state' question, but the answer is: exactly the same as push load balancing when you dont receive the instance's response due to network failure, but it modified the state

Re:Load Balancing by gbuk2013 on Tuesday April 18, 2023 @10:20AM (#35614395)
> queue does not mean async model

“Message queues implement an asynchronous communication pattern between two or more processes/threads whereby the sending and receiving party do not need to interact with the message queue at the same time.”

https://en.m.wikipedia.org/wiki/Message_queue

Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @10:59AM (#35614869)
if you read what i wrote, you will see that it is not asynchronous communication.

and it is not a message queue in the sense you mean, it is a request response queue, it just happens to be using messages

when people think of message queue they are thinking of async event driven communication, and this is not it

Re:Load Balancing by gbuk2013 on Tuesday April 18, 2023 @10:14AM (#35614330)
And what happens if your request modifies state but the response is not received?
Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @10:56AM (#35614820)
exactly the same as push load balancing when it doesnt receive the instance's response due to network failure, but the state is modified
Re:Load Balancing by jayd16 on Tuesday April 18, 2023 @12:13PM (#35615968)
If we're not talking about an async model then the suggestion is much less drastic than it sounded at first. In that case the crux of your desire is simply allowing the hosts to signal readiness more directly.

You would almost never actually wait for host machines to dial in. You would have a list of hosts that are ready or not ready as they would almost always be ready for more. You want to assume readiness (as this lowers latency) and feed the fire hose.

But in this interpretation, in a world where an LB would be using an existing connection to host machines with HTTP/3 we're basically already there. I suppose its trivial and standard to signal unreadiness to the LB from the host with a 429 Too Many Requests response code.

Off the top of my head I'm trying to think how a host could actively signal to an LB that's its ready for more requests... I suppose its trivial and common to use a health check. Is it even a change to say that these need to be updated to achieve your goal of host to LB pulling?

Re:Load Balancing by adql on Wednesday April 19, 2023 @07:21AM (#35626830)
...that's just push model. "Signalling" via "well, the loadbalancer have 10 sessions max per server" is enough.

Pull model just adds unnecesary RTT.

> Off the top of my head I'm trying to think how a host could actively signal to an LB that's its ready for more requests... I suppose its trivial and common to use a health check. Is it even a change to say that these need to be updated to achieve your goal of host to LB pulling?

Like this.

There is rarely a case where you decide to not serve the next request after serving previous one so push is most optimal for short ones. And if it doesn't want to it can just signal that via healthcheck.

Pull makes more sense for latency-insensitive jobs like "take a task from queue, do it, and put the results back", as if you say make video encoding service that dynamically scales itself in the background and "just do one encode and exit" is commonplace.

Re:Load Balancing by preseinger on Wednesday April 19, 2023 @12:43PM (#35630322)
it is not possible for a remote destination host to signal to a sending host that it is ready, or not ready, for more requests, in a reliable way

readiness is not knowable by a receiver, it is a function of many variables, some of which are only knowable to a sender, one obvious example is a network fault between sender and receiver, there are many more

even the concept of "load" reported by a receiving application isn't particularly relevant, what matters is the latency (and other) properties of requests sent to that application as observed by the sender

health is fundamentally a property that is relative to each sender, not something that is objective for a given receiver

Re:Load Balancing by potamic on Wednesday April 19, 2023 @02:09AM (#35624797)
How do you ensure two backends don't pick up up the same request?
Re:Load Balancing by adql on Wednesday April 19, 2023 @07:17AM (#35626806)
That's push model when per-server maxconn is full tho.

The biggest benefit from pull model is not having to update backend server list every time you add/remove one but outside of that it isn't really all that beneficial.

You also get added latency, unless each backend server is actively listening and connected but if it is, you're just wasting extra RTT to say "hey, there is a request in queue, do you want it?"

Re:Load Balancing by paulddraper on Tuesday April 18, 2023 @09:56AM (#35614086)
One of the nicest things about pull load balancing is that it completely replaces the need for a separate registration + health check system.

Once you consider that, IDK if someone can really claim "more complicated."

Re:Load Balancing by samwho on Tuesday April 18, 2023 @10:20AM (#35614387)
I honestly had never thought hard about reversing the relationship and having workers pull. This point about no longer requiring health checks is a real "woah" moment. Thanks for expanding my mind!
Re:Load Balancing by throwaway894345 on Tuesday April 18, 2023 @12:18PM (#35616032)
Agreed on the “whoa moment”. Not needing health checks seems pretty compelling. I’m curious if there are any off-the-shelf pull-based load balancer that don’t require the full HTTP request copied onto the queue before handing off to a worker?
Re:Load Balancing by adql on Wednesday April 19, 2023 @07:15AM (#35626788)
You need health checks. If not for LB then for your own monitoring.
Re:Load Balancing by preseinger on Wednesday April 19, 2023 @12:33PM (#35630211)
you don't

a server can return 200 OK to every health check query and 5xx to every production request, is that server up or down? hopefully clear it is down

similarly, if it returns 5xx to every health check query but 200 to every prod request, is it up or down? hopefully clear it is up

if you want to monitor the status of a server (or application) for internal purposes, that's fine, but that's (at best) supplementary signal for the decisions made by a load balancer, not something you can make load balancing decisions on in isolation

Re:Load Balancing by ramses0 on Tuesday April 18, 2023 @12:48PM (#35616477)
Re:Load Balancing by 0x457 on Tuesday April 18, 2023 @01:27PM (#35617019)
You still need health checks, though? Otherwise, how do you tell the difference between: "no traffic + server alive" vs "some traffic + server is dead". Yeah, you can monitor throughput on a load balancer, but if I ever again wake up from an alert about not traffic being served - I will throw hands.
Re:Load Balancing by samwho on Tuesday April 18, 2023 @02:38PM (#35618058)
Yeah, they’d have to exist but it would be for quite a different purpose. I wonder if that would mean we could implement them in different ways, e.g have a health check service that everything pings and if a ping isn’t received for N minutes, assume it’s dead and trigger some replacement routine or alert.
Re:Load Balancing by throwway120385 on Tuesday April 18, 2023 @02:57PM (#35618342)
This begins to look a lot more like a software watchdog at that point, and you can even have each service provide a count of outstanding/processed requests per tick and if a server never gets outstanding or processed requests you could have the watchdog kill it off.
Re:Load Balancing by paulddraper on Tuesday April 18, 2023 @02:54PM (#35618302)
Your server scaling system will need healthchecks. But:

1. It can be more tolerant of failures, since an unresponsive server doesn't mean failed requests.

2. Hooking up your server scaling system to HAProxy, etc. isn't the easiest thing in the world anyway.

Re:Load Balancing by preseinger on Wednesday April 19, 2023 @12:29PM (#35630167)
server health is necessarily a function of the actual production traffic it receives, determined at the application layer, as observed by a specific observer

it can't be known by the server itself, as (among many other reasons) the server can't know about network issues between itself and any upstream caller

it can't be determined by out-of-band health check queries, because those queries don't represent actual traffic, the simplifying assumption that they _do_ introduces many common failure modes that any seasoned engineer can speak at length about

health checks can be a nice additional signal on top of monitoring actual prod traffic, but they can't be used by themselves, they just don't capture enough relevant information

Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @10:18AM (#35614366)
oh yea, the amount of outages we had in my last company because of weighted roundrobbin registration/healthcheck/watermark/latch issues were way more than anyone would guess
Re:Load Balancing by zokier on Tuesday April 18, 2023 @12:56PM (#35616591)
Doesn't it just flip the registration/check need instead of eliminate it? You'd need to register the brokers/loadbalancers to the workers so they know where to pull work from?
Re:Load Balancing by paulddraper on Tuesday April 18, 2023 @01:11PM (#35616815)
Yes.

But the load balancers/brokers are usually far less dynamic. I've never seen a worker health check a RabbitMQ queue.

Re:Load Balancing by adql on Wednesday April 19, 2023 @07:14AM (#35626780)
"Wait, why this is dead for 4 weeks and not processing anything

> One of the nicest things about pull load balancing is that it completely replaces the need for a separate registration + health check system.

"Jeff, stop taking random advice off HN as gospel, that shit is stuck in GC for last week ,we told you we still need monitoring"

Re:Load Balancing by samwho on Tuesday April 18, 2023 @10:28AM (#35614475)
Thank _you_ for striking up a spirited discussion! :)
Re:Load Balancing by artworx on Tuesday April 18, 2023 @10:43AM (#35614666)
The AWS Lambda Runtime API is pull based:

- GET events from ${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next

- process it (run your handler)

- POST the response to /runtime/invocation/AwsRequestId/response

https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.ht...

Re:Load Balancing by jayd16 on Tuesday April 18, 2023 @10:57AM (#35614847)
Honestly, I disagree. It's not like queue systems are rare. They're fairly common and they're often seen as an over complication! Once and only once queuing is hard. Async programming is hard.

Streaming requests or responses is out the window! Now you're storing the full request and response blobs in your infrastructure instead of chunks at a time in the network layer. Is a whole Netflix movie queued? If we're talking about queued chunks then its just UDP you're describing.

Connection oriented designs tend to more transparency end to end. The synchronous nature means a failed call can be bubbled back through the remote call chain. Failed async calls can be dropped, which leaves ambiguity. The callers need to resort to timeouts instead of closed connection signals.

Not to mention the issue that this doesn't work for client calls. The response handling from the client is more complex. The async callback would need to be demuxed such that a response can be associated with a call. There's no open connection so you'd need to punch the firewall somehow...honestly its very messy.

Re:Load Balancing by paulddraper on Tuesday April 18, 2023 @11:36AM (#35615423)
Re:Load Balancing by throwaway71271 on Tuesday April 18, 2023 @11:09AM (#35614996)
'once and only once' anything is hard, including connection oriented designs, also sync calls can fail in quite similar ways as async calls as per FLP/CAP

the truth is that sync calls (in normal aws + k8s example) have like 50 queues between the user's kernel and your program actually doing the work, just considering the listen(2) queues, and the network card queues, and the reality is that every one of them can just drop packets on the floor whenever it wants

so in reality, network programming is hard, and even sync things are just a collection of many async pieces from the network card to the userspace

Re:Load Balancing by mholt on Tuesday April 18, 2023 @11:05AM (#35614944)
In Caddy we've implemented "dynamic upstream modules" which allow an arbitrary (compiled-in) plugin to give the reverse proxy a list of upstreams that can take the request. A pull-based mechanism could relatively easily be constructed with this feature: https://caddyserver.com/docs/json/apps/http/servers/routes/h...

I could imagine a dynamic upstream module that receives UDP or TCP packets from backends with a number estimating how many connections it can handle at that time. The module then tells the reverse proxy which upstream has the highest number and the reverse proxy selects it.

Re:Load Balancing by zokier on Tuesday April 18, 2023 @12:53PM (#35616562)
That sort pull architecture is interesting thought. I do see it working best when a worker nodes ability to do work is very clear cut, i.e. the response time does not significantly vary with the number of concurrent requests it is handling.

Here is an example where it would not work well: lets imagine workers are doing a CPU bound task and each worker has one cpu (for simplicity), but we have also identified that we can handle up to 10 requests concurrently on one worker, but they will be just slower (because they will get smaller slices of cpu). Ideally we'd wish the requests to be divided equally between the workers, but with naive pull model one worker could greedily grab requests up until its at capacity while the other workers stay idle, making the response times worse than they need to be.

Re:Load Balancing by throwway120385 on Tuesday April 18, 2023 @03:01PM (#35618407)
With a pull architecture you wouldn't identify a request queue depth up front. Rather, each incoming connection gets delayed until a worker attaches to EG the TCP stream. If you're serving a webpage the client wouldn't see anything other than a little load lag, especially if your load balancer took care of the TLS connection before pausing to wait for a worker.

So if you can handle every incoming request with one worker that worker gets them all. Otherwise each worker pops off the stack as it becomes free. And if you can service more concurrent requests you just add more workers.

Re:Load Balancing by zokier on Tuesday April 18, 2023 @03:36PM (#35618947)
> So if you can handle every incoming request with one worker that worker gets them all. Otherwise each worker pops off the stack as it becomes free

As I alluded, that works great if "can handle" and "being free" are clear-cut binary properties. But for complex applications when you are driving for high utilization while keeping latency down those questions become complicated; a worker might have some free capacity to handle requests but it doesn't mean that it would produce response as quickly as some other (more idle) worker.

In other words, the problem is not just assigning requests to workers that can handle them but assigning requests to workers that can handle them with lowest latency.

Re:Load Balancing by preseinger on Wednesday April 19, 2023 @06:59PM (#35634379)
tcp is a layer well below what we're discussing here

"handling a request" is something that is defined at the application layer

Re:Load Balancing by mgoetzke on Wednesday April 19, 2023 @01:12AM (#35624482)
Peter Hintjens wrote a lot of different protocols in https://zguide.zeromq.org/docs/chapter4/#Service-Oriented-Re... and they mostly are part of the spec https://rfc.zeromq.org/spec/18/ now.

Some of these protocols are a good improvement when looking for the ultimate in speed and I used them where applicable, but as a first order approximation a simple load balancer approach is quite good enough. Especially when you do not have dedicated people vested in that domain for maintenance.

Re:Load Balancing by preseinger on Thursday April 20, 2023 @11:17AM (#35641443)
if your load balancer holds on to each received request until a downstream server happens to pull that request and process it, then it's not a load balancer, it's a queue

different concept, different semantics, different results