HAproxy + Wt: a good good match

  • Posted by koen
  • Wednesday, November 24, 2010 @ 16:35

Since we have added WebSockets support to the latest git (I’ll talk about this in detail in another blog post), we need to revise the deployment solutions for Wt.

In this post I will explain why HAproxy is an excellent reverse proxy choice for use with Wt’s built-in httpd.

WebSockets as a protocol can be multiplexed on the same port as the HTTP web server, and this is how Wt implements WebSockets (using its built-in http). Since WebSockets isn’t supported by the FastCGI protocol (and unlikely ever will be), nor by IIS/ISAPI (but probably will be some day), using WebSockets currently mandates the use of Wt’s built-in httpd.

For production deployments, except for embedded systems, it is unlikely that you will be running Wt’s httpd on port 80 simply because it has fairly limited options compared to mainstream web servers (e.g. virtual hosts, multiple appications, etc…). Instead you can use another reverse proxy (or web server), perhaps even on another host, which listens for your web domain on port 80, and which relays requests to Wt back-end servers.

To not negate the nice capabilities and properties of Wt, a suitable reverse proxy solution thus:

  • supports reverse proxying of WebSockets

  • uses async I/O to scale to many connections

  • supports session affinity not using cookies, but using URL rewriting.

In particular the two first options limit the list of possible reverse proxy solutions. Besides HAproxy, we are only aware of nginx as a mainstream solution that uses async I/O, but nginx not support the reverse proxying of WebSockets (or indeed any persistent connection to a back-end).

The good news is thus that HAproxy provides all three requirements. We could have predicted it from their domain name: omen est nomen.

The following is an example of a HAproxy configuration that uses load-balancing to two back-ends:

global
    log 127.0.0.1 local0
    log 127.0.0.1 local1 notice
    maxconn 4096
    user haproxy
    group haproxy
    daemon

defaults
    log    global
    mode    http
    option    httplog
    option    dontlognull
    retries    3
    option redispatch
    maxconn    10000
    contimeout    5000
    clitimeout    50000
    srvtimeout    50000

frontend wt
        bind 0.0.0.0:80
        acl srv1 url_sub wtd=wt1
        acl srv2 url_sub wtd=wt2
        acl srv1_up nbsrv(bck1) gt 0
        acl srv2_up nbsrv(bck2) gt 0
        use_backend bck1 if srv1_up srv1
        use_backend bck2 if srv2_up srv2
        default_backend bck_lb

backend bck_lb
        balance roundrobin
        server srv1 0.0.0.0:9090 track bck1/srv1
        server srv2 0.0.0.0:9091 track bck2/srv2

backend bck1
        balance roundrobin
        server srv1 0.0.0.0:9090 check

backend bck2
        balance roundrobin
        server srv2 0.0.0.0:9091 check

And then start two Wt built-in httpd processes:

$ app.wt --session-id-prefix=wt1 --http-port 9090 ...
$ app.wt --session-id-prefix=wt2 --http-port 9091 ...

In this example setup, we are running the different Wt backend processes on the same host as HAproxy, which may make sense if you want to spread the disaster factor of a process going down because of a bug and taking down all other sessions in the process.

But of course you can use the same schema to distribute the load to different back-end servers.

Tags:
3 comments
  • Posted by anonymous
  • one year ago
Still works (with minor changes) in 2023.
  • Posted by wildcarde
  • 13 years ago
Could you achieve a similar behavior using the apache distributed proxy system? I don't assume the performance would be as good but it would make it easier to roll out HA applications in line with the rest of a web-server.
  • Posted by anonymous
  • 14 years ago
This is exactly what I've been looking for :)
Thanks guys!
Dushan

Contact us for more information
or a personalised quotation