NGINX load balancing hash: use cookie value if present, ip_hash if not

I'm trying to figure out how to do some if-else logic in NGINX's upstream load-balancing directive. Basically, I'd like to use the method:

hash $cookie_my_cookie_name consistent;

... if the cookie (my_cookie_name) is present. If that cookie is not present, then I'd like the upstream selection method to fall-back to the built-in:

ip_hash;

I haven't been able to find examples anywhere in NGINX's docs on how to 'try' one upstream selection method and if that can't work select an alternative method.

The scenario I'm a but worried about is if the cookie isn't present, the $cookie_my_cookie_name variable interpolates (at least in the logs) to -, which is a string, but will always hash to the same upstream server, which is exactly what I don't want. (Thus the test needs to be for the absence of the cookie, which, if present, will always hold a 'good' value.)

Any ideas?


Solution 1:

You should be able to transform your hash key using one or more map blocks.

Not tested:

map $cookie_my_cookie_name $my_hash_key
{
    ""      $remote_addr;
    default  $cookie_my_cookie_name;
}
upstream {
    hash $my_hash_key consistent;
}

I do not think what you describe in your question really serves most purposes well, though. As soon as the cookie is set, the upstream is likely changes - which may mean a user gets transferred to an upstream that does not have his history cached as soon as the cookie is set.

Instead, consider mapping the the hash key to something like a reasonably sized prefix of the IPv4/IPv6 address, and defaulting to the same mechanism for the cookie, so the default case and the upstream assigned based on the cookie resolves to the same value, initially.