• K8S, DNS 간헐적 5~15초 지연
    DEV 2023. 12. 2. 19:54

    5

    Background

    • k8s 일부 pod에서 간헐적으로 5초 단위의 타임아웃 발생
    • 5*x초의 지연이 DNS조회로 인한 이슈라는 문서를 찾음

    DNS

    • Domain Name System
    • 도메인명(www.daum.net) → IP주소(12.34.56.67)

    In Linux

    • Linux 환경에서 DNS를 사용하는 방법 크게 2가지

    /etc/hosts

    • 도메인명으로 IP를 찾을 때 가장 먼저 열어보는 파일

    /etc/resolv.conf

    • DNS resolver, DNS 서버 목록을 기록한 파일
    • /etc/hosts 파일에 도메인명이 존재하지 않을 경우 /etc/resolv.conf에서 도메인명을 검색할 도메인 서버의 주소를 찾는다.

    DNS in K8S

    CoreDns

    • v.1.12 이후로 k8s에서 사용을 권장하고 있는 도메인 서버 서비스
    • 클러스터를 지속적으로 모니터링하며, 새로운 service, pod가 추가되는 경우 → 도메인 서버에 업데이트

    DNS setting in Pod

    • 새로운 pod가 생성될 때, kubelet이 pod의 /etc/resolv.conf 파일에 clusterDNS서버의 IP주소를 추가
      → pod에서 클러스터 내부의 DNS를 사용할 수 있도록 설정
    • coredns configmap
      - kubernetes: CoreDNS가 쿠버네티스의 서비스 및 파드의 IP를 기반으로 DNS 쿼리에 대해 응답
      - forward: 쿠버네티스 클러스터 도메인에 없는 쿼리들은 모두 사전에 정의된 리졸버(/etc/resolv.conf)로 전달

    Process

    • 다시 위 문서의 해결 과정을 살펴보면..
    1. application에는 문제가 없다고 판단 → tcpdump 확인
      - tcpdump = commandline에서 실행하는 일반적인 패킷 가로채기 소프트웨어
      - wireshark로 분석
    2. A(IPv4), AAAA(IPv6)레코드 두 번 lookup 하는 것을 발견 by libc(표준 C 라이브러리)
    IP worker-4 > domain: 33504+ A? service.domain. (75)
    IP worker-4 > domain: 37094+ AAAA? service.domain. (75)
    

     

    1. A queries were coming quickly
    2. the AAAA queries did not seem to be answered in a timely manner and were repeated after five seconds
    3. 클러스터 내에서 IPv6를 사용하는 곳이 없는데도 libc가 AAAA레코드를 lookup 하는 게 이상했지만 암튼 IPv6를 사용하지 않도록 config를 수정   
    4. 그래도 여전히 AAAA lookup이 5초 이상 발생
    5. This delay is common in kernels where DNAT or SNAT translations are taking place and is caused by a race condition in conntrack 
      1. https://www.weave.works/blog/racy-conntrack-and-dns-lookup-timeouts
      2. man(5) page에서 glibc에서 사용하는 parallel lookup mechanism 발견
      - https://man7.org/linux/man-pages/man5/resolv.conf.5.html
    single-request (since glibc 2.10)
           Sets RES_SNGLKUP in _res.options.  By default,
           glibc performs IPv4 and IPv6 lookups in parallel
           since version 2.9.  Some appliance DNS servers
           cannot handle these queries properly and make the
           requests time out.  This option disables the
           behavior and makes glibc perform the IPv6 and IPv4
           requests sequentially (at the cost of some slowdown
           of the resolving process).
    
    single-request-reopen (since glibc 2.9)
           Sets RES_SNGLKUPREOP in _res.options.  The resolver
           uses the same socket for the A and AAAA requests.
           Some hardware mistakenly sends back only one reply.
           When that happens the client system will sit and
           wait for the second reply.  Turning this option on
           changes this behavior so that if two requests from
           the same port are not handled correctly it will
           close the socket and open a new one before sending
           the second request.
    
    
    timeout:n
             Sets the amount of time the resolver will wait for
             a response from a remote name server before
             retrying the query via a different name server.
             This may not be the total time taken by any
             resolver API call and there is no guarantee that a
             single resolver API call maps to a single timeout.
             Measured in seconds, the default is RES_TIMEOUT
             (currently 5, see resolv.h).  The value for this
             option is silently capped to 30.
    

    Conclusion

    • Linux의 경우 `single-request-reopen` 추가
    dnsConfig:
      options:
        - name: single-request-reopen
    728x90

    'DEV' 카테고리의 다른 글

    Elasticsearch에서의 relation  (1) 2023.12.02
    Spring batch integration test (feat.Elasticsearch)  (0) 2023.12.02
    Test Double  (1) 2023.12.02
    Dependency Mechanism  (1) 2023.12.02
    slf4j, facade, TDD  (1) 2023.12.02
go.