3

I am trying to set up nginx and I don't get the point how to do the following setup:

I have an URL http://somehost.com/foo/bar/123/xxx_xxx that needs to be passed to different backends depending on a range the '123' matches (e.g. 0-150 -> backend1, 151-400 -> backend2, ...).

Since I have almost no experience with regexp, I don't know how to do this (in location?).

Thanks in advance for your help, Sascha

Sascha
  • 538
  • 2
  • 5
  • 12
  • I think you should ask this on http://Serverfault.com instead. – Jonas May 12 '11 at 08:25
  • This would be too complicated, unobvious and possible buggy regex. What you're trying to achieve, load-balancing? – Timofey Stolbov May 12 '11 at 09:06
  • The number would be the resolution of an image. We have 4 different backends to deliver these images and we want load-balancing in the form, that all images with res <150 go to backend1, 151-400 to backend2... –  May 12 '11 at 10:35

2 Answers2

3

If you have a static set of the picture sizes, you can make use of map. Declare backends and a map in http section of Nginx configuration file:

http {
  upstream backend1 {
    server backend1:80;
  }

  upstream backend2 {
    server backend2:80;
  }

  map $pic_size $backend {
    default backend_default;
    80 backend1;
    150 backend2;
  }
}

Declare the location in server:

location ~ ^/foo/bar/(?<pic_size>\d+) {
  proxy_pass http://$backend;
}

If you'd like to support conditional logic, I would recommend using Perl handler. Again, in http:

http {
  perl_set $backend 'sub {
my $r = shift;
my $pic_size = $r->variable("pic_size");

$pic_size <= 150 and return "backend1";
$pic_size <= 400 and return "backend2";
return "backend_default";
}';
}

In location:

location ~ ^/foo/bar/(?<pic_size>\d+) {
  proxy_pass http://$backend:80;
}
Alexander Azarov
  • 3,550
  • 21
  • 19
  • The $map was a huge help to me with a related problem I was trying to figure out (how to selectively forward a particular URL to a backend, though based on a text string rather than numeric) without resorting to use of the dreaded "if". Thanks! – jsh Jan 17 '13 at 16:29
2

You can use:

location ~ ^/foo/bar/(\d|\d\d|1[0-4]\d|150)/ {
    proxy_pass backend1;
}

location ~ ^/foo/bar/(15[1-9]|1[6-9]\d|[23]\d\d|400)/ {
    proxy_pass backend2;
}
...

But why you do load balancing in such a heterogeneous way? Why not just shard by image id/hash of name? Your solution will result in different load and even load patterns on different servers. It would be tricky to administer them.

Suor
  • 136
  • 3
  • Thank you, your solutions seems to work great on my testing machine! The reason for this kind of load-balancing is, that some resolutions are requested more often than others and in this way we are able to share the load constantly. However the backends are nodes in a cluster that create the requested resolution on the fly (original image is in an oracle db) and keep them in a cache. In my opinion, this is not the right way, but this was not my decision ;-) However: Thank you very much!! – Sascha May 16 '11 at 06:24