커피닉스, 시스템 엔지니어의 쉼터
  DNS 질의 TimeOut의 진실은.. (2번째) 작성일 : 2010/11/04 21:54
 
  • 글쓴이 : 좋은진호 ( http://coffeenix.net/ )
  • 조회수 : 20184
     
    제  목 : DNS 질의 TimeOut의 진실은.. (2번째)
    작성자 : 좋은진호(truefeel, http://coffeenix.net/ )
    작성일 : 2010.11.4(목)

    범냉이님이 dig과 nslookup툴을 사용하여, resolv.conf에서 지정한 DNS 서버가 죽었을 경우 timeout시간은 어떻게 되는지 테스트를 하셨다. 테스트한 글은 'DNS 질의 TimeOut의 진실은..'( http://coffeenix.net/board_view.php?bd_code=1714 )에 정리되어 있다.
    그 후, 제가 추가 임무(?)를 넘겨받았다. ^^. 이 글을 읽기 전에 반드시 범냉이님의 글을 읽어봐야 한다.


    ※ 이미지 출처 : 구글 'domain lookup' 이미지 검색


    1. dig, nsloookup에서는 왜 timeout이 1초인가?

    resolv.conf에 2대의 DNS서버를 지정을 했다고 가정하자. 그리고, 그 중 첫번째 서버가 응답이 없다고 하자.

     
    nameserver 10.10.10.251   <-- 문제. 도메인 lookup시 첫번째로 요청하는 DNS. Primary라고 지칭해보자.
    nameserver 10.10.10.252   <-- 정상. Secondary.
     


    /usr/include/resolv.h에서 디폴트 timeout은 5초이다.

     
    [ /usr/include/resolv.h ]
    # define MAXNS           3    /* max # name servers we'll track */      <-- 뒤에서 설명하겠다.

    # define RES_TIMEOUT     5    /* min. seconds between retries */        <-- default timeout
    # define RES_MAXRETRY    5    /* only for resolv.conf/RES_OPTIONS */    <-- 최대 retry 가능 수
    # define RES_DFLRETRY    2    /* Default #/tries. */                    <-- default retry
     


    그런데, 왜 dig이나 nslookup은 테스트 결과 1초로 나왔을까? bind내의 유틸리티인 dig, nslookup은 resolv.h의 설정값을 사용하지 않는다. dig소스의 dig.h 를 다음과 같이 정의되어 있다. 이 수치가 바로 timeout설정 값. nslookup도 같은 header를 사용한다.

     
    [ bind9 소스내 dig.h ]

    #define SERVER_TIMEOUT 1
     


    즉, resolv.conf에 순차적으로 나열된 네임서버에서 첫째가 응답이 없다면 1초간 응답을 기다린다. 그 후 다음 서버로 넘긴다.
    만약 3대를 나열했을 때, 앞의 2대가 문제라면, 1초 + 1초 = 총 2초 timeout 후 3번째 서버로 요청을 넘길 것이다.
    resolv.conf에 나열 가능한 서버 대수는 resolv.h에서 MAXNS로 정의되어 있다. 3대. 그 이상의 설정은 무시된다.


    2. 만약 resolv.conf에 지정한 모든 서버가 응답이 없다면?

    resolv.conf에 나열한 모든 서버가 응답이 없다면 dig.h내의 UDP_TIMEOUT 값 동안 응답대기를 한 후 retry를 한다.

     
    [ bind9 소스내 dig.h ]

    /* Default UDP Timeout */
    #define UDP_TIMEOUT 5
     


    정리하면 다음과 같다.

    1) resolv.conf에 나열된 서버간 요청 대기는 1초(SERVER_TIMEOUT)
    2) 나열된 모든 서버 요청 후 retry시 대기는 5초(UDP_TIMEOUT)

    이를 resolv.conf에 1대부터 3대까지 지정되어 있고, 모두 응답이 없을 때를 가정하자.

    1) resolv.conf에 지정한 서버가 1대일 때

     
    5초     + 5초       + 5초       = 총 15초 소요
    --------  ---------   ---------
    try 1번 + try 2번   + try 3번
     


    2) 2대일 때

     
    1초+5초 + 1초+5초   + 1초+5초   = 총 18초 소요
    --------  ---------   ---------
    try 1번 + try 2번   + try 3번
     


    3) 3대일 때

     
    1초+1초+5초 + 1초+1초+5초   + 1초+1초+5초   = 총 21초 소요
    -----------   -------------   -------------
    try 1번     + try 2번       + try 3번
     





    3. resolv.conf의 options 사용

    DNS서버의 응답 시간(options timeout:n)과 retry횟수(options attempts:n)를 /etc/resolv.conf에 지정할 수 있다. timeout을 5초 -> 1초로, retry를 2번 -> 3번으로 변경한 예이다.

     
    [ /etc/resolv.conf ]

    options timeout:1 attempts:3
     


    그러나 dig이나 nslookup에서는 resolv.conf의 options 설정을 사용하지 않으므로 의미가 없다. 즉, 프로그램에 따라(직접 개발한 것도 포함) resolv.conf을 사용할 수도 있고, 그렇지 않을 수도 있으니 resolv.conf 설정만 믿어서는 안된다.


    4. gethostbyname() 함수, ping 프로그램 테스트

    gethostbyname()함수를 사용하는 C프로그램이라면 지금까지 설명한 resolv.h와 resolv.conf을 따르게 된다. 대표적인 것이 ping일 것이다.

    간단한 예를 들어보자. resolv.conf는 다음과 같다.

     
    [ /etc/resolv.conf ]

    search coffeenix.net
    nameserver 10.10.10.251
    nameserver 10.10.10.252
     


    - resolv.conf가 설정된 서버는 10.10.10.123 이라고 하자.
    - gethostbyname()함수로 google.com을 lookup 한 경우다.

    resolv.conf에 지정한 DNS서버에서 ICMP응답을 받을 수 있느냐 없느냐에 따라서 대기시간(timeout시간)은 달라지게 된다.

    1) ICMP udp port domain unreachable 응답이 올 때

    다음은 resolv.conf에 지정한 2대 모두가 DNS응답을 리턴해주지 못했을 때의 패킷을 간단히 표현한 것이다.

     
    ---------  -------------   ------------------
    시간       client            DNS  서버
    ---------  -------------   ------------------
    21:20:46   10.10.10.123  > 10.10.10.251.domain A? google.com.   <-- 1번째 시도 : 1번째 서버로 요청
    21:20:46   10.10.10.123  < 10.10.10.251 ICMP 10.10.10.251 udp port domain unreachable <-- ICMP응답을 받음
    21:20:46   10.10.10.123  > 10.10.10.252.domain A? google.com.   <-- 1번째 시도 : 2번째 서버로 요청
    21:20:46   10.10.10.123  < 10.10.10.252 ICMP 10.10.10.252 udp port domain unreachable
    21:20:46   10.10.10.123  > 10.10.10.251.domain A? google.com.   <-- 2번째 시도 : 1번째 서버로 요청
    21:20:46   10.10.10.123  < 10.10.10.251 ICMP 10.10.10.251 udp port domain unreachable
    21:20:46   10.10.10.123  > 10.10.10.252.domain A? google.com.   <-- 2번째 시도 : 2번째 서버로 요청
    21:20:46   10.10.10.123  < 10.10.10.252 ICMP 10.10.10.252 udp port domain unreachable

    21:20:46   10.10.10.123  > 10.10.10.251.domain A? google.com.coffeenix.net.
    21:20:46   10.10.10.123  < 10.10.10.251 ICMP 10.10.10.251 udp port domain unreachable
    21:20:46   10.10.10.123  > 10.10.10.252.domain A? google.com.coffeenix.net.
    21:20:46   10.10.10.123  < 10.10.10.252 ICMP 10.10.10.252 udp port domain unreachable
    21:20:46   10.10.10.123  > 10.10.10.251.domain A? google.com.coffeenix.net.
    21:20:46   10.10.10.123  < 10.10.10.251 ICMP 10.10.10.251 udp port domain unreachable
    21:20:46   10.10.10.123  > 10.10.10.252.domain A? google.com.coffeenix.net.
    21:20:46   10.10.10.123  < 10.10.10.252 ICMP 10.10.10.252 udp port domain unreachable
     




    10.10.10.251로 google.com을 요청했다. 그런데, DNS 서버는 동작하고 있지 않았다. 대신 DNS가 운영중이지 않다는 명확한 ICMP응답을 받았다. 따라서 대기시간(timeout)이 필요없이 바로 다음 서버인 10.10.10.252를 요청했다. 이렇게 2번의 retry과정을 거쳤다.
    그 후 resolv.conf에 search로 설정된 도메인을 덧붙여서 google.com.coffeenix.net를 찾는 과정을 동일하게 반복한다.

    여기서 알 수 있는 것은 다음과 같다.
    ① ICMP응답이 온다면, timeout없이 바로 다음 서버로 요청을 한다.
    ② search의 도메인을 추가로 덧붙여서 요청을 한다.
    ③ resolv.h에 설정된 retry를 따른다.


    2) ICMP 응답이 없을 때

     
    ---------  -------------   ------------------
    시간       client            DNS  서버
    ---------  -------------   ------------------
    21:21:18   10.10.10.123  > 10.10.10.251.domain A? google.com.   <-- 1번째 시도 : 1번째 서버로 요청
    21:21:23   10.10.10.123  > 10.10.10.252.domain A? google.com.   <-- 1번째 시도 : 2번째 서버로 요청 (위와 5초간격)
    21:21:28   10.10.10.123  > 10.10.10.251.domain A? google.com.   <-- 2번째 시도 : 1번째 서버로 요청 (위와 5초간격)
    21:21:33   10.10.10.123  > 10.10.10.252.domain A? google.com.   <-- 2번째 시도 : 2번째 서버로 요청 (위와 5초간격)

    21:21:38   10.10.10.123  > 10.10.10.251.domain A? google.com.coffeenix.net.
    21:21:43   10.10.10.123  > 10.10.10.252.domain A? google.com.coffeenix.net.
    21:21:48   10.10.10.123  > 10.10.10.251.domain A? google.com.coffeenix.net.
    21:21:53   10.10.10.123  > 10.10.10.252.domain A? google.com.coffeenix.net.
     


    ICMP응답이 없으니 timeout동안 대기하다가 다음 서버로 요청을 했다. 나머지는 앞에서 설명한 것과 같은 과정이다.



    5. 결론 : 효과적인 resolv.conf 설정

    resolv.conf에 2개 IP이상의 nameserver를 지정했을 경우를 가정하여, 결론을 내보겠다.

    만약 resolv.conf에 지정한 첫번째 네임서버(또는 네임서버 VIP) 자체가 죽는다면 ICMP 응답을 못받을 것이다. 따라서 응답시간을 줄이고자 한다면 resolv.conf에서 timeout시간을 줄여주는게 더 나은 대비책이 될 것이다.

     
    options timeout:1 attempts:2 또는
    options timeout:1 attempts:1
     


    하지만 resolv.conf 설정을 사용하지 않는 프로그램도 있다. 모든게, resolv.conf 설정대로 될 것이라는 믿음은 절대 금물.


    커피닉스, 시스템 엔지니어의 쉼터 / URL : http://coffeenix.net/board_view.php?bd_code=1715