Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#765 closed defect (wontfix)

should not perform consistent hash on empty string

Reported by: openid.yandex.ru/wenzowski Owned by:
Priority: major Milestone:
Component: nginx-module Version: 1.9.x
Keywords: Cc:
uname -a: Linux 21ec728a6488 3.19.0 #2 SMP Thu Mar 26 10:44:46 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.9.0 built by gcc 4.9.2 (Debian 4.9.2-10) built with OpenSSL 1.0.1k 8 Jan 2015 (running with OpenSSL 1.0.1f 6 Jan 2014) TLS SNI support enabled configure arguments: --prefix=/opt/nginx --pid-path=/run/nginx.pid --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_spdy_module --with-http_sub_module --with-mail --with-mail_ssl_module --with-stream --add-module=/tmp/build/naxsi-0d53a64ed856e694fcb4038748c8cf6d5551a603/naxsi_src

Description

When an upstream has consistent hashing enabled, eg.

upstream backend {
  hash $arg_a consistent;
}

and a request comes in that does not contain the GET argument a then $arg_a defaults to empty string and all requests are forwarded to the same upstream.

Consistent hashing should be disabled when provided an empty string.

Change History (4)

comment:1 follow-up: Changed 4 years ago by mdounin

  • Resolution set to wontfix
  • Status changed from new to closed

I don't see why an empty string should be special, and this contradicts to the documented compatibility with Cache::Memcached / Cache::Memcached::Fast.

If you want nginx to do something special if there is no parameter provided, you may configure fallback to $remote_addr like this:

map $arg_a $foo {
    "" $remote_addr;
    default $arg_a;
}

comment:2 follow-up: Changed 4 years ago by openid.yandex.ru/wenzowski

I'm missing something. How does hashing get disabled using a map?

The problem here is that empty string results in routing of all requests to the same upstream. I don't want to pin all empty strings to a specific remote address; if the hash function is operating on a falsey value it needs to be disabled entirely, otherwise traffic cripples whatever upstream empty string consistently hashes to.

Is this something that can be done without modification to the hash module? Thanks for your patience.

comment:3 in reply to: ↑ 1 Changed 4 years ago by openid.yandex.ru/wenzowski

As a workaround I'm doing

set_random $prng 0 99;
set_if_empty $arg_a $prng;

but this means I'm performing unnecessary overhead of consistent hashing a random number

Replying to Maxim Dounin:

I don't see why an empty string should be special, and this contradicts to the documented compatibility with Cache::Memcached / Cache::Memcached::Fast.

If you want nginx to do something special if there is no parameter provided, you may configure fallback to $remote_addr like this:

map $arg_a $foo {
    "" $remote_addr;
    default $arg_a;
}

comment:4 in reply to: ↑ 2 Changed 4 years ago by mdounin

Replying to openid.yandex.ru/wenzowski:

I'm missing something. How does hashing get disabled using a map?

Hashing won't be disabled, but map allows to effectively fallback to a different value to hash if a primary one is empty.

The problem here is that empty string results in routing of all requests to the same upstream. I don't want to pin all empty strings to a specific remote address; if the hash function is operating on a falsey value it needs to be disabled entirely, otherwise traffic cripples whatever upstream empty string consistently hashes to.

Is this something that can be done without modification to the hash module? Thanks for your patience.

Most trivial solution would be to route requests with an empty value to a different upstream.

Note: See TracTickets for help on using tickets.