After reading the limit_conn_zone and limit_req_zone documentation for Nginx, I was confused. Even though they both use the $binary_remote_addr
variable to store the key, they describe different sizes of space occupation. Is this a documentation error, please? How much space is needed to store a TCP connection state on a 64-bit platform?
From the description in limit_conn_zone.
Note that instead of
$remote_addr
, the$binary_remote_addr
variable is used here. The$remote_addr
variable’s size can vary from 7 to 15 bytes. The stored state occupies either 32 or 64 bytes of memory on 32-bit platforms and always 64 bytes on 64-bit platforms. The$binary_remote_addr
variable’s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses. The stored state always occupies 32 or 64 bytes on 32-bit platforms and 64 bytes on 64-bit platforms.
From the description in limit_req_zone.
Note that instead of
$remote_addr
, the$binary_remote_addr
variable is used here. The$binary_remote_addr
variable’s size is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses. The stored state always occupies 64 bytes on 32-bit platforms and 128 bytes on 64-bit platforms.
CodePudding user response:
Both of these directives define a zone in shared memory that contains mappings from a key to some state. You are mistaking the size of the key with the size of the state. Additionally, they do not have to use the $binary_remote_addr
variable as the key. In fact, you are the one who decides what variable is used as a key, through the first parameter to the directive (key).
By a mapping i mean a function/data structure which, given a key returns a value associated with that key. The same key will always return the same value. This is similar to a Dictionary (abstract data type) and can be implemented using a Hash Table (data structure). I am not 100% sure that NGINX implementation uses those types specifically but it is possible. Reading up on them would probably help you understand the topic better. However is it implemented, NGINX refers to such mapping as a "zone".
In both directives you define a zone and are able to specify what variable to use as the key. This will decide which requests/connections are grouped into the same value and which are not. $binary_remote_addr
is given as an example. In such case, all requests/connections which share the remote address will be grouped into one value in the zone.
Finally, for the stored state - this is the value that is associated with the key. You can imagine the abstract layout of the memory as:
[key1] ---> { some state stored in the zone, associated with key1 }
[key2] ---> { some other state, associated with key2 }
etc.
Now, what is important is that while they use the same key to index the data, each of these directives stores different information in the zone. The definition of both starts with:
Sets parameters for a shared memory zone that will keep states for various keys.
as this is a generic definition of a zone. What differentiates them is the sentence starting with "in particular":
In particular, the state stores the current number of excessive requests.
for limit_req_zone
or
In particular, the state includes the current number of connections.
for limit_conn_zone
.
Zone created by each directive will store different information in the state associated with the keys. In one case its the number of excessive requests and in the other its the number of connections. Since the information is different, it is natural that the size of it is also different. Thus, each directive describes the size of "stored state" as a different value. They may (but do not have to, you decide) use the same variable as the key, for example $binary_remote_addr
. In such case the sizes of keys will be the same, but they are unrelated to the size of the state associated with those keys in each of the zones.