Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use url pathname as upstream hash in nginx

Tags:

nginx

I have a nginx server with config to use queryparam as upstream hash. Url looks like below

http://www.my-server.com/xyz/WXYZ?abc=123

And configuration as below

upstream test {
    hash $arg_abc;
    ....
}

is there any possibility to use WXYZ part of URL as upstream hash?

WXYZ is dynamic value and xyz is always same and will be there.

this is what I tried,

location ~ ^/xyz/(.).*$ {
   hash $1
}
like image 472
Exception Avatar asked Aug 13 '15 17:08

Exception


2 Answers

Yes, as per the documentation for hash, you can only use it in the upstream context, so what you've tried won't work indeed.

However, why exactly do you need to use only a certain path from your URI, instead of the whole thing, if those other parts stay the same anyways? I think the idea is that the whole string is supposed to be further hashed anyways, so, even if all your URLs start the same, the hash function is still supposed to distribute everything evenly. So, you can most likely just use $request_uri or $uri as your hash.

Alternatively, if you still want to do it your way, you might try to use named pattern matching in your location (location ~ ^/xyz/(?<varForHash>.).*$ {…), and then use the variables from such matches ($varForHash) as your hash (you could probably even use $1 from your example, too, just in the proper context — upstream).

like image 90
cnst Avatar answered Oct 17 '22 19:10

cnst


The deployment guide explicitly said it's possible:

The generic hash method: the server to which a request is sent is determined from a user-defined key which may be a text, variable, or their combination. For example, the key may be a source IP and port, or URI:

upstream backend {
    hash $request_uri consistent;

    server backend1.example.com;
    server backend2.example.com;
}

The hash key is $request_uri which can be replaced with $arg_your_key but not sure is works with upstream block, however it should work as proxy_pass value:

location /xyz {
  proxy_pass http://localhost/$uri$is_args$args;
}

Not sure of requirements but if you need to use certain backend based on argument $arg_abc you need map function, like here:

map $arg_abc $backend_server {
 default  'serverdefault.domain.com:80';
 123 'server1.domain.com:80';
 234 'server2.domain.com:80';
 345 'server3.domain.com:80';
}

server {
 location / {
  proxy_pass http://$backend_server;
 }
}
like image 45
Anatoly Avatar answered Oct 17 '22 19:10

Anatoly