Tuesday, February 14, 2012

VCL Random url part

Random is random, usually. Unless it's being fetched every 20th minute and included as a part of a site with heavy traffic. That's a lesson I learned the hard way by relying on an ad networks RSS aggregator that included one of our RSS feeds on it's pages. The feed is randomized on our end with a list of nodes that are straight out of Views via some custom theming. The nodes are grouped in threes from a larger set.

What I noticed was that over 24 hours, what should have been an even distribution turned out to be heavily weighted towards one specific set. The ad networks RSS aggregation ran on a schedule and as bad luck would have it, Views liked to display the same set every time the RSS aggregator made a visit. Probably just bad luck but to the customer it looked like one set of nodes were favored over the others.

As I run Varnish for caching I started thinking about if I could do this in another way. I thought about faux round-robin directors and complicated solutions involving dns aliases and htaccess rewrites.

Then I stumbled upon this blogpost by Chris Davies who is just generally speaking one of the most knowledgeable techies I know of. So enter inline-C for my VCL.

sub vcl_recv{
    if (req.url == "/randomizeme") {
C{
char buff[5];
sprintf(buff, "%d", rand()%4+1);
VRT_SetHdr(sp, HDR_REQ, "\017X-Distribution:", buff, vrt_magic_string_end);
}C
        set req.url = "/randomizeme/" req.http.X-Distribution;
    }
 }

It works like this:
- Varnish picks up the request on url /randomizeme
- Varnish executes the inline C
- Varnish sets a special header with the randomized integer (the header works as a variable)
- Varnish then rewrites the url to /randomizeme/1-4
- Varnish finally fetches the above url from the backend which is rigged to display different content depending on which "slot" is chosen.
- Varnish delivers the randomized content to the visitor/aggregator/whatever

A little warning: If you modify the header name "X-Distribution", note that the "\017" must be updated, it's octal for the length of the string. I forget if it should include the ":" or not. Trial and error, watch that log for segfaults!

3 comments:

  1. Cool! So if I understand you correctly - you moved the randomization from Drupal to Varnish?

    I've personally never used C in VCL before. Will it compile when you start Varnish or must you initiate that manually? It's not interpreted, is it?

    ReplyDelete
  2. Hi Tobias. Yes, I moved the randomization to Varnish. VCL _is_ C so it's always compiled when you do a vcl.load . Actually I do something very C in the top of my VCL which is the following:

    C{
    #include
    #include
    }C

    ReplyDelete
    Replies
    1. wth, damn it censored my comment haha....

      C{
      #include <stdlib.h>
      #include <stdio.h>
      }C

      Delete