Openshift: Survive to slashdot effect with Varnish

The problem.

A few days ago after adding my website to the Planet Python i got newbilly slashdotted. As i already posted about on OpenShift: First approach i am running this website on OpenShift and this is a quick guide so you do not make the same mistake.

The solution

If you can enable auto-scaling feature on OpenShift then a HAproxy will be automatically enabled on your gears. Using the default provided configuration by Red Hat you will be able to handle at max 256 concurrently openned connections on HAproxy. On the case of your Node.js gears if you consider that a single / request takes about ~200MB you will not be able to handle a big amount of traffic , also note that on thefree tier of OpenShift you will only have 3 small gears with about 1 GiB RAM on each one. So is time for cache requests and prevent them to execute Node.js. Here Varnish comes to play. The desired setup is something like:

browser -> Node Proxy -> Varnish Gear -> Node Proxy -> HAProxy -> App Gear  

Varnish is an awesome HTTP cache software, made by Poul-Henning Kamp it offers an embedded DSL language called VCL that allows you to modify the HTTP request (header, body), the TTL of the cached object, among other cool hacks.

The first step was to enable auto-scaling to a maximum of 2 ( remember: 3 available for free) using the following command:

rhc scale-cartridge ghost -a myapp --min 1 --max 2  

The second step is to create a varnish instance using this cartridge.

rhc app create -a frontend --type https://raw.github.com/mmcgrath-openshift/openshift-cartridge-varnish/master/metadata/manifest.yml  

The third and final step is to clone your application's repo and modify the default.vcl file to proxy your original HAproxy address. Mine configuration looks like (also available on this Github gist):

Please not that you have to override the req.http.host because HAproxy is used for virtual-host and not for direct hostnames. Also note that this setup is ready for ghost blog engine , so adapt it according to your application routes.

backend default {  
    .host = "your-app-domain.rhcloud.com";
    .port = "80";
}

sub vcl_recv {

    #Important: Overwrite the host using your application name, because
    #haproxy uses virtual hosts instead of qualified names.

    set req.http.host = "your-app-domain.rhcloud.com";

    if (req.http.cache-control ~ "no-cache") {
        set req.hash_always_miss = true;
    }

    set req.http.x-pass = "false";

    if (req.url ~ "^/(api|signout)") {
        set req.http.x-pass = "true";
    } elseif (req.url ~ "^/ghost" && (req.url !~ "^/ghost/(img|css|fonts)")) {
        set req.http.x-pass = "true";
    }

    if (req.http.x-pass == "true") {
        return(pass);
    }
    unset req.http.cookie;
}

sub vcl_fetch {  
    if (req.http.x-pass != "true") {
        unset beresp.http.set-cookie;
        if (beresp.status < 500 && beresp.ttl == 0s) {
            set beresp.ttl = 2m;
        }
    }
}

If you are using your own domain name, please don't forget to point your domain name to your varnish gear and also add that domain name to your list of aliases.

After this you should be able to proxy requests to your gears passing them through varnish and caching for at least 2 minutes. This will help you for sure to survive slashdot effects!.

Have fun!


Jorge Niedbalski

Jorge Niedbalski

Software Engineer , focused on automation.


View or Post Comments