요약

  • 원래 DNS 복제 루프에서는 보조 서버가 존에 정의된 refresh 간격에 따라 폴링을 수행했다. 이 방식은 기본 서버의 부담을 아꼈지만, 권위 서버 간의 불일치 기간이 설계된 운영 상태가 되는 결과를 낳았다.
  • DNS NOTIFY는 대체 존을 밀어넣지 않았다. 설정된 보조 서버에게 SOA 시리얼을 확인하라고 알려줬고, IXFR는 그 보조 서버가 이미 보유한 버전 이후의 순서화된 변경 사항을 요청할 수 있게 했으며, AXFR은 완전 사본 폴백으로 유지되었다.
  • 빨라진 경로도 모듈형 시리얼 산술, 안정 저장소, 완전한 처리, 원자적 활성화, 선택적 트랜잭션 인증에 의해 제한되었다. 신호는 검토를 앞당겼을 뿐, 그 자체로 다른 서버를 다시 쓰는 권한을 얻지 못했다.

권위가 스스로에게 불일치하던 그 몇 분

DNS 존에 여러 권위 서버가 존재하는 이유는 정확히 말해, 어느 한 기계, 한 링크 또는 한 기관이 존에 답할 수 있는 유일한 지점이 되지 않도록 하기 위함이다. 복제는 회복 탄력성을 만들지만, 덜 주목받는 질문도 만든다. 존이 변경된 후, 두 권위 서버의 답이 서로 다른 현실을 기술할 수 있는 시간은 얼마나 될 수 있는가?

원래의 답은 의도적으로 시간에 기반한 것이었다.RFC 1034는 한 네임 서버에 기본 사본을 두고, 보조 사본들이 주기적으로 기본 사본을 확인하는 구조를 기술했다. 보조 서버는 존의 Start of Authority 레코드를 질의하고, 자신의SERIAL을 기본 서버의 것과 비교한 뒤, 기본 서버의 버전이 더 최신이면 존을 전송받았다. 존 자체에는REFRESH,RETRY,EXPIRE값이 담겼다.RFC 1035는 이 필드들을 32비트 양으로 확정하고, AXFR을 완전한 존 전송을 요청하는 오퍼레이션으로 지정했다.

이 메커니즘은 무성의한 것이 아니었다. 끊임없는 통신 트래픽을 피했고, 안정된 존은 반복해서 복사할 필요가 없었으며 대부분의 확인은 작은 SOA 질의였다. 확인에 실패하면 보조 서버는 재시도했다. expire 구간 전체 동안 새로 고침에 실패하면, 무기한 오래된 사본을 제공하는 대신 권위 서버로서의 동작을 중단해야 했다.

그러나 이 메커니즘은 지연을 정책으로 만들었다. 기본 서버의 변경과 다음 성공적인 refresh 확인 사이에서, 보조 서버는 올바르게 구성되어 있고 겉보기에 건강한 상태를 유지하면서 이전 버전으로 답할 수 있었다. refresh 간격을 짧게 하면 기본 서버로의 질의를 늘려 그 간격을 좁혔고, 길게 하면 불일치 시간이 늘어나는 대가를 치르고 기본 서버를 보호했다.

이 구분이 중요한 이유는 권위 서버 간의 갈래가 리졸버 캐싱과 같지 않기 때문이다. 재귀 리졸버는 모든 권위 서버가 수렴한 뒤에도 TTL이 만료될 때까지 오래된 레코드를 계속 사용할 수 있다. 반대로 권위 서버 집합이 수렴하기 전에는, 캐시가 비어 있는 두 리졸버가 서로 다른 권위 서버에 질의한다는 이유만으로 서로 다른 현재 답을 얻을 수 있다. 이 글의 주제는 그 첫 번째 복제 경계이며, 다운스트림의 리더 대면 TTL 경계가 아니다.

폴링은 지연을 정책 선택으로 만들었다

폴링 설계에서 주도권은 각 보조 서버에 있었다. 보조 서버는 자신이 마지막으로 refresh한 시점, 질의해야 할 마스터, 권위가 만료되어야 하는 시점을 알고 있었다. 기본 서버는 모든 복제본과의 활성 연결을 기억할 필요가 없었다. 이는 분산 시스템에서 강력한 성질이었다. 알림 채널이 사라지더라도 영구적 실명이 될 수 없었는데, 평범한 타이머가 언젠가 다른 확인을 유발하기 때문이었다.

그러나 1990년대 중반까지 존과 기대치는 달라져 있었다. 사소한 수정 하나가 성장 중인 존 전체의 전송을 요구할 수 있었다. 신속한 전파를 원하는 운영자는 아무것도 바뀌지 않았을 때조차 공격적인 폴링을 선택해야 했다. 변경을 발견하는 비용과 변경을 옮기는 비용은 존의 크기와 고요함에 묶여 있었다.

RFC 1996은 이 절충을 완곡한 표현 없이 기술했다. 긴 refresh 시간은 마스터의 부하를 줄였지만 존이 갱신될 때 긴 불일치 구간을 만들었다. DNS NOTIFY는 폴링 옆에 인터럽트를 도입했다. 마스터가 변경 사항을 로드하면, 관련성 있는 무언가가 바뀌었다고 일련의 보조 서버들에 알릴 수 있었다.

“알린다”라는 단어에 그 아키텍처가 담겨 있다. NOTIFY는 신뢰된 대체 데이터베이스를 담지 않았다. 그 평범한 목적은 보조 서버가 SOA 질의를 시작하도록 만드는 것이었다. 수신자는 자신이 신뢰하도록 구성된 마스터를 확인하고 시리얼을 살펴본 뒤, 자신의 버전이 뒤처져 있을 때에만 전송을 시작했다. NOTIFY 답변 섹션의 선택적 데이터는 명시적으로 비보안 힌트였다. 노크는 기다림을 줄였을 뿐, 그 경계를 넘어 방 안의 배치를 바꾸지는 않았다.

패키지가 아니라 노크

기본 notify 대상 집합은 존의 NS 레코드에 이름이 올라간 서버들로 이루어졌되, SOA 마스터로 지명된 서버는 제외되었다. 운영자는 그 집합을 재정의하거나, 공개적으로 나열되지 않고 구성으로만 알려지는 스텔스 보조 서버를 포함시킬 수 있었다. 이는 존이 배포 구조의 일부를 기술하되, 실제 복제 관계는 여전히 로컬 관리가 결정한다는 뜻이었다.

RFC 1996은 이러한 관계들이 전송 루프 없는 의존 그래프를 이루도록 요구했다. 하나의 기본 마스터가 존재했지만, 다른 서버는 자기 사본에 대해서는 보조 서버이고 다운스트림 복제본에 대해서는 마스터일 수 있었다. 성공적으로 갱신한 뒤 다음 수준에 알림을 보낼 수 있었다. 이 설계는 모든 서버가 하나의 글로벌 소스에서 직접 배운다고 가장하지 않으면서 전송 부하를 분산했다.

베스트 에포트 설계는 또한 절제를 요구했다. UDP 알림은 승인되거나 시간 초과될 때까지 재전송될 수 있으며, 백오프는 운영자가 통제했다. 보조 서버는 여러 업스트림 피어로부터 같은 이벤트를 들을 수 있었다. 갱신이 이미 진행 중일 때는 중복을 억제하는 것으로 기대되었는데, 그래야 여러 노크가 여러 동시 전송을 만들어 마스터를 두드리지 않는다.

NOTIFY에 대한 응답은 수신 확인일 뿐, 성공적인 수렴을 보증하지 않았다. 응답이 유실되면 또 다른 노크를 유발할 수 있었다. 위조된 출처는 쓸모없는 SOA 확인을 유발해 온건한 서비스 거부를 일으킬 수 있었다. 오퍼코드를 구현하지 않은 서버는NOTIMP로 답할 수 있었고, 그러면 마스터는 그 알림 시도를 완료된 것으로 간주했다. 평범한 refresh 폴링은 호환성과 복구 메커니즘으로 남았다.

그렇기 때문에 “푸시 DNS(push DNS)”라는 말은 오해를 부르는 압축이다. 기본 서버가 밀어넣은 것은 긴급성이지 권위가 아니었다. 데이터는 여전히 별도의 프로토콜을 통해, 구성된 전송 피어로부터, 버전 비교를 거쳐 이동했고, 수신 서버의 규칙에 따라서만 활성화되었다.

랩어라운드될 수 있던 시리얼

더 빠른 확인은 두 서버가 어느 버전이 더 최신인지 합의할 수 있을 때만 작동한다. DNS는 언제나 SOA 레코드에 32비트 시리얼을 두었지만, 최댓값이 0으로 되감길 때 평범한 정수 직관은 실패한다. IXFR과 NOTIFY와 같은 달에 발표된RFC 1982는 누락된 산술을 정의했다.

시리얼은 날짜가 아니라 유한한 순서 공간 안의 위치다. 덧셈은 모듈형이고 경계가 있다. 비교는 시퀀스에서 앞선 인접 값을, 랩어라운드 후 보통의 정수가 수치상 더 작더라도 더 최신으로 취급한다. 32비트 공간을 정확히 절반씩 나눈 두 값 사이에는 정의된 순서가 없다. 운영자는 SOA expire 구간 내에서 시리얼을2^31−1보다 많이 진행해서는 안 되며, 그러지 않으면 오래된 보조 서버가 “더 최신” 버전을 보유한 것처럼 보일 수 있다.

이 제약은 역사적 흥미로움이 아니다. 시리얼은 보조 서버가 아무것도 하지 않을지, 차이를 요청할지, 존 전체를 교체할지 판단하는 소형 근거다. 무분별한 재사용, 과대한 점프, 깨진 랩어라운드 비교는 유효한 새 데이터를 겉보기에 앞선 오래된 사본 뒤에 가둘 수 있다.

따라서 이 필드는 일상적 이름이 시사하는 것보다 적게 증명한다. 수정이 언제 이루어졌는지, 누가 승인했는지, 내용이 올바른지, 모든 복제본이 설치했는지를 알려주지 않는다. 허용된 사본 간 전이를 순서화한다. 그 좁은 명제는 운영자가 산술적 의미를 지키는 한 복제에 충분하다.

보관물 대신 수정 사항을 보내다

NOTIFY는 변경을 발견하는 데 걸리는 시간을 줄였다.RFC 1995는 변경을 얻는 비용을 줄였다. 원래 AXFR 모델에서는 주소 하나가 바뀌어도 보조 서버가 존 전체를 가져와야 할 수 있었다. IXFR는 클라이언트가 자신이 이미 보유한 사본의 시리얼을 요청에 담아, 서버의 현재 시리얼에 도달하는 데 필요한 차이를 물을 수 있게 했다.

증분 응답은 삭제-추가 시퀀스의 역사다. 각 시퀀스는 오래된 SOA로 시작해 새 SOA가 뒤따르며, 시퀀스들은 클라이언트의 버전에서 현재 버전을 향해 진행된다. 수정된 레코드는 이전 형태의 제거와 새 형태의 추가로 표현된다. RRset의 나머지가 변하지 않았다면 변경된 멤버만 이동하면 된다.

이것은 단순한 압축 이상이다. 수신자의 시작 상태를 명시적으로 만든다. 서버는 추상적으로 “여기 갱신이 있다”고 말하는 것이 아니라, “당신이 시리얼 X를 보유하고 있다는 전제에서, 이 순서화된 변경들을 적용하면 시리얼 Y가 된다”고 말한다. 보조 서버는 전체 체인을 적용한 뒤에야 더 오래된 버전을 교체한다. 불완전한 차이 스트림이 합법적으로 새 존의 절반이 될 수는 없다.

기본 서버나 다른 IXFR 서버는 답하기에 충분한 역사를 보유해야 한다. RFC 1995는 그 역사를 영구 장부로 만들기를 거부했다. 오래된 버전은 비워낼 수 있었고, 차이 응답이 완전 사본보다 커질 때는 AXFR을 쓰도록 권장되었다. 여러 버전을 하나의 차이로 압축해 중간 역사를 희생할 수 있었다. 다른 서버가 클라이언트의 특정 시작 시리얼을 인식하지 못하면 완전 전송으로 폴백할 수도 있었다.

효율성은 여전히 조건부였다. 조용한 큰 존에 수정 하나가 일어나는 경우 IXFR의 효과가 크다. 거듭 다시 쓰이는 존, 새로 프로비저닝된 보조 서버, 변경 저널이 비워진 서버는 그렇지 않을 수 있다. 프로토콜은 최적화를 선택 사항으로 만들고 완전한 상태를 언제나 전송 가능하게 유지함으로써 성공을 보존했다.

옛 전체 사본이 여전히 필요했던 이유

폴백은 종종 당혹스러운 대상으로 서술된다. 현대적 메커니즘이 실패했으니 시스템이 옛 것으로 돌아갔다는 논리다. 그러나 여기서 폴백은 안전 설계의 일부다. 차이는 알려진 시작 버전과 보유된 변경 경로를 전제로만 의미가 있다. AXFR은 그 공유된 역사가 없을 때 현재 존 전체를 재구성한다.

RFC 5936은 배포된 AXFR을 중요한 무결성 규칙과 함께 재규격화했다. 클라이언트는 부분적으로 전송된 존을 노출해서는 안 된다. 데이터를 별도의 파일이나 저장소로 받아, 건전성 검사를 수행하고, 완성된 버전을 원자적으로 공개해야 한다. 전송이 실패하면 이전의 유효한 버전이 서비스를 유지한다.

RFC 1995는 소스 쪽에 대응하는 의무를 부과했다. 새 존 버전은 IXFR이나 AXFR에 답하는 데 사용되기 전에 안정 저장소에 기록되어야 했다. 그렇지 않으면 마스터가 데이터를 배포한 뒤, 보조 서버들이 이미 수용한 버전 없이 충돌하고 재시작할 수 있었다. 내구성 있는 원점 상태 없는 신속 전파는 바로 이 프로토콜이 줄이려 했던 지속적 불일치를 만들 것이다.

따라서 수신 서버에는 실질적 결정 경계가 있다. 알림은 작업을 트리거할 수 있다. 시리얼은 작업이 필요함을 보여줄 수 있다. IXFR이나 AXFR 스트림은 후보 상태를 공급할 수 있다. 완료된 처리와 원자적 활성화만이 서버가 무엇을 권위 답변으로 내놓을지 결정한다.

빠르다고 덜 책임 있는 것은 아니다

존 전송은 존의 내용을 드러내고, 권위 서버가 답하는 근거 데이터를 교체할 수 있다. RFC 5936은 정책에 따라 전송 접근을 제한할 것을 권고하고, 인증과 무결성을 위해 트랜잭션 서명 메커니즘을 가리킨다. 현재 인터넷 표준은 공유 비밀키 기반 메시지 인증 코드를 이용하는 TSIG를 규정한RFC 8945이다.

여러 메시지로 이루어지는 TCP 전송에서 TSIG는 무결성을 스트림 전반에 걸쳐 연쇄해 수신자가 변조를 감지할 수 있게 한다. 합의된 비밀을 보유한 당사자로부터 메시지가 왔음을 인증할 수 있다. 이는 실질적 보호지만 여전히 점 대 점(point-to-point)이다. 키 배포는 대역 외에서 이루어지며, 공유 키는 많은 피어 사이에서 번거로워지고, 유출되면 한 당사자가 같은 비밀의 다른 보유자를 사칭할 수 있다.

TSIG는 전송을 암호화하지도 않는다. 더 근본적으로, 이는 트랜잭션을 인증하는 것이지 존의 진실성을 인증하는 것이 아니다. 올바르게 서명된 마스터도 여전히 오류가 있거나 악의적인 수정을 제공할 수 있다. 보조 서버는 “MAC이 검증됐다”를 “이 데이터에 이름이 올라간 기관이 모든 주장을 승인했다”나 “이 레코드가 법적 소유권을 확립한다”로 바꿔서는 안 된다. 전송 무결성은 어느 피어가 무엇을 보냈는지를 보존할 뿐, 출처의 판단을 개선할 수 없다.

이 구분이 1996년 설계를 더 내구성 있게 만든다. 구성, 버전 근거, 폴백, 안정 저장소, 수신자 측 활성화를 지우지 않고 속도를 더했다. 메커니즘은 패킷이 조금 더 일찍 도착했다는 이유만으로 모든 보조 서버에 네트워크를 신뢰하라고 요구하지 않았다.

조용한 헌법적 교훈

DNS NOTIFY와 IXFR은 헌법적 변화로 소개되는 일이 드물다. 새로운 통치 기구를 만들지 않았고, 새로운 소유자 계층을 선언하지도 않았다. 그러나 축소판 거버넌스 문제를 해결했다. 한 운영 권위가 직접 통제권을 얻지 않으면서 다른 권위를 빠르게 바꾸게 만들려면 어떻게 해야 하는가?

답은 제한된 진술들의 연쇄였다. “무언가 바뀌었다”는 확인을 유발했다. “내 시리얼은 Y다”는 X와 비교될 수 있었다. “X에서 Y까지의 차이는 다음과 같다”는 처리될 수 있고, 완전 사본으로 대체될 수도 있었다. “이 트랜잭션은 합의된 인증자를 담고 있다”는 경로를 보호할 수 있었다. 그 진술 중 어느 하나만으로는 활성 권위가 되지 않았다.

그 연쇄에는 비용이 있다. 운영자는 올바른 시리얼, 알림 관계, 저널, 전송 권한, 내구성 있는 데이터, 경보를 유지해야 한다. 로컬 구성에 숨겨진 토폴로지는 표류할 수 있다. 보조 서버는 만료될 수 있다. 공격적인 알림자는 부하를 만들 수 있다. 잘못된 변경은 예전보다 빠르게 수렴할 수 있다. 가속은 교정의 수명과 실수를 알아차릴 시간을 똑같이 줄인다.

그러나 그 대안은 복잡성 없는 책임이 아니다. 아무도 보라고 말하지 않아 낡은 채로 머무는 권위다. 역사적 성과는 독립적 검증을 보존하면서 일관성을 신속하게 만든 것이다. 존은 노크를 배웠고, 보조 서버는 신중하게 문을 여는 권리 — 그리고 부담 — 을 지켰다.

출처와 근거의 한계

RFC 1034와 RFC 1035는 폴링, SOA 타이머, 시리얼 비교, 완전 전송을 확립한다. RFC 1982는 시리얼 산술을 정의한다. RFC 1995는 증분 차이와 완전 전송 폴백을 정의한다. RFC 1996은 베스트 에포트 알림과 구성된 의존 그래프를 정의한다. RFC 5936은 완전하고 원자적인 AXFR 활성화를 명확히 한다. RFC 8945는 점 대 점 트랜잭션 인증과 그 한계를 정의한다.

이 규격들은 프로토콜 설계와 요구사항을 확립하지만, 보편적인 배포 연대기나 측정된 글로벌 수렴 시간을 확립하지 않는다. 모든 구현이 같은 기본값을 쓰거나, 같은 저널 깊이를 유지하거나, 전송을 인증하거나, 1996년 8월에 확장을 설치했다는 것을 증명하지 않는다. 주장은 아키텍처적이다. 표준들은 트리거, 버전 근거, 전송, 활성화를 분리해, 알림을 자가 집행적으로 만들지 않으면서 더 빠른 복제를 가능하게 했다.