요약
- NFS는 파일을 발견할 때는 경로명을 사용했지만, 이후 작업에는 불투명한 파일 핸들을 사용했습니다. 클라이언트는 핸들을 서버에 다시 전달할 수 있었지만, 그 바이트를 아이노드(inode), 디스크 주소 또는 이식 가능한 식별자로 취급할 수는 없었습니다.
- NFSv4는 핸들을 영속(persistent) 핸들과 휘발(volatile) 핸들로 나누었습니다. 영속 핸들은 객체의 수명 동안 재시작과 마이그레이션을 거쳐도 고정되어야 하며, 휘발 핸들은 서버가 공개하는 조건에 따라 만료될 수 있습니다.
NFS4ERR_STALE과NFS4ERR_FHEXPIRED는 서로 다른 사실을 보존합니다. 하나는 참조 대상이 사라졌거나 사용할 수 없다고 말하고, 다른 하나는 객체가 살아 있을 수 있음에도 임시 참조가 만료되었다고 말할 수 있습니다. 복구란 이름을 다시 해석하는 것이지, 오래된 바이트의 의미를 추측하는 것이 아닙니다.
이름이 옮겨진 파일
클라이언트가/projects/atlas/report를 해석하여 파일 핸들을 받고 읽기를 시작했다고 상상해 보십시오. 그런 다음 관리자가report를archive로 이름을 바꿉니다. 디렉터리 트리를 통과하는 경로는 바뀌었지만, 열려 있던 작업이 곧바로 다른 객체에 대한 작업이 될 필요는 없습니다. 하드 링크는 이 구분을 더욱 명확하게 합니다. 두 개의 경로명이 하나의 파일로 이어질 수 있습니다. 이름은 네임스페이스를 통과하는 경로이고, 파일 핸들은 서버가 발견한 대상을 가리키는 참조입니다.
이 구분은 초기 네트워크 파일 시스템에도 존재했습니다. 1989년 NFS 버전 2를 위해 발행된 RFC 1094는 경로명 탐색을 한 번에 한 구성 요소씩 수행하는 방식을 기술했습니다. 클라이언트는 별도의 마운트 프로토콜을 통해 초기 루트 핸들을 얻고, 디렉터리 핸들과 구성 요소 이름을LOOKUP에 보내 또 다른 핸들을 받았습니다.GETATTR,READ,WRITE같은 호출은 이후 전체 경로명 대신 핸들을 전달했습니다.
버전 2의 핸들은 정확히 32바이트였고 명시적으로 불투명(opaque)했습니다. "불투명"은 암호화되었거나 비밀이라는 뜻이 아니었습니다. 그것은 클라이언트가 그 값을 장치 번호, 아이노드, 테이블 슬롯 또는 저장 주소로 디코딩할 프로토콜상 권리가 없다는 뜻이었습니다. 참조가 어떻게 파일에 대응하는지는 오직 서버만 알아야 했습니다.
RFC 1813은 버전 3의 핸들을 가변 길이로 만들었지만 동일한 지식 배분은 유지했습니다.nfs_fh3은 개별 파일을 구별하기 위해 서버가 필요로 하는 모든 것을 담았습니다.LOOKUP,CREATE,READDIRPLUS같은 작업은 클라이언트가 캐시하고 이후 요청에 제시할 수 있는 핸들을 반환했습니다. 유선(wire) 계약은 경계를 기술했을 뿐, 서버 내부 파일시스템 표현을 고정하지 않았습니다.
해석 없는 동등성
불투명성은 유혹적인 지름길을 만듭니다. 클라이언트가 핸들을 들여다볼 수 없다면, 적어도 그 바이트를 비교할 수는 있지 않을까요? NFS는 그 비교를 허용하지만, 의도적으로 매우 좁은 의미만을 부여합니다.
같은 서버에서 받은 두 핸들에 대해, 동등함은 두 핸들이 같은 파일을 지정한다는 뜻입니다. 그러나 동등하지 않다고 해서 파일이 다르다는 것이 증명되지는 않습니다. 서버는 객체와 핸들 바이트 문자열 사이에 일대일 대응을 유지할 의무가 없습니다. 따라서 RFC 1813은 비교를 정확성 메커니즘이 아닌 성능 최적화로 규정합니다. 이후의 NFSv4 사양들도 이 규칙을 유지합니다. 하드 링크된 이름은 같은 핸들을 만들어야 하지만, 더 넓은 원칙은 그대로입니다. 클라이언트는 서버가 발행한 바이트를 역으로 해석하거나 과도하게 해석하여 자신만의 식별 체계를 만들 수 없습니다.
이 제한은 실질적인 힘을 가집니다. 캐시는 동일한 핸들을 보고 중복 작업을 피할 수 있습니다. 그러나 서로 다른 핸들로부터 두 쓰기가 반드시 서로 다른 내부 객체를 대상으로 한다고 추론해서는 안 됩니다. 또한 핸들을 마치 전역 콘텐츠 식별자처럼 임의의 서버 간에 비교할 수도 없습니다. 참조는 하나의 서버 식별 도메인 안에서만 존재합니다.
영속성이 명시적 약속이 되다
초기 버전에도 스테일 핸들 결과는 있었지만, NFSv4는 핸들의 수명을 계약의 더 구체화된 부분으로 만들었습니다. RFC 3010은 영속 핸들과 휘발 핸들을 구별했고, RFC 7530과 RFC 8881은 그 모델을 유지하며 정교화합니다.
영속 핸들은 객체의 수명 동안 고정되어야 합니다. 서버 재시작은 그것을 무효화하지 않습니다. NFSv4의 약속 하에서 객체가 다른 서버로 마이그레이션되는 것 역시, 클라이언트가 다른 프로토콜 식별자를 받아들이도록 요구하지 않습니다. 영속성 덕분에 클라이언트는 저장소가 어떻게 재배치되었는지 배우지 않고도 장애와 이동을 넘어 참조를 유지할 수 있었습니다.
영속이라고 불사인 것은 아닙니다. 객체가 삭제되거나 그 파일시스템을 사용할 수 없게 되면, 서버는NFS4ERR_STALE을 반환합니다. 이 실패는 영속성 계약의 예외가 아니라 그 일부입니다. 오래된 참조는 재사용된 내부 위치에 이후 들어선 무엇이든 조용히 자신을 붙이지 않습니다.
모든 객체에 대해 그 불변식을 지킬 수 없는 서버도 있습니다. 계층형 저장소, 마이그레이션 장비, 운영체제 인터페이스 또는 내부 테이블 설계는 연속성이 조건부인 참조를 발행할 수 있습니다. NFSv4는 이를 휘발 핸들이라 부르고, 서버가fh_expire_type을 통해 만료 속성을 보고하도록 합니다. 휘발성은 영속성이라는 허구 뒤에 숨겨지는 것이 아니라, 클라이언트가 복구를 계획할 수 있도록 노출됩니다.
표준은 휘발 핸들이 부팅 시각, 테이블 슬롯, 세대(generation) 번호를 담는 예시적 설계를 제시합니다. 재시작이나 슬롯 재사용 후에는 오래된 세대가 더 이상 일치하지 않습니다. 그 레이아웃은 단지 한 예입니다. 상호운용성 요구 사항은 보이는 동작이며, 내부 필드의 선택이 아닙니다.
스테일은 만료와 같지 않다
NFS4ERR_STALE과NFS4ERR_FHEXPIRED의 구분은 간결한 근거 설계의 한 조각입니다. 서버가 참조된 객체가 제거되었음을 알고 있다면 스테일을 반환합니다. 영속 참조는 그것이 식별하는 파일시스템을 더 이상 사용할 수 없을 때도 스테일이 될 수 있습니다. 서버는 오래된 참조가 더 이상 그 참조 대상에 도달하지 않는다고 말하는 것입니다.
만료 결과는 더 좁은 의미를 말합니다. 휘발 핸들은 연속성을 잃었지만, 그 아래의 객체는 여전히 존재할 수 있습니다. 재시작이 참조를 해석하던 테이블을 지웠을 수 있고, 세대가 바뀌었을 수 있으며, 마이그레이션이 핸들 유형이 살아남기를 약속하지 않은 경계를 넘었을 수 있습니다. 서버는 오래된 토큰을 이행할 수 없지만, 파일이 사라졌다고 주장할 필요는 없습니다.
이 결과들을 하나로 뭉뚱그리면 거짓 결론이 강제됩니다. 모든 만료를 삭제로 취급하면, 클라이언트는 실제로는 존재하는 데이터가 잃어버렸다고 보고할 수 있습니다. 모든 스테일 참조를 임시 토큰 문제로 취급하면, 클라이언트는 이미 제거된 객체를 상대로 영원히 재시도할 수 있습니다. 이 두 오류는 상위 계층이 불확실성이 발생하는 지점에서 그것을 보존하도록 해줍니다.
복구는 다시 이름에서 시작된다
NFSv4는 특수한 루트 핸들과 퍼블릭 핸들을 정의하여 별도 마운트 프로토콜에 대한 의존을 줄입니다.PUTROOTFH는 현재 루트를 확립하고, 이어지는LOOKUP작업이 네임스페이스를 따라 걸어갑니다. 이 원시 동작들은 클라이언트가 휘발 핸들이 만료된 후 어떻게 복구할 수 있는지도 보여줍니다.
견고한 클라이언트는 캐시된 핸들로 이어진 구성 요소 이름들을 보존합니다. 알려진 루트로 돌아가 구성 요소를 다시 따라가며 새 핸들을 얻을 수 있습니다. 그러나 이것은 만료된 바이트의 재구성이 아니라 새로운 관찰입니다. 다른 클라이언트가 그 객체의 이름을 바꿨을 수 있습니다. 파일이 삭제되었을 수도 있습니다. 오래된 이름이 이제 대체물을 지정하고 있을 수도 있습니다. 복구 코드는 객체와 오래된 식별자에 의존하던 상태를 모두 재검증해야 합니다.
이 한계는 상태를 변경하는 작업에서 특히 중요합니다. 클라이언트는 경로명을 다시 해석하는 것만으로 이전에 중단된 쓰기를 안전하게 재실행할 수 있다고 가정해서는 안 됩니다. 식별 연속성, 작업 재실행, 권한 부여는 별개의 문제입니다. NFS 서버는 작업에 대한 접근을 평가하며, 유효한 핸들을 보유하는 것 자체는 권한을 부여하지 않습니다.
따라서 이 역사적 기여는 마법적인 영구 식별자가 아닙니다. 그것은 규율 있는 책임 분할입니다. 서버는 대응 관계를 통제하고 그 연속성을 선언합니다. 프로토콜은 클라이언트가 필요로 하는 최소한의 근거 — 불투명성, 경계가 있는 동등성, 영속 속성, 진실된 실패 — 를 표준화합니다. 클라이언트는 복구에 충분한 네임스페이스 맥락을 저장하고, 확인 없이 오래된 상태를 새로 해석된 객체에 붙이기를 거부합니다.
객체가 유지되는 동안 경로는 바뀔 수 있습니다. 핸들이 만료되는 동안 객체는 유지될 수 있습니다. 작업이 금지되는 동안 핸들은 유효할 수 있습니다. NFS는 이 명제들을 분리해 놓음으로써 더 안전해졌습니다.
출처
회원 브리핑
프로필 심층 컨텍스트
올바른 멤버십 등급으로 로그인하면 전체 브리핑과 출처 노트를 볼 수 있습니다.
Strategic Circle 전용
Strategic Circle
모든 독자에게 공개됩니다. 가입 후 로그인하면 프로필 브리핑를 열람할 수 있습니다.
Strategic Circle 가입하기Leadership Alliance 전용
Leadership Alliance
자격을 갖춘 IP 자산 소유자 및 운영진을 위한 콘텐츠입니다. 로그인하면 Leadership Alliance 브리핑을 열람할 수 있습니다.
Leadership Alliance 가입하기





