호스트 이름을 확인하는 데 5초가 걸립니다.

호스트 이름을 확인하는 데 5초가 걸립니다.

bind9다음을 사용하여 IPv4(Debian Jessie)에서 실행되는 마스터 DNS 서버와 2개의 슬레이브 서버가 있습니다 /etc/bind/named.conf.

listen-on-v6 { none; };

다른 서버에서 연결을 시도하면 각 연결에 최소 5초가 걸립니다(저는 다음을 사용하고 있습니다).조셉의 타이밍 정보디버깅용):

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com
            time_namelookup:  5.512
               time_connect:  5.512
            time_appconnect:  5.529
           time_pretransfer:  5.529
              time_redirect:  0.000
         time_starttransfer:  5.531
                            ----------
                 time_total:  5.531

에 따르면 curl조회에는 대부분의 시간이 걸리지만 표준 nslookup은 매우 빠릅니다.

$ time nslookup example.com > /dev/null 2>&1

real    0m0.018s
user    0m0.016s
sys     0m0.000s

IPv4를 강제로 curl사용하면 훨씬 더 좋아집니다.

$ curl -4 -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  0.004
               time_connect:  0.005
            time_appconnect:  0.020
           time_pretransfer:  0.020
              time_redirect:  0.000
         time_starttransfer:  0.022
                            ----------
                 time_total:  0.022

호스트에서 IPv6을 비활성화했습니다.

echo 1 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6

문제는 지속되지만. strace시간 초과의 이유가 무엇인지 확인하기 위해 실행을 시도했습니다 .

write(2, "*", 1*)                        = 1
write(2, " ", 1 )                        = 1
write(2, "Hostname was NOT found in DNS ca"..., 36Hostname was NOT found in DNS cache
) = 36
socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 4
close(4)                                = 0
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f220bcf8000
mprotect(0x7f220bcf8000, 4096, PROT_NONE) = 0
clone(child_stack=0x7f220c4f7fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f220c4f89d0, tls=0x7f220c4f8700, child_tidptr=0x7f220c4f89d0) = 2004
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 4)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 8)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 16)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 32)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 64)                          = 0 (Timeout)

nslookup(또는 curl -4)이 동일한 DNS 서버를 사용하고 있어 방화벽 문제는 아닌 것 같습니다 . 무엇이 잘못되었을지 아시나요?

tcpdump호스트가 보낸 내용은 다음과 같습니다 tcpdump -vvv -s 0 -l -n port 53.

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:14:52.542526 IP (tos 0x0, ttl 64, id 35839, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:52.542540 IP (tos 0x0, ttl 64, id 35840, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:52.543281 IP (tos 0x0, ttl 61, id 63674, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)
20:14:57.547439 IP (tos 0x0, ttl 64, id 36868, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:57.548188 IP (tos 0x0, ttl 61, id 64567, offset 0, flags [none], proto UDP (17), length 184)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 39535* q: A? example.com. 2/2/2 example.com. [1h] CNAME s01.example.com., s01.example.com. [1h] A 136.243.154.168 ns: example.com. [30m] NS ns01.example.com., example.com. [30m] NS ns02.example.com. ar: ns01.example.com. [1h] A 136.243.154.168, ns02.example.com. [1h] A 192.168.1.2 (156)
20:14:57.548250 IP (tos 0x0, ttl 64, id 36869, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:57.548934 IP (tos 0x0, ttl 61, id 64568, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)

편집하다: 바인드 로그에 다음 메시지가 자주 나타납니다.

error sending response: host unreachable

그러나 각 쿼리는 결국 응답됩니다(단지 5초 소요). 모든 시스템은 물리적 서버입니다(NAT의 결함이 아님). 라우터에 의해 패킷이 차단될 가능성이 더 높습니다. 관련 질문은 다음과 같습니다.DNS 조회에는 때때로 5초가 소요됩니다..

답변1

짧은 답변:

해결 방법은 다음에 줄을 추가하여 및 레코드 glibc조회를 위해 소켓을 강제로 재사용하는 것 입니다 .AAAAA/etc/resolv.conf

options single-request-reopen

이 문제의 실제 원인은 다음과 같습니다.

긴 답변:

glibc의 기능을 사용 curl하거나 사용하는 프로그램wgetgetaddrinfo(), 두 DNS 레코드를 병렬로 조회하여 IPv4 및 IPv6 모두와 호환되도록 시도합니다. 두 레코드가 모두 수신될 때까지 결과를 반환하지 않습니다.그러한 행동과 관련된 몇 가지 문제) - strace위의 내용을 설명합니다. curl -4내부적 으로 레코드만 gethostbyname()쿼리하는 것과 같이 IPv4가 강제되는 경우 .A

우리 는 tcpdump다음을 볼 수 있습니다:

  • -> A?두 개의 요청이 처음에 전송됩니다.
  • -> AAAA?(IPv6 주소 요청)
  • <- AAAA회신하다
  • -> A?IPv4 주소를 다시 요청하는 중
  • <- A답장을 받았습니다
  • -> AAAA?IPv6를 다시 요청하는 중
  • <- AAAA회신하다

A어떤 이유로든 답장 이 삭제되었습니다. 다음 오류 메시지가 표시됩니다.

error sending response: host unreachable

그러나 두 번째 쿼리가 필요한 이유가 확실하지 않습니다 AAAA.

동일한 문제가 있는지 확인하려면 다음에서 시간 초과를 업데이트할 수 있습니다 /etc/resolv.conf.

options timeout:3

먼저 다음을 사용하여 텍스트 파일을 만듭니다.맞춤 시간 보고 구성:

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

그런 다음 요청을 보냅니다.

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  3.511
               time_connect:  3.511
            time_appconnect:  3.528
           time_pretransfer:  3.528
              time_redirect:  0.000
         time_starttransfer:  3.531
                            ----------
                 time_total:  3.531

다음에는 두 가지 관련 옵션이 더 있습니다 man resolv.conf.

단일 요청(glibc 2.10부터)RES_SNGLKUP 에 설정됩니다 _res.options. 기본적으로 glibc는 버전 2.9부터 IPv4 및 IPv6 조회를 병렬로 수행합니다. 일부 어플라이언스 DNS 서버는 이러한 쿼리를 적절하게 처리할 수 없어 요청 시간이 초과됩니다. 이 옵션은 동작을 비활성화하고 glibc가 IPv6 및 IPv4 요청을 순차적으로 수행하도록 합니다(해결 프로세스가 약간 느려지는 대신).

단일 요청 다시 열기(glibc 2.9부터) 확인자는 A 및 AAAA 요청에 동일한 소켓을 사용합니다. 일부 하드웨어는 실수로 하나의 응답만 돌려보냅니다. 그런 일이 발생하면 클라이언트 시스템은 앉아서 두 번째 응답을 기다립니다. 이 옵션을 켜면 이 동작이 변경되어 동일한 포트의 두 요청이 올바르게 처리되지 않으면 두 번째 요청을 보내기 전에 소켓을 닫고 새 소켓을 엽니다.

관련 문제:

답변2

@Tombart가 말했듯이 지연은 IPv6 해상도 시간 초과를 기다리기 때문입니다.

또 다른 가능한 조치 과정은 /etc/gai.conf에서 IPv4에 우선순위를 부여하는 것입니다.

/etc/gai.conf의 의견에서

#   For sites which prefer IPv4 connections change the last line to
#
precedence ::ffff:0:0/96  100

을 변경한 후 gai.conf변경 사항을 적용하려면 DNS 확인자 라이브러리를 사용하는 모든 앱을 다시 시작해야 합니다.

IPv6 연결 없이 BIND 서버를 사용하는 경우 IPv6을 비활성화 named하고 루트 힌트 IPv6 주소에서 가져오는 것이 좋습니다. 분명히 여전히 AAAA 주소를 확인하려고 시도할 것입니다.

따라서 BIND 구성의 경우

/etc/default/bind9에서 IPv4 주소에 -4를 추가합니다.

OPTIONS="-4 -u bind"

에서 /etc/bind/db.rootAAAA DNS 루트가 있는 모든 줄을 삭제합니다.

답변3

BIND9을 사용하는 동안 비슷한 문제가 발생했습니다. 이 문제를 해결하려면 다음을 추가해야 했습니다.

filter-aaaa-on-v4 yes;

named.conf.

(추가 정보)

답변4

누군가가 컬 형식.txt를 찾고 있는 경우. 이것을 쉘에 붙여넣으면 형식 파일이 생성됩니다. 원본 링크가 작동하지 않았습니다. 이 예를 찾았습니다여기

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

관련 정보