호스트는 www.facebook.com
, www.gooogle.com
과 같이 사람이 기억하기 쉬운 이름을 호스트명으로 가지고 있다. 하지만 이렇게 변동 길이의 알파벳-숫자의 문자열은 라우터로 처리하기 어렵기 때문에, 호스트는 IP 주소로도 식별된다.
IP 주소는 4바이트로 이루어져 있다(IPv4의 경우). 예를 들어 121.7.106.83
이라는 IP 주소를 살펴보자. 마침표가 각 10진수 0~255로 구분되는 바이트를 구분하고 있다. IP 주소의 왼쪽에서 오른쪽으로 갈수록 호스트가 인터넷의 어디에 위치해 있는지, 그 위치 정보가 더 구체적으로 나타난다. 때문에 IP 주소는 계층 구조를 이루고 있다고 말한다.
호스트를 식별하기 위해서는 두 가지 방법, 호스트명과 IP 주소를 이용할 수 있다고 했다. 사람들은 기억할 수 있는 호스트명을 선호하는 한편, 라우터는 고정된 길이에 계층적인 IP 주소를 선호한다. 이러한 차이를 해소하기 위해서는 호스트명을 IP 주소로 변환하는 디렉토리 서비스가 필요한데, 이것이 인터넷의 도메인 이름 시스템(DNS, domain name system)이 하는 일이다.
DNS는 (1) DNS 서버의 계층에 구현되어 있는 분산 데이터베이스이며, (2) 호스트가 이 분산 데이터베이스에 쿼리를 날릴 수 있도록 하는 애플리케이션-계층 프로토콜이다. DNS 서버는 보통 Berkeley Internet Name Domain(BIND) 소프트웨어를 실행하는 UNIX 머신이고, DNS 프로토콜은 UDP와 53번 포트를 이용한다.
DNS는 다른 애플리케이션-계층 프로토콜들에 의해 쓰이기도 한다. 예를 들어 HTTP나 SMTP를 사용할 때, 사용자가 젝송한 호스트명을 IP 주소로 변환할 때 그렇다. 사용자 호스트에서 실행되는 브라우저가 www.someschool.edu/index.html
URL을 요청한다고 해보자. 사용자 호스트가 웹 서버 www.someschool.edu
로 HTTP 요청 메시지를 보내려면, 사용자 호스트는 우선 해당 웹 서버의 IP 주소를 얻어야 한다. 이는 다음과 같이 이루어진다.
이렇게 DNS를 통해 IP 주소를 찾으면 추가적인 딜레이가 발생하게 되겠지만, IP 주소는 보통 "근처의" DNS 서버에 캐싱되기 때문에, DNS 네트워크 트래픽과 평균 DNS 딜레이는 줄어들게 된다.
DNS는 호스트명을 IP 주소로 바꾸는 서비스 외에도 몇 가지 중요한 서비스들을 제공한다.
Host aliasing: 호스트는 하나 이상의 별칭을 가질 수 있다. 복잡한 호스트명을 가지고 있는 호스트를 생각해보자. DNS를 이용하면 호스트의 별칭을 통해 호스트의 IP 주소 뿐만 아니라, 그 복잡한 표준(canonical) 호스트명도 알아낼 수 있다.
Mail server aliasing: 이메일 주소는 기억하기 쉬운 게 좋다. 하지만 메일 서버의 실제 호스트명은 사실 더 복잡할 수 있다. DNS를 이용하면 메일 애플리케이션에서도 별칭을 이용해 해당 호스트의 표준 호스트명을 알아낼 수 있다.
Load distribution: DNS는 복제된 웹 서버 사이의 부하를 분산하는 데에도 쓰일 수 있다. 사용량이 많은 사이트는, 서로 다른 종단 시스템에 돌아가고, 따라서 서로 다른 IP 주소를 가지고 있는 여러 서버들로 복제되곤 한다. 이 복제된 웹 서버들의 경우, 한 표준 호스트명에 IP 주소의 집합이 결부된다. DNS 데이터베이스에는 이러한 IP 주소 집합이 들어가있다. 클라이언트가 해당 주소 집합에 매핑되는 이름에 대한 쿼리를 보내면, 서버는 이 주소 집합을, 순서를 돌려가며 사용자에게 보내준다(DNS rotation). 클라이언트는 보통 이 집합의 첫 번째 IP 주소로 HTTP 요청 메시지를 보내기 때문에, DNS가 이렇게 순서를 바꿔주면 복제 서버들 사이의 트래픽을 분산시키는 결과로 이어진다. 메일 서버의 경우도 마찬가지로 DNS 로테이션이 일어난다.
HTTP, FTP, SMTP와 마찬가지로 DNS 프로토콜도 애플리케이션-계층 프로토콜이다. DNS 프로토콜도 (1) 클라이언트-서버 패러다임을 이용해, 통신하는 두 종단 시스템 사이에서 실행되며, (2) 통신하는 종단 시스템 사이에서 DNS 메시지를 전송하기 위해 그 기저의 end-to-end 전송 프로토콜에 의존하기 때문이다.
다만 웹, 파일 전송, 이메일 애플리케이션과 달리, DNS는 사용자끼리 직접 상호작용하기 위해 쓰이는 애플리케이션은 아니고, 사용자 애플리케이션 및 다른 인터넷 소프트웨어에 핵심적인 인터넷 기능을 제공하기 위한 것이다.
이제는 DNS가 어떻게 동작하는지, 특히 호스트명-IP 주소 변환 서비스에 초점을 맞춰, 높은 수준에서 살펴보자.
사용자 호스트에서 실행되는 어떤 애플리케이션이 호스트명을 IP 주소로 변환하고자 한다고 해보자. 이 애플리케이션은 변환될 필요가 있는 호스트명을 명시하며 DNS의 클라이언트 사이드를 호출한다. 그러면 사용자 호스트의 DNS는 네트워크로 쿼리 메시지를 보낸다. 이때 모든 DNS 쿼리와 응답 메시지는 포트 53에서 UDP 데이터그램으로 보내진다. 수 밀리초에서 수 초 정도의 지연 이후, 사용자 호스트의 DNS는 원하던 매핑을 제공하는 DNS 응답 메시지를 받는다. 이 매핑은 호출 애프리케이션으로 전달된다.
애플리케이션의 입장에서야 DNS는 간단하고 직관적인 변환 서비스를 제공하는 것처럼 보이지만, 이 서비스는 전세계에 분산된 수많은 DNS 서버들을 포함하며, 보다 복잡하게 구현된다.
간단하게, 모든 매핑이 들어있는 하나의 DNS 서버만이 있다고 해보자. 이 중앙 집중형 설계에서 클라이언트는 간단히 모든 쿼리를 하나의 DNS 서버로 보내고, DNS 서버는 해당 클라이언트들에게 직접 응답을 할 수 있다. 하지만 이런 중앙 집중형 설계에는 다음과 같은 문제들이 있다.
요컨대 단일 DNS의 중앙 집중형 데이터베이스에는 확장성이 없다.
확장성 문제를 처리하기 위해, DNS는 계층 구조를 이루는, 전 세계에 분산된 수많은 서버들을 사용한다. 기본적으로 DNS 서버에는 루트(root), 최상위 도메인(top-level domain), 권한형(authoritative) DNS 서버의 세 클래스가 있다.
DNS 클라이언트가 호스트명 www.amazon.com
의 IP 주소를 찾고 싶어 한다고 해보자. 이때 다음과 같은 일들이 일어난다.
com
를 위한 TLD 서버를 위한 IP 주소를 반환하다. amazon.com
를 위한 권한형 서버의 IP 주소를 반환한다. www.amazon.com
에 대한 IP 주소를 반환 받는다.각 DNS 서버 클래스들에 대해 더 자세히 알아 보자.
루트, TLD, 권한형 DNS 서버는 모두 계층적 구조를 이룬다.
DNS 서버에는 로컬 DNS 서버라 불리는 다른 타입의 DNS 서버도 있다. 로컬 DNS 서버는 이 서버 계층 구조에 포함되지는 않지만, DNS 아키텍처에서 핵심적인 역할을 한다.
각 ISP는 로컬 DNS 서버를 가지고 있고, ISP는 호스트가 ISP에 접속할 때, 자신의 로컬 DNS 서버들 중 하나 이상의 IP 주소를 준다. 호스트의 로컬 DNS 서버는 보통 호스트에게 가까이 위치하고 있다. 기업의 경우, 보통 호스트와 같은 LAN에 위치하고, 가정의 경우 몇 개의 라우터만 지나면 되는 거리에 있다. 호스트가 DNS 쿼리를 만들면, 이 쿼리는 로컬 DNS 서버로 보내지고, 로컬 DNS 서버는 프록시의 역할을 한다.
호스트에서 어떤 도메인에 대한 쿼리를 보낸다고 하자. 로컬 DNS 서버가 있으면 이 쿼리는 로컬 DNS 서버로 보내진다. 로컬 DNS 서버는 원래 요청 호스트가 직접 했어야 했던 일들을 모두 대신 한 후, 최종 쿼리 결과를 요청 호스트로 보내준다.
앞에서는 TLD DNS 서버가 호스트명을 위한 권한형 DNS 서버를 알고 있다고 가정했지만, 일반적으로는 그렇지 않다. 대신 TLD 서버는 호스트명을 아는 권한형 DNS 서버를 아는, 중간(intermediate) DNS 서버만을 알 수도 있다.
예컨대 위 그림의 dns.umass.edu
가 권한형 DNS 서버가 아니라 중간 DNS 서버라 해보자. 이 서버는 cs.umass.edu
로 끝나는 모든 호스트명을 관리하는 권한형 서버 dns.cs.umass.edu
의 주소를 반환한다. 이 경우 위 그림의 7번 응답을 받고 나서 로컬 DNS 서버는 dns.cs.umass.edu
로 호스트명에 대한 쿼리를 한 번 더 보내고 응답을 받아온 후, 그 결과를 요청 호스트에게로 보내게 된다.
쿼리의 종류에는 재귀형(recursive) 쿼리와 반복형(iterative) 쿼리가 있다. 위 그림에서 요청 호스트에서 로컬 DNS 서버로 가는 쿼리는 재귀형 쿼리로, 요청 호스트가 자신을 대신해 매핑을 얻어 오도록 하는 쿼리다. 이후의 2, 4, 6번 쿼리는 반복형 쿼리로, 각 DNS 서버에서 로컬 DNS 서버로 직접 응답을 얻어 온다.
아래의 그림은 모든 쿼리가 재귀형인 DNS 쿼리 체인이다. 다만 보통 실제 쿼리는 위 Figure 2.19의 패턴을 따른다.
DNS 캐싱은 DNS 시스템에서 아주 중요하며, DNS는 DNS 캐싱을 이용해 지연 성능을 높이고 DNS 메시지의 수를 줄인다.
쿼리 체인에서 DNS 응답을 받은 DNS 서버는 해당 매핑을 자신의 로컬 메모리에 캐싱한다. 예를 들어 Figure 2.19의 로컬 DNS 서버는 어떤 DNS 서버로부터 응답을 받을 때마다 해당 응답에 들어있는 정보를 캐싱할 수 있다. 만약 호스트명/IP 주소 쌍이 DNS 서버에 캐싱되어 있고, 같은 호스트명에 대한 쿼리가 해당 서버에 도달하면, DNS 서버는 다른 DNS 서버로 쿼리를 보내지 않고 바로 해당 쿼리에 대한 응답을 보낼 수 있을 것이다. 다만 호스트명-IP 주소의 매핑이 영구적이지는 않기 때문에 DNS는 캐싱된 정보를 일정 기간이 지나면 버려야 한다.
DNS 분산 데이터 베이스를 함께 구현하는 DNS 서버들은 리소스 레코드(RR, resource record)들도 함께 저장하며, 이 리소스 레코드들 중에는 호스트명-IP 주소 매핑을 제공하는 것도 있다. 각 DNS 응답 메시지는 하나 이상의 RR을 가지고 있다.
RR은 다음과 같이 네 개의 필드를 가지고 있는 튜플이다.
(Name, Value, Type, TTL)
TTL
은 리소스 레코드의 유효 기간으로, 해당 리소스가 캐시에서 지워져야 하는지의 여부를 결정한다. 아래에서는 Type
에 따라 Name
과 Value
필드가 어떤 의미를 하는지를 살펴보자.
Type=A
일 때, Name
은 호스트명이고 Value
는 호스트의 IP 주소에 해당한다. Type=NS
이면 Name
은 도메인이고, Value
는 해당 도메인에 속하는 호스트의 IP 주소를 어떻게 얻을 수 있을지 아는 권한형 DNS 서버의 호스트명이 된다. 이 타입은 쿼리 체인을 따라 DNS 쿼리를 계속 보내야 할 때 쓰인다.Type=CNAME
이면 Name
은 별칭 호스트명, Value
는 표준 호스트명이다. Type=MX
이면, Name
은 별칭 호스트명, Value
는 메일 서버의 표준 이름이다. 메일 서버의 표준 이름(canonical name)을 얻고자 할 때에는 MX
, 그 외 다른 서버의 표준 이름을 얻으려 할 때에는 CNAME
을 사용한다.
DNS 메시지에는 쿼리와 응답 두 종류의 메시지 밖에 없는데, 이 메시지들은 동일한 형식을 가지고 있다.
첫 번째 12 바이트는 헤더 섹션으로, 여러 필드가 있다. 첫 번째 필드는 쿼리를 식별하기 위한 16-bit 필드다. 이 필드는 쿼리에 대한 응답 메시지에도 복사되어, 클라이언트가 보낸 쿼리와 받은 응답을 매치할 수 있도록 한다.
그 뒤에는 많은 플래그들이 있는 플래그 필드가 있다. 플래그에는 다음과 같은 것들이 있다.
헤더 섹션에는 이외의 네 필드도 있는데, 이 필드들은 헤더 뒤의 네 데이터 섹션에 해당하는 것들이 몇 개 씩 있는지를 나타낸다.
위에서는 DNS 데이터베이스에서 레코드를 탐색하는 데에 초점을 맞춰 논의를 진행했다. 그렇다면 어떻게 레코드를 데이터베이스에 넣을 수 있을까?
새로운 도메인명은 레지스트라(registrar)에 등록한다. 레지스트라는 도메인명의 고유성을 검증하고 이를 DNS 데이터베이스에 입력하고, 그러한 서비스에 대가로 돈을 받는 영리 단체다. 1999년 이전에는 레지스트라가 하나 밖에 없었지만, 지금은 많은 레지스트라들이 있고, ICANN(Internet Corporation for Assigned Names and Numbers)에서 다양한 레지스트라들에 대한 승인을 내리고 있다.
도메인명을 레지스트라에 등록할 때에는 이름과 함께 주/보조 권한형 DNS 서버의 IP 주소도 제공해야 한다. 그러면 레지스트라는 그에 해당하는 Type NS, Type A 레코드를 TLD 서버에 넣는다.
예를 들어 networkutopia.com
이라는 도메인을 등록하려고 한다고 해보자. dns1.networkutopia.com
, dns2.networkutopia.com
이 각각 주/보조 권한형 DNS 서버의 이름이고 그 IP 주소는 차례로 212.2.212.1
, 212.212.212.2
라 하자.
레지스트라는 TLD에 주 권한형 DNS 서버를 등록하기 위해 다음의 두 RR을 DNS에 넣는다
(networkutopia.com, dns1.networkutopia.com, NS)
(dns1.networkutopia.com, 212.212.212.1, A)
www.networkutopia.com
웹 서버를 위한 Type A RR과, mail.networkutopia.com
메일서버를 위한 Type MX RR도 권한형 DNS 서버에 넣었다고 해보자.
이제 누군가가 웹 페이지 www.networkutopia.com
에 접속하려고 한다 해보자. 호스트는 일단 DNS 쿼리를 자신의 로컬 DNS 서버로 보내고, DNS 서버는 TLD com 서버에 접속한다. TLD 서버에는 위의 Type NS, Type A RR이 있다. TLD com 서버는 사용자의 로컬 DNS 서버에 두 RR을 담아 답장을 보낸다.
이후 로컬 DNS는 212.212.212.1
(권한형 서버)로 DNS 쿼리를 보내, www.networkutopia.com
에 해당하는 Type A 레코드를 요청한다. 응답에는 원하던 웹 서버의 IP 주소(예를 들어 212.212.71.4
)가 들어있고, 로컬 DNS 서버는 이를 사용자 호스트로 돌려준다. 사용자의 브라우저는 이제 212.212.71.4:80
과 TCP 연결을 시작하고, 이 연결로 HTTP 요청을 보낸다.
최근까지 DNS 서버의 내용은 정적으로 설정되었지만, 요즈음에는 DNS 프로토콜에 UPDATE 옵션이 추가되어 DNS 메시지로 동적으로 데이터를 추가하거나 삭제할 수 있게 됐다.