Fair Proxy Balancer

Hey Grzegorz,

First, actually thank YOU for coming up with the balancer. It’s made my
life much easier. And please, keep the round-robin behaviour as-is! I
mean, it’s a great way to tell if you’re running too many mongrels
and/or
too many nginx connections.

-Rob.

Hi Rob. This is encouraging news and I am working on a setup to
incorporate this into my process. I would really like to hear if there
has been any attempt to evaluate the fair proxy balancer in relation to
other balancing schemes. From the standpoint of server resources, it is
attractive and much simpler than the haproxy or lvm for setup. I realize
speed is subject to all sorts of additional parameters but a comparison
of the balancer with others would be quite interesting.

Rob, can you elaborate a bit more on your mongrels situation. I do not
use ruby but have a similar situation other types of backend servers. In
the current scenario, the last server will always get less hits. Are you
setting some sort of threshold to determine how many mongrels to run (or
just starting up mongrels until the last is getting no hits). Many
thanks.

Regards,
David

Hi,

On Wed, Feb 06, 2008 at 10:07:08AM -0400, David P. wrote:

Hi Rob. This is encouraging news and I am working on a setup to
incorporate this into my process. I would really like to hear if there
has been any attempt to evaluate the fair proxy balancer in relation to
other balancing schemes. From the standpoint of server resources, it is
attractive and much simpler than the haproxy or lvm for setup. I realize
speed is subject to all sorts of additional parameters but a comparison
of the balancer with others would be quite interesting.

(disclaimer: I wrote upstream_fair, I’m biased).

No, I haven’t compared haproxy or lvs (I assume that was what you
meant). However, haproxy is a TCP forwarder which makes it uncomfortable
at times. For example, even if your backends are down, connections to
haproxy will succeed and the only thing haproxy can do is to reset your
new connection (even though nginx has already happily sent the request).
This is a bit different than a failed backend, which returns a system
error (connection refused) or times out. Besides, AFAIK haproxy does not
offer least-connection balancing.

LVS, I cannot comment (haven’t used it) but it has a wider choice of
balancing algorithms, including weighted least-connection. If you have
the resources to set it up (looks a bit hairy to me), it should perform
very well.

Rob, can you elaborate a bit more on your mongrels situation. I do not
use ruby but have a similar situation other types of backend servers. In
the current scenario, the last server will always get less hits. Are you
setting some sort of threshold to determine how many mongrels to run (or
just starting up mongrels until the last is getting no hits). Many thanks.

Hmm, let me use your message to reply to Rob too :slight_smile:

First, actually thank YOU for coming up with the balancer. It’s made my
life much easier. And please, keep the round-robin behaviour as-is! I
mean, it’s a great way to tell if you’re running too many mongrels and/or
too many nginx connections.

Unfortunately, pure WLC behaviour causes problems for mongrel as it
apparently doesn’t like to be slammed too hard (looks like it leaks
memory but that’s just a guess).

In the newest snapshot I added (or rather fixed) the round-robin part.
I’ll make it configurable, but the default will probably be round-robin
from now on. But yes, it is handy.

Best regards,
Grzegorz N.

Hi. Both haproxy and lvs have setups that are more involved for sure.
haproxy 1.3 has more balancing algorithms than 1.2. I have seen patches
that provide least connection balancing for 1.2 also. lvs is what I
believe to be ‘the’ mainstream balancer but needs to be compiled into
the linux kernel - it as not as portable and simple as incorporating the
fair proxy balancer as a result. Interested in Rob’s experience to
determine no of servers. Many thanks Grzegorz.

Regards,
David

On Feb 6, 2008, at 10:44 AM, David P. wrote:

Hi. Both haproxy and lvs have setups that are more involved for
sure. haproxy 1.3 has more balancing algorithms than 1.2. I have
seen patches that provide least connection balancing for 1.2 also.
lvs is what I believe to be ‘the’ mainstream balancer but needs to
be compiled into the linux kernel - it as not as portable and simple
as incorporating the fair proxy balancer as a result. Interested in
Rob’s experience to determine no of servers. Many thanks Grzegorz.

Regards,
David

Hey David-

We’re running the fair balancer on about 100 servers with good
success. We had some issues with the fair balancer in lower load
situations only sending requests to the first backend instead of doing
a round robin when under lower load, this was causing the single
backend to become overloaded. The latest version Grzegorz has just
pushed to his git repo works much better in all the situations we have
put it under.

We run LVS at the edge of our clusters and have LVS balance to nginx
on each VM with nginx doing fair balancing directly to the mongrels
and it is working great. Much fewer moving parts then throwing haproxy
in the mix. In my benchmarks having haproxy between nginx and the
mongrels was s lower since there was one more level of indirection. So
having nginx serving static content and fair balancing to the backends
is ideal for us.

Cheers-

Hi,

I’ve run into a behavioral difference between different versions of
nginx, but I’m not sure which behavior is expected…

I need to proxy a request for a dynamically-assembled javascript file
to a set of app servers, but want to serve static js files directly
from nginx. I want to compress both proxied and unproxied js files.

The config below works, but doesn’t return a compressed file for the
proxied request in all environments. Unproxied javascript requests
are compressed in all cases.

nginx-0.5.20 on FreeBSD-6.2:
returns compressed files for all /js/ paths, including proxied
nginx-0.5.30 on Solaris 10:
returns compressed files for local /js/ paths, but
returns UNcompressed files for all upstream proxied /js/ paths
nginx-0.5.35 on Solaris 10:
(same as nginx-0.5.30 on Solaris 10)

I couldn’t find anything in the 0.5.20 - 0.5.30 release notes that
looked like a relevant bugfix or intentional behavior change.

I realize the environment diffs are substantial, but I’m also not
sure from the docs whether this should work. :slight_smile: gzip_proxied
seems to control a conditional on the headers of the UA request,
and not be relevant to the gzip-or-not decision for the results
of upstream requests before returning to the UA. If it hadn’t
worked in 0.5.20 either, I’d assume that was the whole story.

The best answer might be “Hmm, weird, but you should just cache
the first request to /js/all.js and let nginx treat it as local
thereafter anyway”. Fair enough, but it adds some complexity
elsewhere that I’d like to avoid for now.

Here are the relevant bits of the config file:

handle static files directly

location ~ ^/(js|css|themes)/
{
root /path/to/docroot

gzip_types text/javascript text/css text/plain text/js
application/x-javascript application/javascript;
gzip_proxied any;

if ( $uri ~ ^/(js|css)/ ) { gzip on; }

force proxy for all.js, as it is ephemeral

if ( $uri = “/js/all.js” )
{ proxy_pass http://appservers; break; }
}

Thank you for any insights!
Andrew

Hi Ezra. Cool. The setup I am looking at is quite similar so great to
hear it is doing the job well. Many thanks for sharing your experience.

Regards
David

On Feb 6, 2008 4:41 PM, Grzegorz N. [email protected] wrote:

No, I haven’t compared haproxy or lvs (I assume that was what you
meant). However, haproxy is a TCP forwarder which makes it uncomfortable
at times. For example, even if your backends are down, connections to
haproxy will succeed and the only thing haproxy can do is to reset your
new connection (even though nginx has already happily sent the request).

Could you explain what you mean by “if your backends are down,
connections to haproxy will succeed”? By backend, do you mean Nginx
or, say, a Mongrel server?

Alexander.

On Fri, Feb 08, 2008 at 04:29:27PM +0100, Alexander S. wrote:

On Feb 6, 2008 4:41 PM, Grzegorz N. [email protected] wrote:

No, I haven’t compared haproxy or lvs (I assume that was what you
meant). However, haproxy is a TCP forwarder which makes it uncomfortable
at times. For example, even if your backends are down, connections to
haproxy will succeed and the only thing haproxy can do is to reset your
new connection (even though nginx has already happily sent the request).

Could you explain what you mean by “if your backends are down,
connections to haproxy will succeed”? By backend, do you mean Nginx
or, say, a Mongrel server?

Say you have:

nginx → haproxy → (a bunch of backends)

When nginx connects to haproxy, the connection will succeed (as haproxy
is still alive) but when haproxy tries to connect to any backend (let’s
say they’re all dead or a switch failed etc.), the connection
(haproxy->backend) will eventually time out. However, from nginx’s point
of view, the connection succeeded (haproxy replied), so it sends the
request which then times out or dies with a connection reset.

If you had several haproxy instances, each fronting its own set of
mongrels, you’d have just lost a request unneccessarily [sp?].

Note, I don’t know whether haproxy is smart enough to shut down its
listening socket when all backends fail (it might be). I rather meant to
say that a TCP forwarder must explicitely support such situations to
handle them.

Best regards,
Grzegorz N.

On Feb 8, 2008 4:47 PM, Grzegorz N. [email protected] wrote:

When nginx connects to haproxy, the connection will succeed (as haproxy
is still alive) but when haproxy tries to connect to any backend (let’s
say they’re all dead or a switch failed etc.), the connection
(haproxy->backend) will eventually time out. However, from nginx’s point
of view, the connection succeeded (haproxy replied), so it sends the
request which then times out or dies with a connection reset.

I see. That’s a valid point.

Actually, I never considered that one might use HAProxy behind Nginx
in the first place. Rather, I assumed HAProxy would be a more
naturally placed before Nginx, if one wanted, say, a more strictly
layered setup where a dedicated proxy did the proxying and a web
server such as Nginx did the static file serving.

Alexander.

On Sat, Feb 09, 2008 at 01:33:56AM +0100, Alexander S. wrote:

Actually, I never considered that one might use HAProxy behind Nginx
in the first place. Rather, I assumed HAProxy would be a more
naturally placed before Nginx, if one wanted, say, a more strictly
layered setup where a dedicated proxy did the proxying and a web
server such as Nginx did the static file serving.

Yes, that would be more natural for me too. However, the question was to
compare upstream_fair and haproxy. In order to compare them in any way,
you’d have to put haproxy behind nginx or set up haproxy in front of a
cluster of nginx instances, each fronting one backend.

In both of these setups, the nginx load balancer will be replaced by
the one from haproxy (the difference is the number of nginx instances),
so it would be possible to compare the two load balancers somehow.

Best regards,
Grzegorz N.

Grzegorz N. wrote:

Please give the module a try and report any issues you might find.

This module works great, thanks for releasing it. While validating its
behavior, I noticed a few gotchas that I wasn’t expecting, but I’m not
sure if there is anything upstream_fair can do about it:

  1. If a client performs a request which is long running, and then gets
    fed up with waiting and closes the connection, upstream_fair marks the
    backend process as idle even though it is still servicing the request -
    I guess it is monitoring the front side of the connection rather than
    the back side…?

  2. If I have a long running request active on a mongrel, and nginx times
    it out (proxy_read_timeout defaults to 60s), the request is still
    running on the mongrel, but upstream_fair marks it as idle.

These gotchas can both cause upstream_fair to schedule requests on
mongrels that are not actually idle when there are other idle ones
waiting

Matt

On Mon, May 05, 2008 at 06:21:49PM +0200, Matt Conway wrote:

Grzegorz N. wrote:

Please give the module a try and report any issues you might find.

This module works great, thanks for releasing it. While validating its
behavior, I noticed a few gotchas that I wasn’t expecting, but I’m not
sure if there is anything upstream_fair can do about it:

I’m glad you like it :slight_smile:

  1. If a client performs a request which is long running, and then gets
    fed up with waiting and closes the connection, upstream_fair marks the
    backend process as idle even though it is still servicing the request -
    I guess it is monitoring the front side of the connection rather than
    the back side…?

  2. If I have a long running request active on a mongrel, and nginx times
    it out (proxy_read_timeout defaults to 60s), the request is still
    running on the mongrel, but upstream_fair marks it as idle.

upstream_fair doesn’t monitor anything by itself, it’s told by the nginx
core when a request is started and when it ends. So unfortunately I
cannot
do much about the issues you mention.

Igor, off the top of your head, do you know what status is passed to the
->free callback when a request times out? I could use it to penalise
that
backend somehow.

Anyway, when nginx closes the backend connection, there’s no way to know
what the backend is doing so it would be guessing at best (the backend
may finish half a second later or stay busy forever, we’ll never know).

These gotchas can both cause upstream_fair to schedule requests on
mongrels that are not actually idle when there are other idle ones
waiting

Since commit 4329e708 (Feb 2008) the round-robin mechanism should work
so this effect should be reduced to perform at least no worse than the
default round-robin balancer.

Best regards,
Grzegorz N.