Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
HAProxy 1.8 (haproxy.com)
251 points by phil21 on Nov 1, 2017 | hide | past | favorite | 74 comments


> HAProxy is staying true to its principle of not accessing the disks during runtime and so all objects are cached in memory. The maximum object size is as big as the value of the global parameter “tune.bufsize”, which defaults to 16KB. > This is a general-purpose caching mechanism that makes HAProxy usable as a small object accelerator in front of web applications or other layers like Varnish. The cool thing here is that you can control how large the objects to cache and accelerate delivery should be.

If this is on a server with a few GB RAM, is there any reason not to use it as the only cache? Is there any reason not to set the bufsize to a few MB, for example (assuming memory is not a constraint)?

I have a somewhat complex setup with several micro services each served by a dynamic set of backends. Caching for some of it would be nice, but I couldn't figure out a way to use varnish (or other external cache) without ending up with 1 varnish instance per backend (a pain to maintain), introducing a single point of failure (one per service - and still a pain to maintain), or losing some of the benefit and power of haproxy as a frontend (with varnish in front of it).


If swap is not present, memory access can be deterministic.

Disk access can never be deterministic, which is terrible if you care about latency.


Also, I understand we can configure the objects max size (with tune.bufsize). But can we configure the whole cache size (ie. the number of tune.bufsize KB cached objects) ?


Yes, it's using a similar shctx to ssl, I just don't know how to configure it for now, let's wait for William to push a bit of doc first :-)


HTTP2, Multithreading and finally no more lost TCP Connections on Service Reload!

Awesome! Thank you!


HTTP2 on the frontend only though, a bit disappointing


Maybe wise though. Biting off http2 on both sides in a load balancer all at once might not be smart. Especially at the same time as multithreading.


I agree. I already offload SSL in HAProxy. I'm sure we'll see HTTP2 for frontend/backend communication eventually down the line, but this is a huge and big first step.


AFAIK, this is true of nginx also and from what I've heard in the past, they see no reason to change it.

I can't find it now, but I'm sure they had pretty compelling benchmarks that showed that with keepalive & low-latency networks, performance wise, there's little, if any, performance difference.


> AFAIK, this is true of nginx also and from what I've heard in the past, they see no reason to change it.

http2 backends support is on the roadmap https://trac.nginx.org/nginx/roadmap - so you can expect it to be implemented.


The reason would be so that the backend can take advantage of H2 features.


Look at Lyft's Envoy:

https://www.envoyproxy.io/


LOL this software does not even understand HTTP/1.0...


Based on your comments, I assume you're involved with HAProxy?

Is HTTP/1.0 (vs 1.1) actually used anywhere? Both versions are also compatible so what's the issue? Also seems rather disingenuous to say "even" when Envoy has plenty of other advanced features.


Server side is on its way for next release, haproxy 1.9.


This is really great news for those of us who use HAProxy as an Ingress controller in Kubernetes. Thank you @wtarreau and your team.

Disclaimer: We develop https://github.com/appscode/voyager which is a HAProxy based ingress controller for Kubernetes.


https://www.haproxy.com/blog/dns-service-discovery-haproxy/ (which is a link on the OP) says TTL on SRV records "is ignored by HAProxy as HAProxy maintains its own expiry data which is defined in the configuration".

Is this true for A records too?

If so, neither haproxy nor nginx expire cached A records.

Nginx Plus does, and a few nginx plugins do, however.

https://github.com/airbnb/synapse is a process that polls DNS, and updates haproxy config accordingly and SIGHUPs haproxy I've used synapse to solve this issue, but it's a moving piece I'd rather not have involved.


Yes, cached A records get expired in HAProxy (both community and enterprise).

HAProxy won't follow-up the TTL returned by the server. It's up to the administrator to decide how HAProxy should behave with DNS responses.

From my point of view, you don't need synapse any more if your usage of synapse is limited to this single feature.


While I'm excited to be able to use haproxy for this, one alternative on nginx is to store the hostname you want looked up dynamically in a variable, and use that variable in a proxy_pass directive or equivalent. E.g. "proxy_pass http://$backend:80;" will cause Nginx to pass the value $backend to any resolver you have defined dynamically without needing Nginx Plus.


I'm a bit confused about the runtime capabilities. Does "set server" mean I can register new frontends in runtime? I mean, if we have a static DNS that basically just has a wildcard entry that routes to HAProxy - can I add new routes dynamically at runtime there?

About persistence: Does HAProxy have IP-based session persistence, i.e. routing to always the same backend server for the same client IP, as long as that server is available?


I don't know about dynamic frontends but regarding your second question, I can confirm that HAProxy has session persistence capabilites.

Look up "stick" functions in HAProxy docs. You can even persist TCP connections.


Thank you!


No way to register new frontends, new binds neither new backends. We can only add/remove servers in backends for now. The "registration" you mentioned may happen later.

Please note that you can already do dynamic routing using ACLs or MAPS and updating your ACLs or MAPs content at runtime using the Runtime API (stats socket). there are "set map" and "set map" commands for this purpose.


Thank you. I think dynamic routing would serve our purposes. Am I correct that the map-file as well as the running state needs to be updated separately via commands? I.e. HAProxy syncs between map-file and its runtime state only at setup time, correct?

If so, I have a suggestion: Have a look at what traefik (and before that Hipache) are doing - they use a KVS for the config and sync at runtime, which is quite convenient for dynamic usecases IMO. For the dynamic mapping it would be a better fit than just a file that needs to be manually managed.


For ideas on how to make use of the Runtime API to keep servers in a backend up-to-date dynamically, you can also take a look at a HAProxy Kubernetes Ingress Controller implementation that makes use of it here https://github.com/jcmoraisjr/haproxy-ingress#dynamic-scalin...

After 1.8 releases we plan on contributing DNS SRV capability to the controller as well.


How can the arguably best piece of open source tech keep get better? The only thing I could ask for is a REST admin api to assist with my deploys.


> How can the arguably best piece of open source tech keep get better?

Letsencrypt support? I realize that's a big undertaking though. There is a Lua plugin, but it does depend on certbot being installed and running, which is a bit difficult if you use the docker image (there are some docker containers on github that achieve this by running supervisord in the docker container for cron/certbot and haproxy).

This is probably outside the scope of HAProxy really though, and could probably be implemented entirely as a lua plugin that handles ACME, maybe?

Kudos to the HAProxy devs and contributors. I've always been a fan and great to see them pushing forward with these big improvements.


> The only thing I could ask for is a REST admin api to assist with my deploys.

I run haproxy in docker - create a shellscript that allows your jenkins (or whatever you use) to send a SIGHUP to the haproxy container, and it will reload the config.


I'm currently working on getting this setup myself. I eventually decided to exposing /var/run/docker.sock to my Certbot container and have a posthook that sends -HUP to the HAProxy container, which has a wrapper script that forwards HUP to haproxy's PID.

It would be nice if I could just do this via the HAProxy admin socket .. or not even reloading the whole config but just tell it to rescan the SSL certs.


> I eventually decided to exposing /var/run/docker.sock to my Certbot container

Don't do this, please. It is a security risk as access to the docker socket can be used to take over the entire system as root.


Out of curiosity, do you use host networking for higher performance (latency, conn/s, etc.) on those containers, or use the default docker-proxy forwarding?


I use --net=host for the haproxy container because I dont want to restart the container every time I need to expose a new frontend port.

In fact this is my biggest issue with docker - that properties like bound ports or volumes cant be changed on the fly and without deleting the container.


> The only thing I could ask for is a REST admin api to assist with my deploys.

For now, there is one in HAProxy Enterprise, and it manages HAProxy's configuration file and triggers reload.

We're working on opening it, as soon as we have improved it: make it use both HAProxy Runtime API (stats socket) and configuration file to trigger reloads only when required.

Stay tuned as we say :)


Oh is there a plan to move it towards community?

Here I thought the one big feature is behind a paywall. Competing with https://traefik.io/ in that regard.


Have you tried hatop? Command line only, but very useful.


How about adding support for serving static files?


Maybe, but you can always put something more specialised behind it to do that. The fact that haproxy is light-weight makes it all the more brilliant in my opinion!


It's not a web server.


Let me say it again: no disks I/O in HAProxy at run time. Simply put an nginx locally and use HAProxy's cache (or nginx one).


If you want something in the spirit of HAProxy for serving static content, filed ( http://filed.rkeene.org/ ) is the fastest static HTTP/1.1 server in the world. Putting it behind HAProxy 1.8 for TLS and HTTP/2 would be trivial until those features are directly available.


I like the idea of doing one thing well, and being great at it. Out of curiosity, why depend on haproxy or something else to provide http/2 support? Wouldn’t it make filed even faster (by letting the client pull all assets in parallel) if it supported natively for serving static files? I’m imagining static web pages with a few images to load.

As always, appreciate your open source work! Thanks!


HTTP/2 has been on the To Do list for a while and is a great idea for any HTTP server that wishes to remain relevant. I just suggested HAProxy to be topical and address HTTP/2 right now.


>is the fastest static HTTP/1.1 server in the world

As you're the author and you're promoting your own work, may I ask what sort of testing this claim is supported on?


This claim is based on two parts: benchmarks users have performed and the fact that nobody has called me on the claim :-)

Seriously though if you have the time to benchmark it and compare to your favorite alternative please post the results !


Well, I didn't know it so I tried it on my laptop but sadly that doesn't reflect my observations. Injecting here with 2000 concurrent connections results in a very fluctuating load oscillating between 2000 and 31000 requests/s (column ^h/s) for a small object like mime.types :

   hits ^hits hits/s  ^h/s     bytes  kB/s  last  errs  tout htime  sdht ptime
  32871 32871  31515 31515  11997915 11503 11503     0     0 19.1 92.2 16.5
  41915  9044  20957  9450  15298975  7649  3449     0     0 23.4 128.0 30.8
  43968  2053  14651  2050  16048320  5347   748     0     0 8.3 59.1 9.8
  65994 22026  16494 22026  24087810  6020  8039     0     0 60.4 393.2 66.5
  69176  3182  13832  3182  25249240  5048  1161     0     0 70.1 393.2 109.8
  69176     0  11527     0  25249240  4207     0     0     0 0.0 0.0 0.0
  69176     0   9880     0  25249240  3606     0     0     0 0.0 0.0 0.0
  69746   570   8717   570  25457290  3181   208     0     0 941.4 1847.7 835.2
  69746     0   7748     0  25457290  2828     0     0     0 0.0 0.0 0.0
  69746     0   6973     0  25457290  2545     0     0     0 0.0 0.0 0.0
And after that it totally stops responding until I restart it. On 404 it's more around 37000. This is using 2 threads.

I looked at the code and saw a select() in use so that limits the number of concurrent connections to ~512 on recent libcs (1 fd for the socket, 1 fd for the file, 1024 total). Reducing the number of concurrent connections seemed to help a bit (it delayed the occurrence a bit).

Also it doesn't seem to support keep-alive so we can't get more performance on the client side by reducing the kernel-side work in the TCP stack.

I'm getting the same level of performance out of a single process on thttpd.

Doing the same stuff with haproxy gives me 72000 requests/s in close mode as well delivering a small object with the errorfile trick, at only 80% CPU (my load generator reached its limit), so I guess there's still room for improvement since it's possible to achieve twice the performance using 80% of a single thread on the same machine, and it reaches 88k using the cache. I don't know how other servers compare though, but I definitely think that some might get better results.


select() should definitely never get used -- it's only even compiled in to the executable if you enable the non-default option of "FILED_NONBLOCK_HTTP" which you almost certainly don't want. Did you compile filed in this way ? It sounds like you grep'd the source for select() but didn't actually see that it was #ifdef'd out.

The number of concurrent connections is limited by your resource limits and the fact that file descriptors are cached. You can tune the cache, but you should update your resource limits if so, this is documented here in the man page available here: http://filed.rkeene.org/fossil/home?name=Manual

It does support keep-alive and I have no idea why you think it doesn't ( http://filed.rkeene.org/fossil/artifact?ln=1130-1132%201240-... )

Using only 2 threads (way less than the default) is also very sub-optimal since most of those threads will be waiting for the kernel to deliver the file. On average filed does about 2 system calls before asking the kernel to send the file to the client -- One read() of the HTTP request, one write() of the HTTP response header, and then the sendfile() of the contents. There's no reason not to use more threads than 2 other than to limit I/O (since they do not increase CPU utilization significantly).


Also, thanks for the link to the code, I found the issue with keep-alive (in fact there are two such issues). The first one is that you're looking for the Connection header with the Keep-Alive value, but this is needed only for HTTP/1.0. In 1.1 it's by default so you will not always get it, it will depend on the browsers, proxies etc. The second thing is that checking for headers and values this way is very unreliable as the connection header can contain other stuff, like "TE" to indicate that the TE request header field is present and must not be forwarded to next hop. In this case, the Connection header tokens are delimited by commas and you don't know either if it will match. One could argue that all these cases are not very common in field but it's the difference between being spec-compliant thus interoperable and working most of the time :-)


So I could inject in keep-alive at 100 concurrent threads but it was very slow (2200 req/s at 12% CPU), idling on I-don't-know-what. And at 1000 threads (still 100 concurrent connections), it immediately ate all my memory and got killed by the OOM killer :

Out of memory: Kill process 7134 (filed) score 779 or sacrifice child Killed process 7134 (filed) total-vm:7680976kB, anon-rss:7140908kB, file-rss:1988kB, shmem-rss:100kB oom_reaper: reaped process 7134 (filed), now anon-rss:7143588kB, file-rss:1980kB, shmem-rss:100kB

7 GB for 100 connections is a bit excessive in my opinion :-)

There are definitely still a number of issues to be addressed before it can be used in production, you definitely need to have a more robust architecture and request parser first.


So you need as many threads as you're delivering parallel files ? That reminds me the late 90's when everyone started to discover how easy it was to deal with blocking I/O using threads until they discovered that threads are very slow since you have to suffer from context switches all the time. As a rule of thumb, you must never run more threads than you have CPU cores, or you'll get the taste of context switches.

And it's really hard to scale using a model requiring one thread per connection. You'll hardly stand one million concurrent connections this way, and this can definitely happen for large objects.


Are there any plans to add UDP support to HAProxy? I wanted to use HAProxy as a SIP/RTP proxy at my last job, but was unable to do so as we were pushing SIP and RTP as UDP.


Explain your use case on the mailing list. Absence of UDP support is due to lack of useful scenarios for it.


As someone who puts this as a "want" and certainly not a "need" - the answer is really just management simplicity. That and HAProxy is generally a joy to work with.

I already have a nice anycasted cluster of HAProxy servers that already have the battle tested BGP session teardown logic/etc. integrated - I really don't want to have to use a different load balancing method to HA my UDP services and re-do large portions of that tooling.

It's certainly an annoyance, and being able to define traffic in the same configuration file/syntax/etc. makes it much more maintainable for an ops vs. engineering group.


Fair comment - but I'm not using HAProxy anymore at my current job, so my use case has passed (for now).


and also that LVS does it well in kernel!


When opening the website, why do I get a credential storage prompt on Chrome (Android)?


If you scroll down, the page has a contact form with an email field.

Chrome detects that email field, and assumes it might be part of a login form. (Because it is <input id="email" name="email" […] type="text">).

That triggers that.


Same, weird


Multithreading support. Holy cow yes.

All around good stuff, but I can't wait for multithreading.


Can't wait the release to push it to production servers. Once again HAProxy offers a great software and great evolutions.


wow this is huge: https://www.haproxy.com/blog/dns-service-discovery-haproxy/ h2 only on the frontend, as expected.


That is superb! I love haproxy but although it's rugged and rock-solid it's always seemed like a relic from the old way of doing things. Adding service discovery brings its reliability into a microservice age. Awesome.


Also HTTP Small Object Caching, i wonder how it compares to varnish in performance.


The purpose is not to compare to varnish. If you need a real cache, please use varnish. haproxy is to the cache what varnish is to the load-balancer. Ie: we both do a little bit of it to simplify certain deployments, but serious ones need both. We did this to address certain regular demands from users of dirty servers suffering from just "GET /favicon.ico" (hence the "favicon cache" term we've been using for a long time). I've been annoyed by seeing people abusing the "errorfile 503" to deliver a few static objects and this is an elegant response to address this. Over time it may turn out that it could combine well with varnish, for example to improve a little bit the scalability of haproxy+varnish nodes, we'll see. But it definitely is not at all an alternative to varnish.

As a rule of thumb, I'd say that if you have a cache, keep it. If you only have haproxy, you can try with a few rules to enable very basic caching and see if that improves the situation for you. Then you'll get a better idea about what would be required in your application to deploy an advanced cache and what benefits it could bring.


Very excited for HTTP/2 support to finally make it to HAProxy.


What use is http/2 in frontend only? No server-side pushes, the only thing I can imagine is a tiny bit less bandwidth due to binary headers.


HTTP/2 was designed for high latency networks. It supports stream multiplexing and headers compression to significantly shrink page load time over the internet. It has very limited use on the local network. Regarding server-side push, it brings about as many issues as benefits and is often counter-productive. Hopefully it will totally disappear when Early Hints are standardized (addressing the same benefits without the issues).

That said, we still want to address server-side H2 in 1.9 to address the CDN type of workloads where the origin servers might be far away. But that's less important.


gRPC is also a good candidate for end-to-end HTTP/2 :)


Haproxy would usually be on the same network as your www servers so even without http2 the response time for the backend requests will be tiny compared to the client <-> haproxy roundtrip time.

The promise of http2 is to lower latency on the client side and having H2 on the frontend will help with that.


Fewer concurrent connections for the client if you have a resource heavy page. Http 1.1 still gives you stair stepped responses if you have a large chain of dependencies. Chrome halts concurrent connections around 10 or so.


The horrible "modern" web design scared me. Then I realised I was at haproxy.com, not .org.


You really don't like that design? What's wrong with it? To my eye it doesn't contain any of the cliches of bad modern design.


Any plan to have HTTP/2 on the backend?


when will have server side HTTP2 multiplex load balance?


The connection has timed out

The server at www.haproxy.com is taking too long to respond.

Not the best advert for a high availability proxy...




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: