* TCP_DEFER_ACCEPT
timeout 인자는 3 way handshake 후에 서로의 ACK 패킷 미응답시의 timeout 설정을 의미하는것처럼 보인다.
실제 연결후 아무것도 하지 않아도 설정 시간(second)에 반응(timeout)하지 않는다.
3-way handshake 후에도 ACK 는 일정 주기로 주고 받고 있을 테니까...
그리고 Linux Kernel에서 TCP_DEFER_ACCEPT 옵션의 timeout 설정시 우리의 설정 시간을 무시 할 만한
어느정도 최소한의 timeout이 설정되어 있는 것으로 보인다.
linux 2.6.x kernel 의 net/ipv4/tcp.c 를 보면 밑의 부분이 보인다.
[root@bando kernel-source]# vi net/ipv4/tcp.c
case TCP_DEFER_ACCEPT:
.
.
if (val > 0) {
val > ((TCP_TIMEOUT_INIT / HZ)...
.
.
서버 애플리케이션에 TCP_DEFER_ACCEPT 옵션 적용후 nc, telnet 등으로 서버에 접속하고 아무런 행위도 하지 않으면 ESTABLISHED 되지 않고 SYN_RECV 로 나오게 된다. Maxclient를 50으로 설정한 Apache의 경우 TCP 연결 500개를 확립하고 아무런 행위도 하지 않을시에 실제 정상적인 HTTP 처리는 아무런 문제없이 진행 된다.
-----------------------------------------------------------------------------------------------------------------------
밑은 관련된 기사의 내용이다.
해석이 맞나? ^^ 그냥 원문 보는게...
하여간 내가 원하는 중요한 내용은 파란색 부분이다.
-----------------------------------------------------------------------------------------------------------------------
기사원문 : http://articles.techrepublic.com.com/5100-10878_11-1050771.html
TCP_DEFER_ACCEPT 는 리눅스에서 지원하는 socket option 옵션이다.
클라이언트가 TCP 연결 수행시 서버단에서 실제 데이타가 수신되기 전까지 곧바로 ESTABLISHED 를 수행하지
않고 기다리는 소켓 옵션 설정값이다. 구현의 목적은 실제 전송 패킷 수의 감소 그로 인한 지연 감소 그로 인한
성능 향상 목적등이 되겠다. TCP_DEFER_ACCEPT는 리눅스에서의 이름이고 같은 수행을 하는 옵션들이
다른 운영체제에서도 이름은 다르지만 존재하고 있다. 그리고 서버단이 아닌 리눅스 클라이언트단에서도
설정 가능하다.(마지막 ACK를 전송하지 않게 되는..즉 data와 함께 ACK flag 설정을 보내게 되는...)
리눅스에서의 사용은 밑처럼 하면 된다.
클라이언트가 TCP 연결 수행시 서버단에서 실제 데이타가 수신되기 전까지 곧바로 ESTABLISHED 를 수행하지
않고 기다리는 소켓 옵션 설정값이다. 구현의 목적은 실제 전송 패킷 수의 감소 그로 인한 지연 감소 그로 인한
성능 향상 목적등이 되겠다. TCP_DEFER_ACCEPT는 리눅스에서의 이름이고 같은 수행을 하는 옵션들이
다른 운영체제에서도 이름은 다르지만 존재하고 있다. 그리고 서버단이 아닌 리눅스 클라이언트단에서도
설정 가능하다.(마지막 ACK를 전송하지 않게 되는..즉 data와 함께 ACK flag 설정을 보내게 되는...)
리눅스에서의 사용은 밑처럼 하면 된다.
int timeout = 20;
setsockopt(sock, SOL_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int));
setsockopt(sock, SOL_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int));
timeout 인자는 3 way handshake 후에 서로의 ACK 패킷 미응답시의 timeout 설정을 의미하는것처럼 보인다.
실제 연결후 아무것도 하지 않아도 설정 시간(second)에 반응(timeout)하지 않는다.
3-way handshake 후에도 ACK 는 일정 주기로 주고 받고 있을 테니까...
그리고 Linux Kernel에서 TCP_DEFER_ACCEPT 옵션의 timeout 설정시 우리의 설정 시간을 무시 할 만한
어느정도 최소한의 timeout이 설정되어 있는 것으로 보인다.
linux 2.6.x kernel 의 net/ipv4/tcp.c 를 보면 밑의 부분이 보인다.
[root@bando kernel-source]# vi net/ipv4/tcp.c
case TCP_DEFER_ACCEPT:
.
.
if (val > 0) {
val > ((TCP_TIMEOUT_INIT / HZ)...
.
.
서버 애플리케이션에 TCP_DEFER_ACCEPT 옵션 적용후 nc, telnet 등으로 서버에 접속하고 아무런 행위도 하지 않으면 ESTABLISHED 되지 않고 SYN_RECV 로 나오게 된다. Maxclient를 50으로 설정한 Apache의 경우 TCP 연결 500개를 확립하고 아무런 행위도 하지 않을시에 실제 정상적인 HTTP 처리는 아무런 문제없이 진행 된다.
[root@bando ~]# nc localhost 80
.
.
[root@bando ~]# netstat -an|grep :80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:80 127.0.0.1:54623 SYN_RECV
[root@bando ~]# man tcp
.
.
TCP_DEFER_ACCEPT
Allows a listener to be awakened only when data arrives on the socket. Takes an integer value
(seconds), this can bound the maximum number of attempts TCP will make to complete the connec-
tion. This option should not be used in code intended to be portable.
.
.
.
.
[root@bando ~]# netstat -an|grep :80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:80 127.0.0.1:54623 SYN_RECV
[root@bando ~]# man tcp
.
.
TCP_DEFER_ACCEPT
Allows a listener to be awakened only when data arrives on the socket. Takes an integer value
(seconds), this can bound the maximum number of attempts TCP will make to complete the connec-
tion. This option should not be used in code intended to be portable.
.
.
-----------------------------------------------------------------------------------------------------------------------
밑은 관련된 기사의 내용이다.
해석이 맞나? ^^ 그냥 원문 보는게...
하여간 내가 원하는 중요한 내용은 파란색 부분이다.
-----------------------------------------------------------------------------------------------------------------------
기사원문 : http://articles.techrepublic.com.com/5100-10878_11-1050771.html
Take advantage of TCP/IP options to optimize data transmission
Takeaway: 데이타 전송의 최적화는 각 기업들에게 있어서 중요한 문제이다. 고맙게도, TCP/IP 프로토콜은 data 전송 최적화를 하기 위한 많은 방법들을 제공한다. 이기사는 몇몇 옵션들을 살펴보고 그옵션들이 성능 향상을 어떻게 하는지 보여준다.
By Alex Kuznetsov, Alex Plant, and Alexander Tormasov
마지막 시간에 우리는 TCP_CORK 옵션을 사용해서 네트워크상에서 전송되어지는 패킷들의 숫자를 감소시킬수 있는 방법들을 설명했었다. 결정적으로, 트래픽을 감소시키는것은 높은 퍼포먼스 네트워크 데이타 전송 문제의 한 부분인 것은 확실하다. 다른 TCP 옵션들은 상당히 퍼포먼스를 향상시키고 일정 상태 이하로 서버 응답 잠재를 감소킨다. 이 옵션들의 몇개를 살펴보자!TCP_DEFER_ACCEPT
첫번째 옵션 우리는 TCP_DEFER_ACCEPT 을 생각해볼 것이다. (Linux상에서 불려지는 것이다; 다른 OS들은 같은 옵션이지만 다른이름을 사용해서 제공한다.)TCP_DEFER_ACCEPT의 아이디어를 이해하는것은, HTTP client와 server 간 통신의 전형적인 진행 그림을 필요로 한다. data 전송을 위해 연결이 확립되는 TCP를 잘 생각해봐라.TCP가 데이타 전송의 목적을 위해 연결이 어떻게 확립되어지지 생각해봐라. 네트워크상에서 정보는 IP 패킷(또는 IP 데이타그램)이라고 불려지는 각각의 조각들로 이동된다. 한 패킷은 항상 한개의 헤더를 가지는데 헤더는 서비스 정보를 운반하고, 인터넷 프로토콜을 핸들링하기위해 사용하고, 적재된 데이타를 운반하기도 한다. 서비스 정보의 대표적인 예제는 flag들 이라고 불려지는 한 set 인데 그것은 성공적인 패킷 수신의 acknowledgement처럼 한 TCP/IP 스택을 특별한 의미를 가지도록 패킷들을 표시한다. 종종, 그것은 "표시된" 패킷들중에 payload 운반을 가능하게도 하지만, 때때로 내부 로직은 TCP/IP 스택이 헤더와 함께 올바르게 패킷들이 보내지는 것을 강요하기도 한다. 이 패킷들은 종종 필요없는 지연들 그리고 오버해드를 가중시키거나 그리고 전체 성능 하락의 결과를 만들어 내기도 한다.
서버가 지금 한 소켓이 생성되어졌고 한 연결을 위해 기다리는 중이다. TCP/IP 에서 그 연결 순서는 3-way handshake 라고 불려진다. 첫번째, 클라이언트는 SYN 플래그 설정과 함께 payload는 제외하고 한TCP 패킷(한 SYNC 패킷)을 보낸다. 서버는 첫 패킷의 acknowledge 받고 SYN/ACK 플래그 설정과 함께 한 패킷(한 SYN/ACK 패킷)을 보내는것으로 응답한다. 클라이언트는 그리고나서 두번째 패킷의 acknowledge 받고 한 ACK 패킷을 보내고 연결 순서가 완료된다. SYN/ACK 를 받은 후에, 패킷 서버는 receiver 프로세스가 작동하고 data를 기다리게 된다. 3-way handshake가 완료되어지면, 클라이언트는 서버에 전송되어질 "쓸모있는" 데이타를 보내는것을 시작한다. 보통, HTTP 요청은 매우 작고 단일 패킷에 적합하다. 그렇지만 이경우에, 적어도 4개의 패킷들이 적지않은 지연 시간과 함께 두곳 모두에서 보내질 것이다. 또한 주의해야 할것은 receiver 는 이미 그정보를 기다리는 중이었다 - 데이타가 보내지기 전에
이 문제들을 완화하기 위해서, Linux(몇몇 다른 OS들과 함께)는 TCP 수행에서 TCP_DEFER_ACCEPT
옵션을 포함한다. server측에 listening socket 설정, 그것은 kernel은 마지막 ACK 패킷을
기다리지 않고 실제 data의 첫번째 패킷이 도착할때까지 그 프로세스를 시작하지 말라고 지시한다.
SYN/ACK를 보낸후에, 서버는 그리고 나서 클라이언트로부터 data 패킷을 위해 기다릴 것이다.
지금, 단지 3 패킷만이 네트워크상에 보내질 것이고 연결 확립 지연은 상당히 줄어들 것이다.
이것은 HTTP를 위해 대표적인것이다.
옵션을 포함한다. server측에 listening socket 설정, 그것은 kernel은 마지막 ACK 패킷을
기다리지 않고 실제 data의 첫번째 패킷이 도착할때까지 그 프로세스를 시작하지 말라고 지시한다.
SYN/ACK를 보낸후에, 서버는 그리고 나서 클라이언트로부터 data 패킷을 위해 기다릴 것이다.
지금, 단지 3 패킷만이 네트워크상에 보내질 것이고 연결 확립 지연은 상당히 줄어들 것이다.
이것은 HTTP를 위해 대표적인것이다.
이옵션과 동등하게 마찬가지로 다른 운영체제에서도 사용가능하다. FreeBSD에서 예를 들면, 동일한 작동은 다음 코드와 함께 이루어진다.
/* some code skipped for clarity */
struct accept_filter_arg af = { "dataready", "" };
setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));
이것은 FreeBSD에서 "accept fillter"를 호출해서, 다른 방법으로 사용되어진다.모든경우에도, 그 효과는TCP_DEFER_ACCEPT와 동일하다. 이것은 FreeBSD에서 "accept fillter"를 호출해서 다른 방법으로 사용하고 있긴 하지만 어떤경우라도 그 효과는 TCP_DEFER_ACCEPT와 동일하다. - 그 서버는 마지막 ACK 패킷을 기다리지 않고, payload 패킷이 전송되기만을 기다릴 것이다. 이 옵션에 대한 더 많은 정보 그리고 Web server의 높은 성능 을 위한 그것의 중요성은 Apache documentation 에서 확인 할 수 있다.
HTTP client-server 간 통신은, client의 행동을 변경하는 것을 필요로 할지도 모른다. 왜 클라이언트는 어떻게 해서든 이 "쓸모없는" ACK 패킷을 보내려고 하는가? 한 TCP 스택은 ACK 패킷의 상태를 알 방법이 없다. FTP가 HTTP대신에 사용된 경우에, 클라이언트는 FTP server 명령이 포함된 한 패킷을 받을때까지 어떤 데이타도 보내지 않을 것이다. 이경우에 지연된 ACK는 client-server 간 통신 지연의 원인이 될 것이다. 이 ACK가 필요한지를 결정하기 위해서 클라이언트는 그 애플레케이션의 프로토콜과 그것의 현재 상태를 알아야 한다. 이와같이 그것은 클라이언트의 행동을 변경하는것을 필요로 한다.
Linux 기반 클라이언트를 위해서, 우리는 또하나의 옵션을 사용할수 있는데 그것 또한 TCP_DEFER_ACCEPT라고 불려진다. socket에는 listening 그리고 connected 소켓 그리고 두 상응하는 옵션의 설정들을 가지는 두가지 타입이 있다.
따라서 그것은 종종 같이 사용되어지는 이 두 옵션을 위해 같은 이름을 사용하는 것이 가능하다. 연결되어진 소켓에 이옵션을 설정하게 되면, 클라이언트는 SYN/ACK 를 받은후에 ACK 패킷을 보내지 않을 것이고, 대신에 사용자 프로그램으로부터 데이타를 보내기 위해서 다음 요청을 기다릴 것이다; 따라서 서버는 한개 적은 패킷을 보내게 될 것이다.
TCP_QUICKACK
쓸모없는 패킷들이 보내지는것에 의한 원인으로 지연이 생기는것을 막기위한 다른 방법은 TCP_QUICKACK를 사용하는 것이다. 이 옵션은 TCP_DEFER_ACCEPT와 다른 것인데, 말하자면 그것은 연결 확립의 진행을 관리하는것 뿐만 아니라, 보통 데이타 전송 진행중에도 사용되어질수 있다. 게다가, 그것은 client-server 연결의 어느쪽에도 설정 될 수 있다.
ACK 패킷의 전송을 지연하는것은 사용자 데이타가 곧 전송되어질 것이라는 것을 알고 있을때 유용하고, 그것은 오버헤드를 최소화 하기 위해 데이타 패킷에 ACK 플래그 설정하는 것이 낫다. 송신자가 데이타가 곧 보내질(multiple packets) 것이라고 확신하면, TCP_QUICKACK 옵션은 0으로 설정 할 수 있다. 이 옵션의 기본 값은 "connected" 상태 소켓들을 위해서 1이고, 그 값은 처음 사용하고나서 kernel에 의해서 곧장 1로 reset 될 것이다.(이것은 1회성 옵션이다.)
이 경우에, 그것은 ACK 패킷들을 보내는 것이 유리 할 수 있다. ACK 패킷은 data 블럭의 수신을 확인 할 것이고, 다음 블럭이 처리되어질때, 지연은 발생하지 않을 것이다. 이 데이타 전송 방법은 사용자 입력의 순간을 예측 할 수 없는 위치에 있는 양방향 통신 진행을 위해 대표적이다. Linux에서 이것은 기본적인 소켓 행동으로 알려져있다.
앞서말한 상황에서, 클라이언트는 HTTP 요청을 서버에 보내고, 서버는 이미 그 요청 패킷은 짧고 연결이 확립되어진 후에 곧장 보내질 것이라는 것을 알고 있다는 것과 HTTP가 어떻게 작동하는지 보여줬다. 비어있는 ACK 패킷을 보내는것은 필요하지 않기 때문에 성능 향샹을 위해서 TCP_QUICKACK를 0으로 설정하는 것은 적절하다. 서버측에서, 두 옵션 모두 listening 소켓에 한번만 설정 할 수 있다. Accept 호출에 의해 간접적으로 생성되어진 모든 소켓들은 원래 소켓으로부터 모든것을 상속 받게 될 것이다.
TCP_CORK, TCP_DEFER_ACCEPT 그리고 TCP_QUICKACK 옵션들의 결합으로 각 HTTP 트랜잭션에 참여하는 패킷들의 수가 최소한의 허용 가능함 범위로 줄어들 것이다(TCP 프로토콜 요구조건과 보안 고려사항들이 요구하는 대로). 그 결과 데이타 전송 과 요청 진행과정이 빨라지는 것 뿐만 아니라 client-server 송수신 잠재까지 최소화 한다.
Conclusion
네트워크 프로그램 성능의 최적화는 복잡하고 힘든일임에는 분명하다. 최적화 기술은 어디에서나 접근 가능한 zero-copy를 사용하는 것, TCP_CORK에 의해 조합된 올바른 패킷 그리고 상응하게전송되어지는 패킷들의 수의 최소화 그리고 잠재 최적화를 포함한다.
성능 과 확장성에 어느정도 의미있는 증가를 위해 그것은 이용할 수 있는 모든 방법들의 조합과 코드에 걸쳐 일관되게 사용하는 것이 필요하다. 물론 더하여, TCP/IP 스택의 내부 동작과 OS 전반에 걸쳐 명확한 이해는 필요하다.
------------------------------------------------ 기사 원문 ------------------------------------------------
Take advantage of TCP/IP options to optimize data transmission
Takeaway: Streamlining data transmission is a critical challenge for any enterprise. Thankfully, the TCP/IP protocol provides many ways to optimize data transfer. This article examines several options and shows how they can boost performance.
By Alex Kuznetsov, Alex Plant, and Alexander Tormasov
Last time, we explained how the TCP_CORK option can decrease the number of packets transferred over a network. While critically important, reducing traffic is just one part of the puzzle of high-performance network data transmission. Other TCP options can significantly improve performance and reduce server response latency under certain conditions. Let's look at some of those options.
TCP_DEFER_ACCEPT
The first option we'll consider is TCP_DEFER_ACCEPT. (This is what it's called in Linux; other OSs offer the same option but use different names.) To understand the idea of the TCP_DEFER_ACCEPT option, it is necessary to picture a typical process of the HTTP client-server interaction. Consider how the TCP establishes a connection with the goal of transferring data. On a network, information travels in discrete units called IP packets (or IP datagrams). A packet always has a header that carries service information, used for internal protocol handling, and it may also carry payload data. A typical example of service information is a set of so-called flags, which mark the packets as having special meaning to a TCP/IP stack, such as acknowledgement of successful packet receiving. Often, it's possible to carry payload in the “marked” packet, but sometimes, internal logic forces a TCP/IP stack to send out packets with just a header. These packets often introduce unwanted delays and increased overhead and result in overall performance degradation.
The server has now created a socket and is waiting for a connection. The connection procedure in TCP/IP is a so-called “three-way handshake.” First, a client sends a TCP packet with a SYN flag set and no payload (a SYN packet). The server replies by sending a packet with SYN/ACK flags set (a SYN/ACK packet) to acknowledge receipt of the initial packet. The client then sends an ACK packet to acknowledge receipt of the second packet and to finalize the connection procedure. After receiving the SYN/ACK, the packet server wakes up a receiver process while waiting for data. When the three-way handshake is completed, the client starts to send “useful” data to be transferred to the server. Usually, an HTTP request is quite small and fits into a single packet. But in this case, at least four packets will be sent in both directions, adding considerable delay times. Note also that the receiver has already been waiting for the information—since before the data was ever sent.
To alleviate these problems, Linux (along with some other OSs) includes a TCP_DEFER_ACCEPT option in its TCP implementation. Set on a server-side listening socket, it instructs the kernel not to wait for the final ACK packet and not to initiate the process until the first packet of real data has arrived. After sending the SYN/ACK, the server will then wait for a data packet from a client. Now, only three packets will be sent over the network, and the connection establishment delay will be significantly reduced, which is typical for HTTP.
Equivalents of this option are available on other operation systems, as well. For example, in FreeBSD, the same behavior is achieved with the following code:
/* some code skipped for clarity */
struct accept_filter_arg af = { "dataready", "" };
setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));
This feature, called an “accept filter” in FreeBSD, is used in different ways, although in all cases, the effect is the same as TCP_DEFER_ACCEPT—the server will not wait for the final ACK packet, waiting only for a packet carrying a payload. More information about this option and its significance for a high-performance Web server is available in the Apache documentation.
With HTTP client-server interaction, it may be necessary to change client behavior. Why would the client send this “useless” ACK packet anyway? A TCP stack has no way of knowing the status of an ACK packet. If FTP were used instead of HTTP, the client would not send any data until it received a packet with the FTP server prompt. In this case, delayed ACK will cause a delay in a client-server interaction. To decide whether this ACK is necessary, a client should know the application protocol and its current state. Thus, it is necessary to modify client behavior.
For Linux-based clients, we can use another option, which is also called TCP_DEFER_ACCEPT. There are two types of sockets, listening and connected sockets, and two corresponding sets of options. Hence, it is possible to use the same name for these two options that are often used together. After setting this option on a connected socket, the client will not send an ACK packet after receiving a SYN/ACK packet and will instead be waiting for a next request from a user program to send data; therefore, the server will be sent one fewer packet.
TCP_QUICKACK
Another way to prevent delays caused by sending useless packets is to use the TCP_QUICKACK option. This option is different from TCP_DEFER_ACCEPT, as it can be used not only to manage the process of connection establishment, but it can be used also during the normal data transfer process. In addition, it can be set on either side of the client-server connection. Delaying sending of the ACK packet could be useful if it is known that the user data will be sent soon, and it is better to set the ACK flag on that data packet to minimize overhead. When the sender is sure that data will be immediately be sent (multiple packets), the TCP_QUICKACK option can be set to 0. The default value of this option is 1 for sockets in the “connected” state, which will be reset by the kernel to 1 immediately after the first use. (This is a one-time option.)
In another scenario, it could be beneficial to send out the ACK packets. The ACK packet will confirm receipt of a data block, and when the next block is processed, there will be no delay. This mode of data transfer is typical for interactive processes, where the moment of user input is unpredictable. In Linux, this is known as default socket behavior.
In the aforementioned situation, where a client is sending HTTP requests to a server, it is previously known that the request packet is short and should be sent immediately after a connection is established, which is indicative of how HTTP works. There is no need to send a pure ACK packet, so it is possible to set TCP_QUICKACK to 0 to improve performance. On the server side, both options can be set only once on the listening socket. All sockets, created indirectly by an accept call, will inherit all of the options from the original socket.
By combining the TCP_CORK, TCP_DEFER_ACCEPT, and TCP_QUICKACK options, the number of packets participating in each HTTP transaction will be reduced to a minimal acceptable level (as required by TCP protocol requirements and security considerations). The result is not only fast data transfer and request processing but also minimized client-server two-way latency.
Conclusion
Optimization of network program performance is obviously a complex task. Optimization techniques include using the zero-copy approach everywhere possible, proper packet assembling by TCP_CORK and equivalents, minimization of a number of packets transferred, and a latency optimization. For any significant increase in performance and scalability, it is necessary to use all methods available jointly and consistently across the code. Of course, a clear understanding of inner workings of TCP/IP stack and OS as a whole is required, as well.

감사합니다 ^^ 퍼 가겠습니다. 안된다고 하시면 삭제 하겠습니다~