Incident Library
  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례2건

2건 중 1~2번째

  1. 증상

    DNS 오류율과 서버 부하가 늘었다는 알림이 울렸다. 일부 AdGuard DNS 사용자는 DNS 조회가 느려지거나 실패했고, 타임아웃과 SERVFAIL 응답을 받았다.

    촉발

    AdGuard 는 11월 25일에 사용자 데이터 캐시 방식을 개선하려는 새 AdGuard DNS 버전을 배포했다. 버그 때문에 리졸버가 로컬 캐시 파일에 전체 사용자 데이터가 아니라 최근에 바뀐 일부만 저장했다. 다시 시도한 배포에서 많은 리졸버가 한꺼번에 전체 동기화를 시작했다.

    원인
    구성 요소
    기여 요인
    감지

    15시 30분에서 16시 UTC 사이, 두 번째 배포를 시작한 뒤 DNS 오류율과 서버 부하가 늘었다는 알림이 울렸다.

    조치
    • 버그가 있는 버전을 모든 서버에서 동시에 롤백했다. 롤백은 17시 30분에서 18시 UTC 사이에 끝났다.
    • 암스테르담의 트래픽 일부를 다른 유럽 거점으로 돌렸다. 암스테르담은 안정됐지만 프랑크푸르트와 런던의 부하가 늘었다.
    • 프랑크푸르트와 런던에서 실제 연결 동시성과 파이프라인 깊이를 줄였다. 프랑크푸르트에서 파이프라인 깊이를 5에서 1로 줄이자 매우 빨리 회복됐다.
    • 한도를 실제 하드웨어 용량에 맞게 조정했다.
    • 전체 동기화가 더 일어나지 않도록 손상된 캐시 파일과 사용자 데이터 스냅샷을 고쳤다.
    • 트래픽 분배를 정상으로 돌렸고 오류율이 평소 수준으로 내려왔다.
    후속 조치
    • 전체 사용자 데이터가 로컬 캐시 파일에 제대로 직렬화되고 그 파일에서 제대로 복원되는지 확인하는 자동 테스트를 넣는다. 캐시가 비었거나 잘린 것도 잡아내게 한다.
    • 실제와 비슷한 부하에서 빈 캐시나 손상된 캐시로 리졸버를 시작하는 통합 테스트를 넣어, 시스템이 무리 없이 동작하고 비즈니스 로직 서비스에 과부하를 주지 않는지 확인한다.
    • 거점마다 서버 하드웨어 사양을 하나로 맞춰 RAM 크기가 크게 다른 서버가 한 클러스터에 섞이지 않게 하거나, 하드웨어 종류마다 설정을 따로 관리한다.
    • 표준 노드 종류마다 connlimit, 캐시 크기, 연결 한도를 다시 살펴 조정해 32 GiB 노드와 64 GiB 노드가 모두 안전한 가비지 컬렉션과 메모리 범위 안에서 돌게 한다.
    • 최대 부하에서도 고루틴과 힙이 지나치게 늘지 않도록 파이프라이닝 깊이를 다시 따져 보고 필요한 곳은 낮춘다.
    • 연결 수와 고루틴 수를 제한하는 방식을 다시 따져 보고, 자원 사용을 적절히 제한하면서도 연결이 끊긴 뒤에도 처리량이 충분히 나오게 한다.
    • 모니터링이 CPU 와 전체 메모리뿐 아니라 Go 힙 크기, 가비지 컬렉션 시간, 초당 가비지 컬렉션 횟수, 클러스터별 요청 지연 분포도 보게 넓힌다.
    • 상위 DNS 가 정상인데 SERVFAIL 비율과 요청 처리 시간이 계속 오르면 울리는 알림을 따로 둬, 내부 경합과 가비지 컬렉션 문제를 사용자가 겪기 전에 잡는다.
    • DNS 리졸버의 배포와 롤백 절차를 다듬어 전체 서버의 큰 부분에서 캐시가 동시에 무효화되지 않게 한다.
    • 암스테르담과 프랑크푸르트에서 본 동작을 바탕으로, 사고 중에 파이프라인 깊이, 연결 한도, connlimit 을 빨리 조정하는 플레이북을 문서로 만들고 연습한다.
    교훈

    노드마다 다르게 움직인 데에는 사용할 수 있는 RAM, Go 가비지 컬렉터, connlimit 설정이 서로 맞물린 것이 컸다. 메모리가 큰 서버에서 connlimit 을 너무 높게 잡으면 힙이 크게 자란 뒤에야 가비지 컬렉션이 강하게 돈다. 그러면 메모리는 남아도 CPU 시간이 가비지 컬렉션에 점점 더 쓰여, 지연이 늘고 처리량이 준다. AdGuard 는 이것을 메모리를 많이 쓰는 애플리케이션에서 connlimit 이 만드는 알려진 최악의 경우라고 했다. 메모리가 작은 서버는 캐시 크기와 연결 한도를 RAM 에 맞춰 줄이지 않아서 더 일찍 실패했다. 여기에 높은 파이프라이닝과 많은 재시도가 겹쳐 가비지 컬렉션 압박, 연결 포화, 클라이언트 재시도가 서로를 키우는 고리가 생겼다.

  2. 증상

    2021년 9월 30일 slack.com 의 DS 레코드를 DNS 등록 기관에 올린 직후 Customer Experience 팀에 사용자 신고가 들어왔다. Slack 클라이언트에 "ERR_NAME_NOT_RESOLVED" 오류가 뜬다는 신고였다. 그런데 DNSSEC 검증을 강제하는 이름 해석 모니터링과 DNSSEC 프로브는 모두 정상으로 나왔다.

    촉발

    2021년 9월 30일 Traffic Engineering 팀이 세 번째 시도로 slack.com 의 Route53 영역과 NS1 하위 위임 영역에 DNSSEC 서명을 켜고, 세 시간 뒤 DNS 등록 기관에 slack.com 의 DS 레코드를 올렸다.

    원인
    구성 요소
    기여 요인
    감지

    DS 레코드를 올린 직후 Customer Experience 팀이 ERR_NAME_NOT_RESOLVED 를 본다는 사용자 신고를 받았다. 이때 DNSSEC 프로브는 정상으로 나왔다. 서명을 되돌린 뒤에는 외부 DNS·DNSSEC 해석 프로브가 여러 리졸버의 해석 실패를 알려 Traffic 팀이 호출됐다.

    조치
    • 등록 기관에서 slack.com 의 DS 레코드를 내려 .com 영역에서 지웠다.
    • slack.com 권한 영역과 위임 영역의 DNSSEC 서명을 되돌려 마지막 정상 설정으로 돌렸다.
    • 주요 ISP 와 공개 DNS 리졸버 운영자에게 연락해 slack.com 의 캐시 레코드를 모두 비워 달라고 요청했다.
    • Google 8.8.8.8 과 Cloudflare 1.1.1.1 처럼 캐시 비우기 사이트를 둔 리졸버는 팀이 직접 캐시를 비웠다.
    교훈

    Slack 은 와일드카드 레코드가 있는 도메인을 slack.com 보다 먼저 시험하지 않은 것을 실수로 꼽았다. .com 영역의 DS 레코드는 리졸버에 최대 24시간 캐시되므로, DS 레코드를 내린 뒤에도 그 시간 동안은 권한 영역에서 DNSKEY 를 지우면 안 된다. 영역에 서명을 다시 켜도 DS 레코드의 TTL 에는 영향이 없다. Terraform 으로 DNS 를 관리하면 Route53 콘솔이 서명을 끌 때 띄우는 경고를 보지 못한다. 리졸버마다 NSEC 응답을 다르게 해석해도 규격에 맞을 수 있으므로, 권한 이름 서버가 실제로 있는 레코드 타입을 NSEC 타입 비트맵에 정확히 담는 것만이 이 모호함을 피하는 길이다.

내 클러스터에도 있는지 확인하기

이 2건에서 가장 많이 나오는 구성 요소: 재귀 DNS 리졸버 서비스, DNS 서버와 레코드. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별2