• SO_SNDBUF 0

    2016. 12. 4.

    by. xxx123

     

     

     

     

     

    SO_SNDBUF는 소켓 버퍼(=Winsock Kernel Buffer =TCP Stack Buffer)의 사이즈를 조절하는 옵션의 인자값으로 들어간다.

    이름 그대로 SEND 소켓 버퍼의 사이즈를 조절하는 것인데,

    이 사이즈값을 0으로 하냐 마냐에 따라 퍼포먼스의 차이를 보이게 된다.

     

     

     

     

     

     

     

     

     

    1. SO_SNDBUF를 0의 의미

     

    이것은 크게 3가지 의미를 갖는다.

     

     

    ① 유저 버퍼(=Application Buffer)와 소켓 버퍼간의 Copy를 막는다.

    소켓 버퍼가 0이 아닐 경우 Send Call시 유저 버퍼의 데이터는 소켓 버퍼로 복사되며 

    SendCompletion을 발생시킨다.

    이 버퍼간의 복사를 댓가로 유저 버퍼에서는 Send에 대한 모든 책임을 소켓 버퍼로 이양하게 되는 것이다.

    이 때 소켓 버퍼의 사이즈를 0으로 하면 데이터 복사 없이 유저 버퍼에서 바로 데이터를 송신하게 된다.

    복사가 줄어드는 만큼, 전송 속도는 빨라지게 된다.

     

     

    ② Send Completion 규칙을 바꾼다.

    위에서 말했듯이 일반적으로 소켓 버퍼가 존재할때 Completion은 소켓 버퍼에 복사되면서 일어나게 된다.

    근데 소켓 버퍼 사이즈를 0으로 한다면 네트워크 상으로 패킷이 보내졌을 때 윈속으로 Completion을 알려준다.

     

     

    ③ Nagle's Algorithm의 데이터 쌓기 기능을 마비시킨다.

     

    중요한 부분중 하나이다. 

    일단 핵심부터 얘기하자면 Send 소켓 버퍼를 0으로 하게되면 Nagle 알고리즘에 의해 이더넷 프레임 사이즈()

    까지 모여야 데이터가 전송되는데 그 데이터가 모일 장소가 사라진다는 것이다.

    그러므로 Nagle 알고리즘의 Send 데이터 쌓기 기능이 동작하지 않는다고 볼 수있다.

     

    여기서 주의해야할 점은,

    Nagle 알고리즘의 데이터 쌓기 기능이 동작하지 않는다고 해서 알고리즘 자체가 동작하지 않는것은 아니다.

    Nagle 알고리즘은 상대에게서 ACK를 받았을때 다음 Send를 수행하게 된다.

    이것이 왜 문제가 되는지 한번 보도록하자.

    위 그림은 Nagle 알고리즘이 동작하는 상황에서 Send 소켓 버퍼가 존재할 때의 경우이다.

    어플리케이션단에서 Send()가 호출되면 데이터는 Send 소켓 버퍼로 계속해서 복사가 되고

    네이글 알고리즘에 의해 쌓인 데이터는 상대방의 ACK를 받고 한꺼번에 전송되게 된다.

     

    위 그림은 Nagle 알고리즘이 동작하는 상황에서 Send 소켓 버퍼가 없을 때의 경우이다.

    Send를 수행하고 싶어도 일단 Send 소켓 버퍼가 없으므로 복사할 곳이 없어진다.

    Send를 수행하지 못하고 기다렸다가 상대방의 ACK가 오고 나서야 한번씩 다음 Send()를 진행할 수 있게된다.

    결과적으로 Nagle 알고리즘이 켜진 상태에서 Send 소켓 버퍼를 0으로 만드는 것은 별로 좋지 못한 선택이라 할수 있겠다.

     

     

    또 여기서 고려해야할 것은 상대방의 ACK는 바로오지 않는다는 것이다.

    이것은 Winsock의 동작 방식과 관련이 있는데 그 방식은 다음과 같다.

     

    TCP 통신에서 데이터 패킷을 받게 되면 그 패킷을 잘 받았다고 ACK 메세지를 보내게 되어있는데 Microsoft TCP 스택은 200ms 타이머 동작하게 된다.

    즉, 패킷을 받자마자 바로 ACK를 보내는게 아니라 몇몇 규칙에 따라 ACK를 보내는 것이다.

     

     

    - 타이머(200ms)가 초과하기 전에 두번째 패킷을 받게되면 ACK를 보낸다. 

    상대방이 보내오는 패킷 빈도가 높다면 빠르게 ACK를 보낼 수 있다는 것이다.

     

     

    - 타이머가 완료되거나 두번째 패킷이 상대방으로부터 오거나 하기 전에 내쪽에서 상대편에게 보낼 패킷이 있다면

    그 패킷에 ACK 신호를 같이 끼워서 보낸다.

    단방향 통신이 아니라 양방향으로 패킷을 주고받는 중이라면 좀 더 빠르게 ACK를 보낼 수 있다는 것이다.

     

     

    - 위 상황이 다 발생하지 않았다면 타이머가 완료된 후에 ACK를 보낸다.

     

     

     

     

    자, 위 특징과 함께 생각해보면 Nagle이 켜져있고 Send 소켓 버퍼를 0으로 만든 상황에서 

    ACK를 기다려야 하는데, 그 ACK는 내가 SYN를 보냈어도 그 SYN를 받고 나서 200ms 후에나 되돌아 온다는것이다.

    물론 위에서 설명한대로 양방향에서 패킷을 주고받고 있는 상황이라면 그나마 그 딜레이를 줄일 수는 있을것이다.

    하지만 기본적으로 Nagle + SO_SNDBUF 0의 조합은 좋지 않다는것을 알 수 있다. 

     

     

     

     

     

     

     

     

     

     

    2. 그렇다면 SO_SNDBUF를 0은 언제 설정해야하는가?

     

     

    Nagle과 Send 소켓 버퍼를 0으로 만드는 조합을 생각해보면 다음과 같은 결론이 나온다.

     

    Nagle SND_BUF 0 
     O  디폴트 조합이다. 
     O  최악의 조합이다.  Nagle 알고리즘에 따라 ACK가 올때까지 기다리겠지만, Send 소켓 버퍼가 0이므로 데이터를 모아보내지 못하고 매번 한번씩만 보내게 될것이다.
     게다가 ACK는 Winsock의 ACK 전송 규칙에 의해 바로바로 오지 않을것이다.
     
     X 테스트를 통해 상황에 맞게 셋팅해야한다.
     X

     

    사실 SND_BUF의 사이즈를 0으로 하여 복사 비용을 줄이는것에 대한 이점은 별로 높지 않다는것이 정설이다.

    이런 실정에서도 SND_BUF 사이즈를 0으로 하였을때 이득을 볼 수 있는 상황이 있는데,

    바로 대용량 데이터를 보낼때이다.

    Nagle 알고리즘에도 예외가 있는데 바로 이더넷 프레임 사이즈 (1460 bytes)이상의 데이터를 보내게 되면 ACK를 기다리지 않고 바로 상대방에게 Send를 수행하게 된다.

    문서에도 이런 대용량 데이터 전송시 이점이 있을수 있음을 명시하고 있다.

     

    즉 결론적으로는 Nagle알고리즘을 킨상태에서 SND_BUF를 0으로 셋팅하는것은 지양해야하며,

    가급적 테스트를 통해 검증된 상황이 아니라면 두 소켓옵션을 변경하지 말라는것이다.

     

     

     

     

     

     

     

     

     

     

    3. 그외 여러가지 가정.

     

    실제 테스트를 진행했을 때 서버가 바쁜 상황에서 SO_SNDBUF를 0으로 설정하면

    SendCompletion이 늦게 떨어지는 상황을 보았다. (당시는 Nagle 알고리즘 On/Off 여부를 확인하진 않았다.)

    어떻게 보면 SendBuffer로 복사를 하면 바로 떨어질 Completion이 지연되는것은 당연할 수 있다고 한다.

     

    하지만 내부에서 SendCompletion이 유저버퍼에서 네트워크 상으로 송신했을 때가 아니라,

    상대방의 ACK를 받고 나서 떨어질수도 있을것 같다는 가정이 생겼다.

    그 이유인즉, 패킷에 문제가 생겼을 경우 이를 재전송해야하는데 이를 유저버퍼에서 진행한다면,

    유저버퍼가 사라졌을때 재전송이 부분이 문제가 된다는 것이다.

    이미 SendCompletion이 떨어진 후인데, 재전송이 안되는 상황이 발생할수 있다는 것이다.

     

    그리하여 ACK를 받고나면 Completion이 떨어지는 것이고 그 통보가 늦어진다는것이다.

     

    하지만 실제 문서에는 존재않는 내용이며, 그저 내부적인 가설이지만 아주 틀린 얘기는 아닌것같다.

     

     

     

     

     

     

     

     

     

     

     

    [참고]

    https://support.microsoft.com/en-us/kb/214397

     

    'Programming > Network' 카테고리의 다른 글

    TCP Header  (0) 2015.06.19
    page-locking & non-paged pool  (0) 2015.06.19
    shutdown()과 closesocket()  (1) 2015.06.15
    IOCP - 1 (I/O CompletionPort)  (0) 2014.12.14
    Overlapped I/O  (0) 2014.09.18

    댓글