원문 캡처 · chinmayabharadwaj.substack.com
원문 캡처 · chinmayabharadwaj.substack.com

DNS는 분산 시스템이므로 레코드를 바꿔도 보조 서버와 전 세계의 리졸버에 즉시 반영되지는 않는다. 변경 알림과 영역 전송, 캐시 만료가 어떤 순서로 이뤄지는지 살펴본다. 앞선 글에서는 DNS의 발전과 질의 흐름을 다뤘다.

shipmyproduct.com이라는 웹사이트가 52.168.10.11(node1), 52.168.10.12(node2), 52.168.10.13(node3) IP 주소를 가진 서버에서 운영된다고 하자. node2가 중단되거나 IP가 52.168.10.14로 바뀌면, 이전 주소로 연결한 사용자는 응답 시간 초과나 404 오류를 겪을 수 있다. 새 IP를 DNS에 반영해야 한다.

실제 서비스에서는 공급업체가 변경 과정을 대신 처리하는 경우가 많다. 직접 관리한다면 주 서버의 영역 파일(zone file)을 수정하거나 공급업체 API 또는 동적 DNS 갱신(DDNS)을 이용할 수 있다. 도메인을 호스팅하거나 자체 사본으로 질의에 답하는 서버를 권한 서버라고 한다. 주 DNS 서버는 레코드를 편집하는 서버다.

DNS는 최종적으로 일관성을 갖추는 분산 시스템이다. 따라서 주 서버는 다른 서버에 변경 사실을 알리고, 보조 서버가 직접 변경 내용을 가져가게 한다. 주 서버가 모든 변경 사항을 보조 서버에 일괄 전송하는 방식도 가능하지만, DNS는 가벼운 UDP 알림을 보내고 보조 서버가 필요할 때 데이터를 가져가는 방식을 택한다. 보조 서버는 부하가 크면 TCP 기반 전송을 미루고 나중에 다시 시도할 수 있다.

이 구조에서는 어느 서버의 데이터가 최신인지 확인하고, 보조 서버가 얼마나 자주 동기화할지 정하며, 오래된 레코드를 언제 폐기할지도 관리해야 한다. 이를 위해 각 영역에는 SOA(Start of Authority) 레코드가 필수 메타데이터로 들어간다. SOA는 영역의 단순한 속성이 아니라 TYPE = SOA인 리소스 레코드다. 따라서 BIND나 Knot 같은 DNS 소프트웨어는 A, MX, TXT 레코드와 비슷한 방식으로 SOA 정보를 다룰 수 있다. 클라이언트는 SOA 레코드의 mname(Master name)을 조회해 DDNS 갱신을 보낼 주 서버를 찾을 수도 있다.

shipmyproduct.com의 SOA 레코드는 다음과 같은 형태일 수 있다.

@ IN SOA ns1.shipmyproduct.com. admin.shipmyproduct.com. ( 10 ; Serial number (32 bit serial) 3600 ; Refresh timer (1 hour) 900 ; Retry timer (15 minutes) 1209600 ; Expire timer (2 weeks) 300 ; Minimum / Negative Cache TTL (5 minutes) )

영역 파일을 수정하면 SOA 일련번호(serial)가 증가하고 주 서버에서 영역을 다시 불러온다. 이어 주 서버는 보조 서버에 UDP notify 패킷을 보낸다. 알림 대상은 NS 레코드 집합에 나열된 서버이며, 주 서버 자신인 MNAME은 제외한다. DNS 소프트웨어의 also-notify 설정으로 보조 서버를 추가할 수도 있다. 실제 네임서버를 사설망 방화벽 뒤에 숨기고 공개 DNS 트래픽에 노출하지 않는 숨겨진 주·보조 서버 구성에서도 notify를 이용해 알림을 보낸다.

알림을 받은 보조 서버는 주 서버에 일련번호를 묻는다. 주 서버의 일련번호가 더 높으면 보조 서버는 자신의 일련번호를 보내 IXFR(증분 영역 전송)을 요청한다. 영역에 레코드가 수백만 개 있을 수 있어 매번 전체 사본을 전송하면 비용이 크기 때문이다. 주 서버는 변경 작업을 추가만 하는 저널에 기록하며, BIND에서는 .jnl 파일을 사용한다. 이 기록을 이용해 보조 서버가 가진 버전부터 최신 버전까지의 차이를 만들 수 있다. IXFR은 RFC 1995에 정의돼 있다.

예를 들어 주 서버의 저널에는 일련번호 10에서 11로 바뀌는 동안 이전 IP를 지우고 새 IP를 추가한 기록이 담길 수 있다. 이때 SOA 레코드도 일련번호 10에서 11로 갱신된다.

주 서버가 보조 서버가 보낸 일련번호를 바탕으로 변경 이력을 만들 수 없거나, 보조 서버에 비교할 기존 버전이 없으면 전체 영역 전송인 AXFR을 수행한다. 증분 변경량이 너무 커서 변경분만 보내는 편이 적절하지 않은 경우에도 주 서버는 모든 레코드가 포함된 영역 전체 사본을 보낸다. AXFR은 RFC 5936에 정의돼 있다.

알림이 유실되거나 전송에 실패하면 SOA의 세 가지 시간이 동작을 제어한다. Refresh는 보조 서버가 주 서버에 일련번호가 증가했는지 확인하는 주기다. Retry는 주 서버가 응답하지 않을 때 보조 서버가 다시 시도하기까지 기다리는 시간이다. Expire는 주 서버에 일정 기간 접속하지 못했을 때 적용되는 최대 한계다. 예를 들어 2주 동안 주 서버에 연결하지 못하면 보조 서버는 로컬 사본을 신뢰할 수 없다고 판단하고 해당 영역 질의에 답하지 않는다.

보조 서버가 갱신된 뒤에도 사용자에게 즉시 새 IP가 전달되는 것은 아니다. 8.8.8.8 같은 리졸버는 각 리소스 레코드 집합(RRset)에 설정된 TTL(Time To Live)이 끝날 때까지 캐시에 기존 값을 보관한다. IP가 자주 바뀐다면 TTL을 낮게 설정할 수 있지만, 새 TTL은 다음 캐시 갱신부터 적용된다. 리졸버 자체의 캐시 설정이 추가로 적용될 수도 있다.

IP를 수동으로 바꾸기 어려운 동적 IP 환경에서는 DDNS를 사용할 수 있다. DHCP 서버가 임대 기간이 끝난 IP 주소를 다시 할당하면, 해당 영역에 DDNS가 설정된 경우 주 서버에 갱신을 보낼 수 있다. 예를 들어 node의 새 IP가 52.168.10.14라면 DHCP 서버가 DNS UPDATE() 호출을 자동으로 보내 사람의 개입 없이 DNS를 갱신할 수 있다. 이 방식에는 보안 문제가 따르며, 해당 문제는 뒤에서 다룰 예정이라고 설명한다.