요약

  • RFC 849는 권위 있는 HOSTS.TXT가 최신이면서도 사이트가 실제로 사용하는 복사본은 오래될 수 있는 이유를 보여주었다.
  • 이 문서가 선호한 설계는 속도를 위한 일회성 푸시, 불필요한 전송을 피하기 위한 저렴한 버전 확인, 그리고 전달 실패 후 복구를 위한 시작 시 및 주기적 폴링을 결합했다.

레지스트리가 변경될 때 한 기계의 전원이 꺼져 있다고 하자. 알림은 어디에도 도착하지 못한다. 몇 시간 뒤 기계가 켜지고, 여전히 어제의 호스트 테이블을 들고 응용 프로그램에 의심할 이유가 없는 이름과 주소로 답하기 시작한다.

이 과정 어디에도 마스터 파일이 틀렸다는 사실은 필요하지 않다. 오류는 게시와 사용 사이에 존재한다.

1983년 5월, Mark Crispin은 RFC 849Suggestions for Improved Host Table Distribution에서 바로 이 좁은 문제를 인터넷 커뮤니티에 제기했다. 이 메모는 표준을 제안하지 않았다. 첫머리에서 이렇게 밝혔다: 이 제안들은 나중에 합의가 형성될 수 있는 의견 요청이었다는 것. 그 중요성은 채택보다 진단에 있다. 이 문서는 "레지스트리가 갱신된다"는 하나의 사실을 여러 개의 독립적으로 실패 가능한 사건으로 나누었다.

하나의 파일이 하나의 운영 상태를 의미하지는 않았다

중앙 파일 체계에는 오랜 역사가 있었다. RFC 608은 NIC가 관리하는 원천을 기술했으며, 여기서 호스트 이름·주소·속성의 ASCII 목록을 주기적으로 생성할 수 있었다. 누구든 FTP로<NETINFO>HOSTS.TXT를 가져올 수 있었다. 이 설계는 여러 저자가 경쟁하는 대신 하나의 유지되는 원천을 제공했다.

1982년까지 RFC 810은 이 형식을 인터넷 용도로 확장했다. 테이블에는 네트워크, 게이트웨이, 호스트, 그리고 선별된 프로토콜 정보가 담겼다. SRI-NIC에서 익명으로 가져오거나 NIC 호스트 이름 서버에서 얻을 수 있었다. 그러나 이 메모는 사용자에게 또 하나의 과제를 부여했다: 테이블을 필요한 로컬 형식으로 변환하는 일이다.

이 한 문장이 다운로드 뒤에 운영 경계를 놓았다. 게시된 테이블, 전송된 바이트, 변환된 로컬 데이터베이스, 리졸버의 활성 상태는 같은 대상이 아니었다.

RFC 811은 TCP 포트 101에 질의 서비스를 추가했다. 클라이언트는 이름으로 호스트를 조회하거나 주소로 검색하거나,ALL을 보내BEGIN과END사이에 전체 테이블을 받을 수 있었다. 이는 NIC 정보 접근을 개선했다. 그러나 사이트에 이미 설치된 복사본이 최신인지 운영자에게 알려주지는 않았다.

RFC 849는 바로 이 이음새에서 시작했다. Crispin은 SRI-NIC이 유일하게 상시 가용한 이름 서버이기에는 충분히 신뢰할 수 없어서 사이트들이 로컬 복사본을 유지해야 한다고 썼다. NIC는 전체 레지스트리 덤프와 익명 FTP를 모두 제공했지만, 새 버전을 가져와야 한다는 사실을 누군가는 알아야 했다. 그는 갱신이 항상 신중히 공지된 것은 아니며, 로컬 복사본과 NIC 복사본을 비교하는 좋은 자동 방법도 없었다고 지적했다. 따라서 사이트는 두 방향으로나 실패할 수 있었다: 오래된 데이터를 조용히 유지하거나, 같은 테이블을 다시 가져오는 데 네트워크와 기계 자원을 낭비하는 것이다.

모든 바이트를 옮기기 전에 버전을 묻기

RFC 849의 가장 작은 제안이 가장 유의미할 수 있다. Crispin은 현재 테이블 버전을 보고하는 프로토콜을 원했다. Tenex와 TOPS-20 시스템에서는 파일 세대 번호가 자연스러운 식별자를 제공했다. 그는 이미 NIC 버전과 같은 세대 번호를 가진SYSTEM:HOSTS.TXT를 유지하고, 가끔 번호가 바뀌었는지 확인하고 있었다. 원하는 프로토콜은 이 비교를 자동화할 것이었다.

버전 식별자는 테이블이 정확하다는 것을 증명하지 않는다. 그보다 소박한 일을 한다: "이 릴리스는 이미 갖고 있다"와 "가져올 다른 릴리스가 있다"를 구분한다. 이 저렴한 관찰은 변화가 없을 때 전체 전송을 막고, 변화가 있을 때는 오래됨을 드러낸다.

이것은 근거 경계다. 세대 번호는 배달, 변환, 활성화에 대한 근거가 아니라 판본 동일성에 대한 근거다. 로컬 파일이 현재 번호를 가지면서도 설치가 실패해 리졸버에 도달하지 못할 수 있다. 반대로 오래된 번호는 개별 레코드가 어떻게 다른지 안다고 가장하지 않고도 감지할 수 있다.

푸시가 빠랐던 이유는 실패를 누군가 대신 기억했기 때문

RFC 849의 첫 번째 배포 제안은 참여하는 각 사이트에 새 서버를 두는 것이었다. 이 서버는 등록된 포트에서 "신뢰" 사이트—구체적으로 SRI-NIC, 그리고 어쩌면 다른 곳—로부터 전송되는 레지스트리를 기다릴 것이었다. 협력 사이트들은 거의 즉시 변경을 받을 수 있었다—호스트가 켜져 있다면.

바로 이 조건이 시스템 문제 전체를 품고 있다. 순수 푸시를 완전하게 만들려면 발신자는 꺼진 수신자를 기억하고 나중에 다시 시도해야 했다. NIC는 이름 레지스트리뿐 아니라 두 번째로 끊임없이 변하는 상태 집합—구독 모수, 각 전달 시도의 결과, 도달하지 못한 기계에 대한 재시도 의무—까지 유지해야 했다. 수신자 집합이 커질수록 중앙 기억 장치와 운영 책임도 커졌다.

Crispin은 갱신된 레지스트리에 체크섬을 적용해 수신자가 도착이 완전하고 손상 없음을 확인할 수 있게 하자고 제안했다. 주장은 좁았다. 이 메모는 암호학적 원천 인증, 악의적 변조 저항, 개별 레코드의 의미 검증을 명시하지 않았다. 완전한 전달이라도 잘못된 원천 레코드를 담을 수 있었다. 올바른 파일이라도 로컬 변환에서 실패할 수 있었다. 무결성은 사슬의 한 고리에만 속했다.

메일은 부담을 옮겼을 뿐 해결하지 않았다

세 번째 제안은 테이블을 갱신 수신자 목록에 메일로 보내고 각 사이트가 자체 절차를 정하도록 하는 것이었다. NIC 입장에서는 구현이 간단했다. 그러나 RFC 849는 커지는 파일을 여러 수신자에게 대량으로 보내기에는 나쁜 방법이라며 이를 거부했다.

메일은 또한 제어 상태를 흐렸다. 전달을 위해 접수된 메시지가 곧 수신 운영 체제에 의해 설치된 파일인 것은 아니었다. 큐잉, 메일박스 처리, 추출, 활성화가 모두 발신자의 행동과 사용 가능한 로컬 이름 사이에 끼어 있었다. 이 메커니즘은 바이트를 옮겼지만, 상태 전이를 명시적으로 만들지는 않았다.

하이브리드 설계는 각 실패에 다른 책임자를 두었다

Crispin이 선호한 답은 푸시와 버전 폴링을 결합했다. NIC는 등록된 각 수신자에게 갱신을 한 번 보낸다. 무한한 재시도 부담은 지지 않는다. 시스템 시작 시 각 사이트는 갱신이 존재하는지 물어보고 필요하면 가져오는 프로그램을 실행한다. 주기적 폴링—예시로는 하루 한 번—이 추가 백업이 될 수 있었다.

이 나눔은 경제적이었다. 푸시는 빠른 경로였다: 도달 가능한 기계는 다음 일정을 기다릴 필요가 없었다. 폴링은 복구 경로였다: 꺼져 있던 기계는 발신자가 자신의 개별 가용 이력을 영원히 기억해 주기를 요구하지 않고 돌아왔을 때 복구할 수 있었다. 버전 확인은 변화가 없을 때 이 복구 경로를 저렴하게 유지했다.

어떤 단계도 즉각적인 수렴을 보장하지 않는다. 호스트는 푸시 시점에 꺼져 있을 수 있고, 시작 또는 주기적 확인까지 오래된 상태로 남을 수 있다. 호스트가 돌아왔을 때 NIC에 도달하지 못할 수도 있다. 가져오기가 실패하거나, 체크섬이 어긋나거나, 변환이 멈출 수 있다. 이 설계의 장점은 이런 결과들이 더 이상 "호스트 테이블"이라는 하나의 덧없는 사실이 아니라는 점이다. 각각은 관찰 가능한 경계와 다음 행동을 갖는다.

DNS는 신선함의 단위를 바꾸었을 뿐, 그 존재 자체를 바꾸지 않았다

이름 지정 아키텍처는 이미 더 큰 전환에 접근하고 있었다. 1983년 11월에 발행된 RFC 881은 당시 거의 모든 인터넷 호스트가 NIC의 마스터 HOSTS.TXT에 기반한 어떤 형태의 테이블을 사용하고 있었다고 밝혔다. 이 계획은 도메인형 이름과 서비스가 도입되는 동안의 공존을 예상했다.

RFC 882는 확장 한계를 진단했다: 전역 테이블의 크기, 특히 갱신 빈도가 감당하기 어려워지고 있었다. 분산 데이터베이스를 요구했다. RFC 883은 이름 공간을 여러 서버에 나누고, 권위 있는 존 데이터를 캐시된 관측과 분리했다. 서버는 존 복사본을 주기적으로 새로 고쳤고, 캐시 데이터는 만료되었다. 이 명세는 마스터의 변경이 모든 복사본을 즉시 갱신하지 않고 분산 시스템을 통해 서서히 퍼진다는 점을 솔직히 밝혔다.

이후의 아키텍처를 RFC 849의 구현으로 거꾸로 읽어서는 안 된다. 두 문서는 크기가 다른 문제를 풀며, RFC 849의 제안은 표준이 아니었다. 연속성은 개념적인 것이다. 분산은 오래됨을 폐지하지 않는다. 오래됨에 명시적인 범위, 타이머, 버전, 갱신 절차, 복구 행동을 부여할 뿐이다.

운영 기록은 마지막으로 완료된 전환이다

지속되는 교훈은 "푸시가 낫다"도 "폴링이 안전하다"도 아니다. 각 메커니즘은 서로 다른 비용을 숨긴다. 푸시는 수신자가 도달 가능한 동안 빠르지만, 완전성을 위해 발신자가 수신자 상태를 유지해야 한다. 폴링은 수신자에게 복구 제어권을 주지만, 반복 확인과 지연된 발견이 시간을 소모한다. 버전 근거는 폴링을 저렴하게 만들고, 무결성 근거는 전송을 검사 가능하게 만들지만, 어느 쪽도 데이터를 활성화하지는 않는다.

권위 있는 레지스트리는 최신 수용 매핑을 서술할 수 있다. 그 서술만으로 꺼진 호스트를 갱신하거나, 파일을 로컬 데이터베이스로 변환하거나, 리졸버가 그것을 사용하게 만들 수는 없다. 이것들은 실행 중인 시스템이 수행하는 행위다.

RFC 849는 하나의 마스터 테이블과 분산 이름 지정 서비스 사이의 과도기에 놓인 인터넷을 포착했다. 두 페이지 안에서 더 큰 시스템이 종종 가리는 구분을 드러냈다: 게시는 원천에서의 사건이고, 신선함은 소비자 쪽에서 검증된 조건이다. 마스터 파일은 최신일 수 있다. 그래도 네트워크는 오래될 수 있다.

출처