Linux

[Redis][Doc] Redis Clients Handling

Binceline 2013. 10. 7. 22:45

Client 연결을 어떻게 수행하는지에 대한 문서이다.

Redis Clients Handling

이 문서는 networklayer의 관점에서의 클라이언트와의 connections, timeouts, buffers, 그리고 다른 비슷한 주제들에 대해 어떻게 수행하는지에 대한 정보를 제공한다. 

이 문서가 포함하고 있는 정보들은 오직 Redis version 2.6 이상에서만 가능하다.


How client connections are accepted

어떻게 클라이언트 연결이 액셉트되는가

Redis accepts clients connections on the configured listening TCP port and on the Unix socket if enabled. When a new client connection is accepted the following operations are performed:

Redis가 enable되었다면 listen 상태인 TCP port와 Unit socket에 클라이언트의 커넥션을 허용한다. 새로운 클라이언트가 커넥션할 때는 다음 연산이 수행되는 것을 허용한다.

  • The client socket is put in non-blocking state since Redis uses multiplexing and non-blocking I/O.
  • The TCP_NODELAY option is set in order to ensure that we don't have delays in our connection.
  • readable file event is created so that Redis is able to collect the client queries as soon as new data is available to be read on the socket.
  • -----------------------------
  • Redis가 multiplexing과 non-blocking I/O를 사용하기 때문에 클라이언트 소켓은 non-blocking 상태로 전환한다.
  • TCP_NODELAY 옵션은 연결에 딜레이가 없는지 확인하기 위해 설정한다.
  • Redis가 즉시 소켓에서 새로운 데이터를 읽어 클라이언트 쿼리들을 모을 수 있기 때문에 readable 파일 이벤트가 생성된다.

After the client is initialized, Redis checks if we are already at the limit of the number of clients that it is possible to handle simultaneously (this is configured using the maxclients configuration directive, see the next section of this document for further information).

그 후 클라이언트가 초기화되고, Redis는 이미 동시에 수행 가능한 클라이언트의 수의 limit을 검사한다(이것은 maxclients 구성 지침을 사용하는 것으로 구성되고, 이 문서를 좀 더 읽다 보면 그에 대한 자세한 정보를 볼 수 있다).

In case it can't accept the current client because the maximum number of clients was already accepted, Redis tries to send an error to the client in order to make it aware of this condition, and closes the connection immediately. The error message will be able to reach the client even if the connection is closed immediately by Redis because the new socket output buffer is usually big enough to contain the error, so the kernel will handle the transmission of the error.

클라이언트들이 최대치로 이미 액셉트되어서 현재 클라이언트를 액셉트할 수 없는 경우, Redis는 이 상황을 알리기 위해 클라이언트로 에러를 보내는 걸 시도한다. 그리고 즉시 연결을 종료한다 왜냐 하면 새로운 Socket output buffer가 일반적으로 에러를 포함할 가능성이 높기 때문이다. 그래서 에러 메시지는 연결이 종료된 경우조차도 Redis에 의해 즉시 클라이언트에 도달할 수 있을 것이다. 그래서 커널이 에러를 전달해 줄 것이다.


In what order clients are served

클라이언트가 어떤 순서로 보내는가

The order is determined by a combination of the client socket file descriptor number and order in which the kernel reports events, so the order is to be considered as unspecified.

However Redis does the following two things when serving clients:

그 순서는 클라이언트 소켓의 파일 디스크립터 번호와 커널이 이벤트를 알려주는 순서의 조화에 의해 결정된다.  그래서 그 순서는 정해져 있지 않다고 생각해야 한다.

그렇지만 클라이언트에 전송할 때 Redis는 다음과 같은 두 가지 작업을 한다.

  • It only performs a single read() system call every time there is something new to read from the client socket, in order to ensure that if we have multiple clients connected, and a few are very demanding clients sending queries at an high rate, other clients are not penalized and will not experience a bad latency figure.
  • However once new data is read from a client, all the queries contained in the current buffers are processed sequentially. This improves locality and does not need iterating a second time to see if there are clients that need some processing time.
  • -------------------------------------
  • 여러 개의 클라이언트가 연결되었는지 확인하기 위해 오직 새로운 어떤 것이 클라이언트 소켓을 read할 때마다 한 번의 read() 시스템 콜을 사용하는데, 몇 가지는 클라이언트가 빠른 속도로 쿼리들을 전송하는 것이 요구된다. 그리고 다른 클라이언트들은 penalize되고 bad latency(좋지 않은 지연시간) 형태는 볼 수 없을 것이다.

Maximum number of clients

클라이언트의 최대 수

In Redis 2.4 there was an hard-coded limit about the maximum number of clients that was possible to handle simultaneously.

In Redis 2.6 this limit is dynamic: by default is set to 10000 clients, unless otherwise stated by the maxmemory directive in Redis.conf.

However Redis checks with the kernel what is the maximum number of file descriptors that we are able to open (the soft limit is checked), if the limit is smaller than the maximum number of clients we want to handle, plus 32 (that is the number of file descriptors Redis reserves for internal uses), then the number of maximum clients is modified by Redis to match the amount of clients we are really able to handle under the current operating system limit.

When the configured number of maximum clients can not be honored, the condition is logged at startup as in the following example:

Redis 2.4에서는 동시에 수행 가능한 클라이언트의 최대 수를 제한하는 것에 대해 하드코딩된 것이 있었다.

Redis 2.6에서 이것은 동적이며, Redis.conf에서 maxmemory 지침으로 설정되지 않는다거나, 따로 설정하지 않는다면 기본적으로 10000 개의 클라이언트로 설정되어 있다.

그러나 Redis는 열 수 있는 파일 디스크립터(확인된 soft limit)의 최대치가 몇인지 커널을 이용해 확인하고, 만약 제한이 우리가 수행하기 원하는 클라이언트의 최대치보다 작다면 plus 32를 한다(이것은 Redis가 미리 내부적으로 사용하기 위해 할당받은 파일 디스크립터의 수이다.). 그 후 클라이언트의 최대 수는, 현재 운영체제 제한 이하에서 실제로 수행 가능한 클라이언트의 양과 같게 하기 위해 Redis에 의해 수정된다.

클라이언트의 최대 수로 구성되는 것이 honored할 수 없을 때, 그 상태는 실행될 때 다음 예제와 같이 기록된다.

$ ./redis-server --maxclients 100000
[41422] 23 Jan 11:28:33.179 # Unable to set the max number of files limit to 100032 (Invalid argument), setting the max clients configuration to 10112.

When Redis is configured in order to handle a specific number of clients it is a good idea to make sure that the operating system limit to the maximum number of file descriptors per process is also set accordingly.

Under Linux these limits can be set both in the current session and as a system-wide setting with the following commands:

Redis가 지정된 수로 클라이언트를 수행하기 위해 구성되는 경우, 이것은 운영 체제가 프로세스 당 파일 디스크립터의 최대치 제한이 적절히 설정되어 있는지 확인할 수 있는 좋은 방법이다.

  • ulimit -Sn 100000 # This will only work if hard limit is big enough. 
  • sysctl -w fs.file-max=100000


Output buffers limits

출력 버퍼 제한

Redis needs to handle a variable-length output buffer for every client, since a command can produce a big amount of data that needs to be transfered to the client.

However it is possible that a client sends more commands producing more output to serve at a faster rate at which Redis can send the existing output to the client. This is especially true with Pub/Sub clients in case a client is not able to process new messages fast enough.

Both the conditions will cause the client output buffer to grow and consume more and more memory. For this reason by default Redis sets limits to the output buffer size for different kind of clients. When the limit is reached the client connection is closed and the event logged in the Redis log file.

There are two kind of limits Redis uses:

명령이 클라이언트로 전송되어야 하는 많은 양의 데이터를 생산할 수 있기 때문에, Redis는 모든 클라이언트에서 variable-length(길이가 변하는) output buffer를 수행할 필요가 있다.

그러나 이것은 Redis가 output을 클라이언트에 전송할 수 있을 정도로 빠르게 전송하기 때문에 더 많은 output을 생산하는 더 많은 명령을 클라이언트가 전송하는 것이 가능하다. 클라이언트가 새로운 메시지들을 충분히 빠르게 수행할 수 없는 경우에, 이것은 Pub/Sub 클라이언트들에게는 특별한 사실이다.

양 쪽의 상황은 클라이언트의 output buffer가 커지고 더욱 많은 메모리를 소모하게 되는 원인이 될 것이다. 이러한 이유로 다른 종류의 클라이언트들을 생각해서 기본 Redis 설정을 output buffer size로 제한한다. 한계에 도달하면 클라이언트 연결은 종료되고 event는 Redis log파일에 기록된다.


Redis가 사용하는 제한은 두 가지가 있다.

  • The hard limit is a fixed limit that when reached will make Redis closing the client connection as soon as possible.
  • The soft limit instead is a limit that depends on the time, for instance a soft limit of 32 megabytes per 10 seconds means that if the client has an output buffer bigger than 32 megabytes for, continuously, 10 seconds, the connection gets closed.
  • -----------------------------
  • hard limit은 고정된 limit이고, 여기 도달하면 Redis는 가능한 한 빨리 클라이언트 연결을 종료할 것이다.
  • 반대로 soft limit은 시간에 따른 제한이다. 예를 들어 10초당 32MB의 soft limit은 클라이언트가 계속 10초당 32MB보다 큰 output buffer를 가지는 경우 연결이 종료된다.

Different kind of clients have different default limits:

다른 종류의 클라이언트들은 다른 기본 limit을 가진다.

  • Normal clients have a default limit of 0, that means, no limit at all, because most normal clients use blocking implementations sending a single command and waiting for the reply to be completely read before sending the next command, so it is always not desirable to close the connection in case of a normal client.
  • Pub/Sub clients have a default hard limit of 32 megabytes and a soft limit of 8 megabytes per 60 seconds.
  • Slaves have a default hard limit of 256 megabytes and a soft limit of 64 megabyte per 60 second.
  • -----------------
  • 일반 클라이언트들은 0일 때 기본 limit을 사용한다. 이것은 전혀 제한이 없다는 것을 뜻한다. 왜냐하면 가장 일반적인 클라이언트들은 하나의 명령을 전송하는 것과 다음 명령이 전송되기 전에 reply가 완벽하게 read되는 것을 기다리는 것 을 구현하는 데에 blocking을 사용하기 때문이다. 그래서 일반 클라이언트인 경우, 연결을 종료하는 것은 항상 바람직하진 않다.
  • Pub/Sub 클라이언트들은 기본적으로 60초당 32MB의 hard limit과 8MB의 soft limit을 가진다.
  • Slaves는 기본적으로 60초당 256MB의 hard limit과 64MB의 soft limit을 가진다.

It is possible to change the limit at runtime using the CONFIG SET command or in a permanent way using the Redis configuration file redis.conf. See the example redis.conf in the Redis distribution for more information about how to set the limit.

이것은 CONFIG SET 명령 또는 Redis 구성 파일인 redis.conf를 사용하여 영구적인 방법으로 런타임에 limit을 변경하는 것이 가능하다. 어떻게 limit을 설정하는 지에 대한 더 많은 정보는 Redis distribution의 redis.conf 예제를 봐라.

Query buffer hard limit

Every client is also subject to a query buffer limit. This is a non-configurable hard limit that will close the connection when the client query buffer (that is the buffer we use to accumulate commands from the client) reaches 1 GB, and is actually only an extreme limit to avoid a server crash in case of client or server software bugs.

모든 클라이언트는 쿼리 버퍼를 제한할 수 있다. 클라이언트 쿼리 버퍼가 1GB에 도달할 때 연결이 종료될 non-configurable hard limit이다. 그리고 실제로 클라이언트 또는 서버 소프트웨어 버그에 대해 서버 크래쉬를 피하기 위한 극단적인 제한이다.

Client timeouts

By default recent versions of Redis don't close the connection with the client if the client is idle for many seconds: the connection will remain open forever.

However if you don't like this behavior, you can configure a timeout, so that if the client is idle for more than the specified number of seconds, the client connection will be closed.

You can configure this limit via redis.conf or simply using CONFIG SET timeout <value>.

Note that the timeout only applies to number clients and it does not apply to Pub/Sub clients, since a Pub/Sub connection is a push styleconnection so a client that is idle is the norm.

최신 버젼의 Redis는 클라이언트와의 연결을 종료하지 않는다. 클라이언트가 매 초 놀고 있다면 연결은 영원히 열린 상태로 남을 것이다.

그러나 만약 이런 행동이 마음에 들지 않는다면, timeout을 따로 구성할 수 있다. 그래서 만약 클라이언트가 지정된 시간초보다 더 놀고 있다면, 그 클라이언트는 종료될 것이다.

이 제한을 redis.conf 또는 간단하게 CONFIG SET timeout <value>를 사용하여 구성할 수 있다.

결론은 timeout은 오직 Pub/Sub클라이언트가 아닌 클라이언트 수로 적용된다. Pub/Sub 연결은 push styleconnection이기 때문이다. 그래서 놀고 있는 클라이언트가 표준이다.


Even if by default connections are not subject to timeout, there are two conditions when it makes sense to set a timeout:

기본적인 연결이 timeout되지 않는 경우에도, timeout설정을 이해하기 위한 두 가지의 상황이 있다.

  • Mission critical applications where a bug in the client software may saturate the Redis server with idle connections, causing service disruption.
  • As a debugging mechanism in order to be able to connect with the server if a bug in the client software saturates the server with idle connections, making it impossible to interact with the server.
  • -------------------------
  • 클라이언트 소프트웨어가 idle 연결을 사용하여 Redis 서버를 포화시킬 수 있는 버그가 있을 때, Mission critical applications은 서비스 중단의 원인이 될 것이다.
  • 디버깅 메카니즘으로 서버와의 연결을 가능하게 한다. 만약 클라이언트 소프트웨어가 idle 연결을 사용하여 서버를 포화시키는 버그가 있다면, 그것이 서버와 상호작용하는 것을 불가능하게 한다.

Timeouts are not to be considered very precise: Redis avoids to set timer events or to run O(N) algorithms in order to check idle clients, so the check is performed incrementally from time to time. This means that it is possible that while the timeout is set to 10 seconds, the client connection will be closed, for instance, after 12 seconds if many clients are connected at the same time.

Timeout은 정확한 것으로 생각되지 않는다 : Redis는 놀고 있는 클라이언트를 체크하기 위해 timer event 설정 또는 O(N) 알고리즘을 피한다. 그래서 체크는 점진적으로 가끔 수행된다. 이것은 timeout이 10초로 설정되는 동안 그 클라이언트 연결이 종료되는 것이 가능하다는 것을 의미한다. 예를 든다면 12초 후 여러 클라이언트가 동시에 연결되어 있는 경우이다.

CLIENT command

The Redis client command allows to inspect the state of every connected client, to kill a specific client, to set names to connections. It is a very powerful debugging tool if you use Redis at scale.

CLIENT LIST is used in order to obtain a list of connected clients and their state:

Redis 클라이언트 명령은 모든 연결된 클라이언트들의 상태를 볼 수 있고, 지정한 클라이언트를 종료시킬 수도 있고, 연결에 이름을 설정할 수도 있다. 이것은 Redis를 사용하는 경우 매우 강력한 디버깅 툴이다.

redis 127.0.0.1:6379> client list
addr=127.0.0.1:52555 fd=5 name= age=855 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
addr=127.0.0.1:52787 fd=6 name= age=6 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping

In the above example session two clients are connected to the Redis server. The meaning of a few of the most interesting fields is the following:

위의 예제 세션에서 두 개의 클라이언트들은 Redis 서버에 연결되었다. 가장 흥미로운 field들 몇 가지의 의미는 다음과 같다.

  • addr: The client address, that is, the client IP and the remote port number it used to connect with the Redis server.
  • fd: The client socket file descriptor number.
  • name: The client name as set by CLIENT SETNAME.
  • age: The number of seconds the connection existed for.
  • idle: The number of seconds the connection is idle.
  • flags: The kind of client (N means normal client, check the full list of flags).
  • omem: The amount of memory used by the client for the output buffer.
  • cmd: The last executed command.
  • -------------------------
  • addr : 클라이언트 주소. Redis 서버로 연결된 클라이언트 IP와 원격 포트 번호이다.
  • fd : 클라이언트 소켓의 파일 디스크립터 번호
  • name : CLIENT SETNAME에 의해 설정된 클라이언트 이름이다.
  • age : 연결된 시간을 초로 나타낸 것이다.
  • idle : idle 시간의 초 단위 숫자이다.
  • flags : 클라이언트의 종류이다. (N의 의미는 normal 클라이언트라는 뜻이다. full list of flags를 확인해라).
  • omem : output buffer를 위해 클라이언트가 사용한 메모리의 양
  • cmd : 마지막 실행된 명령

See the CLIENT LIST documentation for the full list of fields and their meaning.

Once you have the list of clients, you can easily close the connection with a client using the CLIENT KILL command specifying the client address as argument.

The commands CLIENT SETNAME and CLIENT GETNAME can be used to set and get the connection name.

field들과 그 의미의 전체 목록을 보려면 CLIENT LIST 문서를 봐라.

클라이언트의 목록을 가진다면, 클라이언트 주소를 인자로 지정하는 것으로 CLIENT KILL 명령으로 쉽게 연결을 종료할 수 있다.

CLIENT SETNAME 과 CLIENT GETNAME 명령은 연결 이름을 set/get할 때 사용할 수 있다.

반응형