본문 : http://www.ischo.net -- 조인상 //시스템 엔지니어



출처 : http://www-903.ibm.com/kr/techinfo/pseries/tech/tech_11.html
+++++++++++++++++++++++++++++++++++++++++++++++++++++++


FIN_WAIT_2 상태에 대하여


유부선  bsyu@kr.ibm.com

개요    TCP socket connection 상태의 종류    FIN_WAIT_2 에 대한 대책 

개요 

TCP는 UDP와는 달리 connection-oriented protocol인 관계로, 연결을 맺거나 특히 끊을 때, 많은 확인 절차를 거치게 됩니다. 이로 인하여, server와 client 간에 약간의 overhead가 있을 수 있습니다. 특히, web server로 사용되는 system의 경우, 대부분의 client들이 그리 안정적이지 않은 PC client이므로, connection을 맺던 client application이 crash되는 경우 web server에는 다소간의 문제가 발생할 여지가 있습니다. 가장 대표적인 문제가 FIN_WAIT_2 상태입니다. 여기서는 이 상태가 무엇을 뜻하는지, 이로 인해 어떤 문제가 있을 수 있는지, 또 그에 대한 대책은 무엇인지 알아보겠습니다.


TCP socket connection 상태의 종류 

다음은 RFC 793 에 나와있는 그림으로, TCP connection을 맺고 있는 두 system이 정상적으로 connection을 끝내는 과정을 보여줍니다.

TCP A                TCP B
1. ESTABLISHED    ESTABLISHED
2. (Close)
FIN-WAIT-1 → <SEQ=100><ACK=300><CTL=FIN,ACK>  → CLOSE-WAIT
3. FIN-WAIT-2 ← <SEQ=300><ACK=101><CTL=ACK>  ← CLOSE-WAIT
4. (Close) 
TIME-WAIT ← <SEQ=300><ACK=101><CTL=FIN,ACK>  ← LAST-ACK
5. TIME-WAIT → <SEQ=101><ACK=301><CTL=ACK>  → CLOSED
6. (2 MSL)   
CLOSED

Normal Close Sequence


먼저, A가 connection을 close 하면서, 종료 신호인 FIN segment를 A가 B로 보내고, A는 FIN-WAIT-1 상태로 들어갑니다. 이 상태에서는 A system의 user는 더 이상의 SEND는 사용할 수 없게 되지만, RECEIVE는 계속 가능합니다. B가 그 신호를 받으면 B는 CLOSE-WAIT에 들어가면서 그에 대한 acknowledge를 보내옵니다. A는 이를 받으면 FIN-WAIT-2 상태가 되고, B는 connection을 close하면서 자신의 FIN을 보냅니다. 이 때 A는 TIME-WAIT 상태가 되어 최종적으로 B와의 connection이 닫히는지 확인하게 됩니다. 즉, server가 client로부터 FIN에 대한 ACK을 받고나서, client의 FIN을 기다리는 상태가 FIN-WAIT-2 상태입니다. 문제는, 이 FIN-WAIT-2 상태에 대해서는 원래 time-out 값이 정해져 있지 않아서, client가 FIN을 보내오기 전에 client의 application이나 client 자체가 crash되는 경우, 또는, client program이나 server program에 bug가 있어서 이를 제대로 처리 못하는 경우에는, server에 남아있을 FIN-WAIT-2 상태는 server가 rebooting하기 전에는 끝까지 남아 있게 된다는 것입니다. 이는 netstat -a 명령어로 확인해 볼 수 있는데, 이러한 상태의 connection이 많이 쌓이다보면 문제를 일으킬 수도 있습니다.


FIN_WAIT_2 에 대한 대책 

가장 좋은 해결책은 bug가 있는 client 또는 server program을 수정하는 것입니다. 대부분의 문제는 그 문제로부터 발생하기 때문입니다. Server에서 운영되는 가장 대표적인 application은 Apache webserver일 것입니다. Apache는 이 문제에 대한 해결책으로 lingering_close() 함수 대신 SO_LINGER 함수를 사용하도록 권하기도 합니다. (자세한 것은 아파치 홈페이지 www.apache.org를 참조하시기 바랍니다.) 다른 UNIX들은 FIN-WAIT-2에 대해, time-out 값을 지정함으로써 이 문제를 회피하도록 해줄 수 있게 해주기도 합니다. Solaris, HP/UX, Linux 등 많은 OS가 이러한 기능을 제공합니다. 이것들은 RFC 793을 위반하는 것입니다만, 필요에 의해 각 vendor가 제공하는 것입니다. AIX는 (다른 UNIX와 마찬가지로) TCP keepalive timer를 제공함으로써 이 문제를 해결합니다.


# no -a | grep tcp_keep
tcp_keepintvl = 150
tcp_keepidle = 14400

위의 값이 default 값이며, 이 경우, 150 * 500ms clock tick = 75 초, 그리고 14400 * 500ms clock tick = 2 시간이 됩니다.

keepalive timer는 data segment를 보내면서 reset됩니다. 만약 주어진 tcp_keepidle tick 동안 아무 data segment도 보내지지 않았다면 먼저, 첫번째 keepalive probe packet이 보내집니다.

이 packet에 대해 reply가 없을 경우, tcp_keepintvl에 정해진 tick만큼을 간격으로 하여, 추가의 keepalive packet을 보내게 됩니다.

만약 이 keepalive에 대해 reply가 계속 없을 경우, 그 connection은 close됩니다. AIX 4.2에서는 TCPTV_KEEPCNT (기본값 8)에 해당하는 개수의 probe에 대해 응답이 없을 경우 close되는데, AIX 4.3에서는 이 no attribute가 없어졌습니다.

tcp_keepinit는 초기 연결시 응답이 없을 경우에 사용되는 값입니다. 따라서, 일단 connection을 맺고 나서 발생하는 문제에 대해서는 적용되지 않습니다.

위에 따르면, FIN_WAIT_2가 발생하는 경우, default로 2시간 10분 후에야 그 connection이 close되도록 되어 있습니다. 만약, 매우 busy한 web server인 경우에는 이 값들을 조절하는 것이 필요할 수 있습니다.

참고

http://www.faqs.org/rfcs/rfc793.html
http://www.ibrado.com/sock-faq/




추가 내용 ++++++++++++++++++++++++++++

다음과 같은 파라미터를 이용해서 FIN_WAIT_2 상태의 지속시간을
조정할 수도 있다.

# no -a | grep tcp_finwait2
            tcp_finwait2 = 1200

디폴트값이 1200 이며 단위는 half second.
즉 1200 이면 600초. 즉 10분이다.

변경은  " 예)# no -o tcp_finwait2=120 "  과 같이 해주면 되고
즉시 반영되지만 재부팅시 초기화되므로
/etc/rc.net 스크립트등에 기록이 필요하다.
(*.95.187.205)