GN⁺: Windows NT vs. Unix: 설계 비교
(blogsystem5.substack.com)- NT는 종종 "매우 진보된" 운영 체제로 평가받았지만 그 이유를 잘 몰랐음
- 2023년 말, 'Inside Windows NT' 1판을 읽고 NT와 Unix를 비교하기로 함
- NT(1993년 7월)와 당시 Unix 시스템(4.4BSD, 리눅스 1.0)의 설계를 비교한 것임
- Unix 전문가로서 NT는 잘 모르기에 NT의 차이점 위주로 서술함
- NT가 Unix보다 나은 점이 무엇인지, 그리고 여전히 그런지에 대한 질문을 다룸
미션
- Unix의 역사는 NT보다 훨씬 오래됨
- Unix 개발은 1969년에 시작되었고 주요 목표는 프로그래머에게 편리한 플랫폼이 되는 것이었음
- Unix는 Multics에서 영감을 받았지만, 단순성에 초점을 맞춰 Multics를 능가함
- 이식성과 멀티태스킹은 Unix 설계의 원래 목표는 아니었음: 이러한 기능은 몇 년 후 Unix의 많은 "포크"와 재발명에서 추가됨
- Microsoft의 역사
- MS-DOS의 첫 번째 릴리스는 1981년 8월에 출시되었고, "레거시 Windows"(DOS 기반 버전)의 첫 번째 릴리스는 1985년 11월에 출시됨
- MS-DOS는 널리 성공했지만, Windows가 진정으로 중요해진 것은 1990년 5월 Windows 3.0부터였음
- Windows NT는 1989년에 구상되었고 1993년 7월 NT 3.1 릴리스로 세상에 모습을 드러냄
- Microsoft의 이점
- NT의 설계는 Unix보다 20년 늦게 시작되어 Microsoft에 이점을 줌
- Microsoft는 이미 MS-DOS와 레거시 Windows 덕분에 큰 사용자 기반을 확보하고 있었음
- NT를 설계한 Microsoft 팀은 이러한 개발의 통찰력, 다른 운영 체제 개발 경험, 최신 기술에 대한 접근성을 가지고 있어 NT 제작에서 "달을 향해 쏘기"를 할 수 있었음
커널
- Unix는 Minix나 GNU Hurd와 같은 몇 가지 예외를 제외하고 모놀리식 커널로 구현되어 운영 체제가 제공하는 기능과 상호 작용하기 위한 시스템 호출 모음을 노출함
- 반면 NT는 모놀리식 커널과 마이크로커널의 중간 형태임: 특권 구성 요소인 executive는 사용자 공간 subsystems에 모듈식 구성 요소 모음으로 자신을 표현함
- 사용자 공간 subsystems는 애플리케이션이 사용하는 API(POSIX, OS/2 등)를 executive 시스템 호출로 "변환"하는 특수한 프로세스임
- NT executive의 중요한 부분 중 하나는 HAL로, 머신의 하드웨어에 액세스하기 위한 추상 기본 요소를 제공하고 커널의 나머지 부분에 대한 기반으로 작용함
- 이 계층은 NT가 i386, Alpha, PowerPC를 포함한 다양한 아키텍처에서 실행될 수 있게 하는 핵심임
- 당시 Unix는 특정 아키텍처에 결합되어 있었음: Unix 개념은 이식 가능했지만 구현은 그렇지 않았음
- SunOS는 원래 Motorola 68000만 지원했고, 386BSD는 Intel 아키텍처로의 BSD 첫 포팅이었으며, IRIX는 Silicon Graphic의 MIPS 기반 워크스테이션용 Unix 변종이었음
- NT executive의 또 다른 중요한 부분은 멀티프로세싱 시스템 및 선점형 커널에 대한 지원임
- 커널에는 무엇이 다른 것을 중단할 수 있는지 결정하기 위한 다양한 인터럽트 수준(BSD 용어로 SPL)이 있지만, 더 중요한 것은 커널 스레드가 다른 커널 스레드에 의해 선점될 수 있다는 점임
- 이는 오늘날 모든 고성능 Unix 시스템이 하는 것이지만 많은 Unix가 시작한 방식은 아님
- 이러한 시스템은 선점이나 멀티프로세싱을 지원하지 않는 커널로 시작하여 사용자 공간 멀티프로세싱 지원을 추가한 다음 커널 선점을 추가함
- 마지막 단계가 가장 어려운 단계이며 FreeBSD 5.0 사가 난관을 설명함
- 따라서 NT가 처음부터 올바른 기반으로 시작한 것은 흥미로움
객체
- NT는 객체 지향 커널임
- Unix도 그렇다고 생각할 수 있음: 프로세스는 struct로 정의되고 파일 시스템 구현은 vnode("가상 노드", inode와 혼동하지 말 것)를 다룸
- 그러나 이는 NT가 하는 것과 정확히 같지 않음: NT는 이러한 모든 다른 객체가 시스템에서 공통 표현을 갖도록 강제함
- 프로세스와 파일 핸들과 같은 이질적인 것들에 대해 의미 있는 추상화를 어떻게 제공할 수 있는지 의심할 수 있음
- 실제로는 불가능하지만 NT는 이들 모두가 공통 객체 유형에서 상속되도록 강제했고, 놀랍게도 이는 몇 가지 좋은 특성을 가짐
-
중앙 집중식 액세스 제어
- 객체는 object manager 에 의해서만 생성되므로 정책을 시행할 코드의 단일 위치가 있음
- 권한 검사와 같은 의미론은 한 위치에서만 정의되고 시스템 전체에 균일하게 적용될 수 있어 강력함
- NetBSD도 이것이 좋은 아이디어라고 결론지었지만 2001년이 되어서야 Kernel Authorization(kauth) 프레임워크를 얻음
-
공통 ID
- 객체에는 ID가 있고 모두 단일 트리로 표현됨
- 이는 프로세스, 파일 핸들 또는 파이프에 관계없이 모든 객체에 대해 고유한 네임스페이스가 있음을 의미함
- 트리의 객체는 이름(경로)으로 주소 지정 가능하며 트리의 다른 부분은 다른 하위 시스템이 소유할 수 있음
- 예를 들어 트리의 일부는 마운트된 파일 시스템을 나타낼 수 있으며, 따라서 해당 하위 트리의 루트 노드를 탐색하면 파일 시스템이 경로의 나머지 부분을 해결하게 됨
- 이는 Unix 시스템의 VFS 계층과 유사하지만, VFS는 파일 시스템에 대해서만 다루는 반면 객체 트리는 모든 단일 커널 객체에 대해 다룸
- Unix는
/proc/
,/sys/
등을 통해 비파일 객체 유형을 파일 시스템에 끼워 넣으려고 시도했지만, 이는 NT가 제공하는 것에 비해 사후 처리로 느껴짐
-
통합 이벤트 처리
- 모든 객체 유형에는 signaled 상태가 있으며, 그 의미는 각 객체 유형에 따라 다름
- 예를 들어 프로세스 객체는 프로세스가 종료될 때 signaled 상태로 전환되고, 파일 핸들 객체는 I/O 요청이 완료될 때 signaled 상태로 전환됨
- 이는 단일 wait 스타일 시스템 호출이 객체 그룹이 상태를 변경하기를 기다릴 수 있으므로 사용자 공간에서 이벤트 기반 코드(async 코드)를 작성하는 것이 매우 쉬워짐
- Unix 시스템에서 I/O 및 프로세스 완료를 동시에 기다리는 것은 고통스러움
- 객체는 NT 고유의 구성 요소이며 NT가 지원하려는 모든 API에 잘 일반화되지 않음
- 예를 들어 POSIX 하위 시스템: POSIX에는 NT와 같은 객체 개념이 없지만 NT는 POSIX 애플리케이션과 어떤 종류의 호환성을 제공해야 함
- 이러한 이유로 POSIX 하위 시스템이 executive에서 객체를 할당하는 동안 해당 POSIX 엔터티를 나타내기 위해 자체 장부 기록을 유지하고 즉시 두 엔터티 간의 논리적 변환을 수행해야 함
- 반면 Win32 하위 시스템은 중개자 없이 클라이언트에 객체를 전달함
프로세스
- 프로세스는 NT와 Unix의 공통된 개체이지만 완전히 동일하지는 않음
- Unix에서는 프로세스가 트리로 표현되어 각 프로세스에는 부모가 있고 프로세스는 0개 이상의 자식을 가질 수 있음
- 그러나 NT에는 그러한 관계가 없음: 프로세스는 생성자로부터 리소스를 "상속"할 수 있지만 생성된 후에는 독립적인 엔터티임
- NT가 설계되었을 당시 스레드는 흔하지 않았음:
- Mach는 1985년에 스레드를 통합한 최초의 Unix 유사 커널이었음
- 이는 다른 Unix가 이 개념을 나중에 채택하고 기존 설계에 맞게 수정해야 했음을 의미함
- Linux는 1996년 6월 2.0 릴리스에서 스레드를 각각 고유한 PID를 가진 프로세스로 표현하기로 선택했고, NetBSD는 2004년 2.0 릴리스까지 프로세스와 별개의 엔터티로 표현되는 스레드를 얻지 못함
- Unix와 달리 NT는 SMP 머신에서 고성능 컴퓨팅을 위해 스레드가 필수적임을 알고 처음부터 스레드를 지원하기로 선택함
- NT에는 전통적인 Unix 의미의 시그널이 없음
- 대신 alerts 가 있으며 이는 커널 모드와 사용자 모드가 될 수 있음
- 사용자 모드 알림은 다른 객체와 마찬가지로 기다려야 하며 커널 모드 알림은 프로세스에 보이지 않음
- POSIX 하위 시스템은 커널 모드 알림을 사용하여 시그널을 에뮬레이트함
- 시그널은 프로세스 실행을 방해하는 방식 때문에 Unix에서 종종 사마귀라고 불렸음: 시그널을 올바르게 처리하는 것은 정말 어려운 노력이므로 NT의 대안이 더 우아한 것 같음
- NT에서 최근에 흥미로운 개발은 피코프로세스의 도입이었음
- 이 기능이 추가될 때까지 NT의 프로세스는 상당히 무거웠음: 새 프로세스는 시작 시 주소 공간에 매핑된 NT 런타임 라이브러리 묶음을 얻음
- 피코프로세스에서 프로세스는 Windows 아키텍처와 최소한의 연관이 있으며, 이는 WSL 1에서 Linux 호환 프로세스를 구현하는 데 사용됨
- 어떤 면에서 피코프로세스는 기본 Windows 프로세스보다 Unix 프로세스에 더 가깝지만 WSL 2로의 이동으로 인해 2016년 8월부터 존재했음에도 불구하고 더 이상 많이 사용되지 않음
- Windows의 보안 문제를 비난하는 만큼, NT는 시스템이 기본적으로 기능 기반 시스템으로 작동한다는 점에서 초기 인터넷 표준에 대한 고급 보안 설계로 시작함
- 로그온 후 시작되는 첫 번째 사용자 프로세스는 사용자 세션의 권한을 나타내는 커널로부터 액세스 토큰을 받으며, 프로세스와 하위 프로세스는 권한을 주장하기 위해 이 토큰을 커널에 제공해야 함
- 이는 프로세스가 단순히 식별자를 가지고 있고 커널이 프로세스 테이블에서 각 프로세스가 무엇을 할 수 있는지 추적해야 하는 Unix와 다름
호환성
- NT의 주요 목표는 레거시 Windows, DOS, OS/2 및 POSIX용으로 작성된 애플리케이션과 호환되는 것이었음
- 이에 대한 한 가지 이유는 기술적인 것으로, 이로 인해 시스템이 우아한 설계를 갖도록 강제되었음
- 다른 이유는 정치적인 것으로, NT는 IBM과 공동 개발되었고 NT는 결국 Windows가 되었음에도 불구하고 OS/2 애플리케이션을 반드시 지원해야 했음
- 이러한 호환성에 대한 필요성으로 인해 NT의 설계는 Unix와 크게 달라졌음
- Unix에서는 사용자 공간 애플리케이션이 시스템 호출 인터페이스를 통해 커널과 직접 통신하며, 이 인터페이스가 Unix 인터페이스임
- C 라이브러리는 커널을 호출하기 위한 접착제를 제공하고 애플리케이션은 직접 시스템 호출을 실행하지 않지만 이는 사소한 세부 사항임
- NT에서는 애플리케이션이 executive(커널)와 직접 통신하지 않음
- 대신 각 애플리케이션은 특정 보호된 하위 시스템과 통신하며, 이러한 하위 시스템은 NT가 호환되기를 원하는 다양한 운영 체제의 API를 구현함
- 이러한 하위 시스템은 사용자 공간 서버로 구현됨(NT "마이크로커널" 내부에 없음)
- Windows 애플리케이션에 대한 지원은 Win32 서버에서 제공하며, 이는 사용자가 직접 볼 수 있는 유일한 서버이기 때문에 특별함: 콘솔 프로그램과 DOS 터미널을 제어하며 성능상의 이유로 특정 권한을 가짐
- 전통적인 Unix와 비교할 때 BSD와 Linux는 모놀리식 커널을 가지고 있기 때문에 NT의 설계는 매우 다름
- 이러한 커널은 사용자 공간 애플리케이션이 시스템과 직접 상호 작용하기 위해 활용하는 시스템 호출 인터페이스를 노출함
- 그러나 BSD는 모놀리식 커널 내에서 오랫동안 대체 바이너리 실행을 지원해 왔음: 이는 실행 중인 바이너리에 따라 사용자 공간에 다른 시스템 호출 테이블을 노출한 다음 해당 "외부" 시스템 호출을 커널이 이해하는 것으로 변환하는 방식으로 작동함
- Linux는 personalities 를 통해 이에 대한 제한된 지원도 제공함
- BSD 접근 방식이 NT가 다른 시스템을 지원하는 방식과 매우 다르지만 WSL 1은 매우 유사하며 원래 정의된 용어로 하위 시스템이 아님
- WSL 1에서 NT 커널은 Linux 프로세스를 피코프로세스로 표시하고 거기에서 다른 시스템 호출 인터페이스를 노출함
- NT 커널 내에서 해당 Linux 관련 시스템 호출은 NT 작업으로 변환되어 BSD의 Linux 호환성과 마찬가지로 동일한 커널 내에서 제공됨
- 유일한 문제는 NT가 Unix가 아니기 때문에 Linux "에뮬레이션"이 까다롭고 BSD가 제공할 수 있는 것보다 훨씬 느리다는 것임
- WSL 2가 이 설계의 본질을 잃고 완전한 VM 설계로 갔다는 것은 유감임
- NT 설계의 흥미로운 세부 사항
- NT 설계의 목표는 단일 셸에서 하위 시스템 간의 원활한 I/O 리디렉션을 허용하는 것이었음
- 하위 시스템은 포트를 통해 애플리케이션에 노출되며, 이는 NT 객체이고 Mach가 프로세스와 서버가 통신하는 방식과 유사함
가상 메모리
- NT는 Unix와 마찬가지로 모두 페이징이 있는 Memory Management Unit(MMU)에 의존하여 프로세스 간 보호를 제공하고 가상 메모리를 제공함
- 사용자 공간 프로세스의 페이징은 머신의 물리적 메모리 양보다 더 큰 주소 공간을 제공하는 일반적인 메커니즘임
- 그러나 NT를 당대의 Unix 시스템보다 앞서게 한 한 가지는 커널 자체도 디스크로 페이징 아웃될 수 있다는 것임
- 커널 전체가 페이징 가능하다면 페이징 아웃된 파일 시스템 드라이버의 코드가 필요한 커널 페이지 폴트를 해결하는 상황에 처하게 되겠지만, 커널의 상당 부분은 페이징 가능함
- 요즘에는 커널이 머신에 설치된 일반적인 메모리에 비해 작기 때문에 특별히 흥미롭지는 않지만 과거에는 모든 바이트가 소중했기 때문에 큰 차이를 만들었음
- 요즘 우리가 가상 메모리와 페이징이 작동하는 방식을 당연하게 여기지만, 이는 NT가 설계되었을 때 큰 연구 분야였음
- 이전의 Unix 구현에는 파일 시스템과 가상 메모리에 대한 별도의 메모리 캐시가 있었고, SunOS가 이전 설계의 오버헤드를 줄이기 위해 통합 가상 메모리 아키텍처를 구현한 것은 1987년이 되어서였음
- 반면 NT는 처음부터 통합 메모리 아키텍처로 시작했음
- Unix에서 발견된 비효율성에 대한 통찰력이 있었고 NT 설계가 시작되기 전에 SunOS가 구현한 솔루션을 볼 수 있었기 때문에 이를 수행하기 쉬웠다고 말할 수 있음
- 그러나 이는 NT를 당시 다른 많은 운영 체제보다 "더 발전"시켰으며, NetBSD 1.6의 Unified Buffer Cache(UBC) 구현으로 2002년까지 다른 시스템이 따라잡지 못했음을 주목해야 함
- NT와 Unix의 흥미로운 차이점은 공유 메모리를 관리하고 표현하는 방식임
- NT에서 공유 메모리 섹션은 객체이므로 다른 모든 객체와 정확히 동일한 액세스 유효성 검사를 받음
- 또한 단일 객체 트리의 일부이므로 다른 모든 객체와 동일한 방식으로 주소 지정할 수 있음
- Unix에서는 이 기능이 볼트로 고정되어 있음: 공유 메모리 객체는 다른 네임스페이스, 다른 모든 엔터티에 대한 다른 API를 가지므로 일반적인 권한이 적용되지 않음
I/O 서브시스템
- 초기 버전의 Unix는 하나의 파일 시스템만 지원했음
- 예를 들어 BSD가 UFS 이상을 지원하기 위해 Virtual File System(VFS) 추상화를 얻은 것은 1990년 4.3BSD까지 이르렀음
- 반면 NT는 여러 파일 시스템을 허용하는 설계로 시작했음
- 여러 파일 시스템을 지원하기 위해 커널은 어떤 식으로든 해당 네임스페이스를 노출해야 함
- Unix는 마운트 포인트를 통해 단일 파일 계층 구조에서 파일 시스템을 결합함: VFS 계층은 파일 시스템의 루트에 해당하는 노드를 식별하고 경로를 탐색할 때 해당 파일 시스템 드라이버에 요청을 리디렉션하는 메커니즘을 제공함
- NT는 표준 사용자 인터페이스에서 파일 시스템이 분리된 드라이브로 나타나더라도 유사한 설계를 가지고 있음: 내부적으로 executive는 파일 시스템을 객체 트리의 객체로 표현하고 각 객체는 경로의 나머지 부분을 구문 분석할 책임이 있음
- 해당 파일 시스템 객체는 사용자 공간에서 액세스할 수 있도록 DOS 드라이브로 다시 매핑됨
- DOS 드라이브도 참조하는 파일 시스템으로 I/O를 리디렉션하는 별도의 하위 트리 아래에 있는 객체임
- NT는 결국 NTFS와 함께 출시되었음
- NTFS는 성능이 좋지 않다는 이유로 비난받는 것을 좋아하더라도(잘못된 주장) 당시로서는 정말 발전된 파일 시스템이었음
- NT의 I/O 하위 시스템은 NTFS와 결합하여 64비트 주소 지정, 저널링, 심지어 유니코드 파일 이름을 제공했음
- Linux는 1990년대 후반까지 64비트 파일 지원을 받지 못했고 2001년 ext3가 출시될 때까지 저널링을 받지 못했음
- 대체 내결함성 메커니즘인 Soft updates는 1998년까지 FreeBSD에 나타나지 않았음
- Unix는 파일 이름을 유니코드가 아닌 null 종료 바이트 배열로 나타냄
- NT 출시 시 포함된 다른 기능으로는 디스크 스트리핑과 미러링(오늘날 RAID로 알려짐) 및 장치 핫 플러깅이 있음
- SunOS가 1990년대 초반부터 RAID 지원을 포함했기 때문에 이러한 기능은 새로운 것은 아니었지만, 흥미로운 점은 이들이 모두 원래 설계의 일부로 고려되었다는 것임
- 더 높은 수준에서 NT의 I/O 하위 시스템을 Unix보다 훨씬 더 발전시키는 것은 그 인터페이스가 본질적으로 비동기라는 사실이며 처음부터 그랬다는 것임
- 이를 관점에 두기 위해 FreeBSD는 1998년 FreeBSD 3.0까지 aio(7)에 대한 지원을 보지 못했고 Linux는 2002년 Linux 2.5까지 이를 보지 못했음
- 비동기 I/O에 대한 지원이 20년 이상 Unix 시스템에 존재했음에도 불구하고 여전히 널리 사용되지 않음: 이러한 API를 아는 사람은 거의 없고, 대다수의 애플리케이션은 이를 사용하지 않으며, 성능이 좋지 않음
- Linux의 io_uring은 비동기 I/O를 개선하는 비교적 최근 추가 기능이지만 보안 취약점의 주요 원인이었으며 널리 사용되지 않음
네트워킹
- 오늘날 인터넷은 어디에나 있지만 NT가 설계되었을 때는 그렇지 않았음
- Microsoft 생태계를 돌아보면 DOS 3.1(1987)은 FAT 파일 시스템에서 파일 공유를 위한 기반을 포함했지만 "OS" 자체는 네트워킹 기능을 제공하지 않았음: Microsoft Networks(MS-NET)라는 별도의 제품이 이를 수행했음
- Windows 3.0(1990)은 로컬 네트워크에서 기본적인 프린터 및 파일 공유를 허용하는 NetBIOS에 대한 지원을 포함했지만 TCP/IP에 대한 지원은 찾아볼 수 없었음
- 반면 Unix는 인터넷 그 자체였음: 모든 기본 인터넷 프로토콜은 Unix로 그리고 Unix와 함께 작성되었음
- NT 설계 중에는 우수한 네트워크 지원을 고려하는 것이 중요했으며 실제로 NT는 네트워킹 기능과 함께 출시되었음
- 그 결과 NT는 인터넷 프로토콜과 기존 Microsoft 환경에서 사용되는 전통적인 LAN 프로토콜을 모두 지원했으며, 이는 기업 환경에서 Unix보다 NT를 앞서게 했음
- 예를 들어 NT의 네트워크 도메인을 들 수 있음
- Unix에서 네트워크 관리자는 일반적으로 수동으로 머신 간에 사용자 계정을 동기화했음
- SunOS와 같은 시스템이 구현한 X.500 디렉터리 프로토콜(1988)과 Kerberos(1980년대)를 사용자 인증에 사용했을 수 있지만 이러한 기술은 특별히 간단하지 않았음
- 대신 NT는 시작부터 디렉터리 및 인증 기능을 통합한 도메인을 제공했으며, 이는 설정이 훨씬 쉽고 시스템에 내장되어 있기 때문에 회사 네트워크에서 "승리"한 것으로 보임
- 동기화된 사용자 계정의 목표는 머신 간에 리소스, 주로 파일을 공유하는 것이며, 이렇게 할 때 권한을 나타내는 방법이 중요함
- 오랜 시간 동안 Unix는 각 파일에 대해 단순한 읽기/쓰기/실행 권한 집합만 제공했음
- 반면 NT는 처음부터 고급 ACL과 함께 제공되었는데, 이는 여전히 Unix에서 아픈 점임
- Linux와 BSD에도 이제 ACL이 있지만 시스템 간 인터페이스가 일관되지 않고 시스템 설계에 이질적인 추가 기능처럼 느껴짐
- NT에서 ACL은 객체 수준에서 작동하므로 모든 커널 기능에 일관되게 적용됨
- 파일 공유에 대해 이야기할 때 네트워크 파일 시스템에 대해 이야기해야 함
- Unix에서 사실상 파일 시스템은 NFS였고 NT에서는 SMB였음
- SMB는 MS-NET 및 LAN Manager에서 상속되었으며 리디렉터라는 구성 요소를 통해 커널에 구현됨
- 본질적으로 리디렉터는 NFS가 Unix에 있는 것처럼 파일 작업을 트랩하고 네트워크를 통해 전송하는 "단순한" 또 다른 파일 시스템임
- protobuf와 gRPC가 널리 사용되어 새로운 아이디어처럼 보일 수 있지만 오래된 아이디어에 기반을 두고 있음
- Unix에서는 주로 NFS를 지원하기 위해 1980년대 초반부터 Sun RPC를 사용했음
- 마찬가지로 NT는 자체 DSL(인터페이스 정의를 지정하고 원격 프로시저에 대한 코드를 생성하기 위해 MIDL로 알려짐)과 RPC 클라이언트 및 서버를 구현하기 위한 자체 기능을 통해 내장 RPC 지원과 함께 제공되었음
- Unix 시스템은 임의의 드라이버 지원에 크게 주력하지 않았음: Unix 시스템은 일반적으로 특정 머신 및 공급업체와 결합되어 있었음
- 반면 NT는 "모든" 머신을 위한 OS가 되려고 했으며 소프트웨어 회사에서 판매되었으므로 다른 사람이 작성한 드라이버 지원이 중요했음
- 그 결과 NT에는 Network Driver Interface Specification(NDIS)이 제공되었는데, 이는 네트워크 카드 드라이버를 쉽게 지원하기 위한 추상화임
- 오늘날까지 제조업체에서 제공하는 드라이버는 Linux에서 그렇게 흔한 일이 아니며, 이로 인해 2000년대 초반에 Linux에서 WiFi 카드용 Windows 드라이버를 재사용할 수 있는 매우 인기 있는 셈인 ndiswrapper와 같은 흥미로운 장치가 생겨남
- 마지막으로 NT와 Unix의 또 다른 차이점은 명명된 파이프의 구현에 있음
- 명명된 파이프는 Unix에서 로컬 구성 요소임: 동일한 머신에 있는 두 프로세스가 디스크에 지속적인 파일 이름으로 서로 통신할 수 있는 메커니즘을 제공함
- NT에는 이와 동일한 기능이 있지만 명명된 파이프가 네트워크를 통해 작동할 수 있음
- 공유 파일 시스템에 명명된 파이프를 배치하면 서로 다른 컴퓨터의 두 애플리케이션이 네트워킹 세부 정보를 걱정하지 않고도 서로 통신할 수 있음
User-Space
- Configuration:
- NT는 레지스트리라는 데이터베이스에서 시스템 및 애플리케이션 구성을 중앙 집중화하여 레거시 Windows에서 사용되는 오래된 CONFIG.SYS, AUTOEXEC.BAT 및 수많은 INI 파일에서 벗어났음
- 이는 일부 사람들을 매우 화나게 만들었지만 결국 통합 구성 인터페이스는 모두에게 유익함: 지원할 단일 기반이 있기 때문에 애플리케이션을 작성하기가 더 쉬워지고 살펴볼 곳이 하나뿐이기 때문에 사용자가 시스템을 더 쉽게 조정할 수 있음
- 반면 Unix는 여전히 수십 개의 DSL과 일관성 없는 파일 위치로 인해 어려움을 겪고 있음
- 구성 파일을 지원하는 각 프로그램에는 자체 구문이 있으며, 프로그램이 읽는 위치를 아는 것은 어렵고 항상 잘 문서화되지는 않음
- Linux 생태계는 XDG 및 dconf(이전에는 GConf)를 통해 NT와 유사한 접근 방식을 추진했지만 데스크톱 구성 요소는 이러한 기술을 독점적으로 사용하는 반면 시스템의 기본 구성 요소는 이를 채택하지 않아 일관성 없는 엉망진창을 남김
- Internationalization:
- Microsoft는 이미 전 세계에 Windows 3.x를 출시하고 있는 대기업으로서 지역화가 중요하다는 것을 이해하고 NT가 처음부터 이러한 기능을 지원하도록 만들었음
- 이를 UTF 지원이 1990년대 후반까지 나타나기 시작하지 않았고 선택적 gettext 추가 기능을 통해 다른 언어를 지원한 Unix와 대조해 볼 것
- C 언어:
- FreeBSD 및 NetBSD와 같은 Unix 시스템이 한동안 꿈꿔 온 한 가지는 더 안전한 방식으로 커널을 구현하기 위해 자체 C 방언을 고안하는 것임
- 이는 GCC 전용 확장에 의존하는 Linux를 제외하고는 어디에도 가지 않았음
- 반면 Microsoft는 C 컴파일러를 소유하는 특권을 가지고 있었으므로 Microsoft C로 작성된 NT에서 이를 수행했음
- 예를 들어 NT는 소프트웨어 및 하드웨어 예외를 처리하기 위해 try/except 절을 추가하는 기능인 Structured Exception Handling(SEH)에 의존함
- 이것이 큰 장점이라고는 말하지 않겠지만 실제로 차이점임
결론
- NT는 출시 당시 획기적인 기술이었음
- 위에서 설명했듯이 오늘날 시스템 설계에서 당연하게 여기는 많은 기능이 NT에는 처음부터 존재했지만, 거의 모든 다른 Unix 시스템은 시간이 지남에 따라 그러한 기능을 천천히 얻어야 했음
- 그 결과 이러한 기능은 Unix 철학과 항상 원활하게 통합되지는 않음
- 그러나 오늘날 NT가 Linux나 FreeBSD보다 진정으로 "더 발전했는지"는 분명하지 않음
- NT는 시작부터 더 견고한 설계 원칙과 동시대의 운영 체제보다 더 많은 기능을 가지고 있었지만, 요즘에는 차이가 모호함
- 즉, NT는 발전했지만 현대 Unix만큼 상당히 더 발전하지는 않았음
- NT에 이러한 모든 견고한 설계 원칙이 있음에도 불구하고 UI의 비대화로 인해 설계가 빛을 발하지 못한다는 점이 실망스러움
- 초강력 머신에서도 OS의 느린 속도는 목격하기 고통스러울 수 있으며 심지어 이 OS의 종말로 이어질 수도 있음
GN⁺의 정리
- 이 글은 NT와 Unix의 설계 차이를 비교하여 NT의 초기 설계가 얼마나 진보적이었는지를 설명함
- NT는 처음부터 이식성, 다중 처리 지원, 호환성을 목표로 설계되었으며, 이는 Unix와의 주요 차이점임
- NT의 객체 지향 커널, 통합 메모리 아키텍처, 비동기 I/O 인터페이스 등은 Unix보다 더 진보된 기능을 제공함
- 그러나 오늘날 NT와 Unix 시스템 간의 차이는 크지 않으며, NT의 UI 비대함이 성능 저하를 초래함
Hacker News 의견
-
NT 커널은 훌륭하지만 오래된 설계임
- Windows OS는 NT 커널 위에 많은 구식 요소가 쌓여 있어 문제 발생
- Microsoft는 Win32와 MS-DOS 패러다임에서 벗어나 NT 기반의 새로운 OS 설계를 고려해야 함
-
NT와 Unix의 가장 큰 차이점은 드라이버 접근 방식임
- NT는 Windows 3.x/95/98의 드라이버 문제를 해결하기 위해 설계됨
- Unix는 드라이버를 고신뢰성 구성 요소로 간주하며 커널 개발자가 작성함
-
현대 WinNT에서는 Direct3D가 커널의 필수 부분임
- D3D11은 GPU 없이도 사용 가능하며, WARP라는 소프트웨어 대체 기능 제공
- Linux에는 이와 유사한 기능이 부족함
-
NT 커널은 프로세스가 아닌 스레드를 실행함
- 스레드는 몇 밀리초 내에 생성 가능하며, 프로세스는 무겁게 작동함
- NT의 역사는 VMS의 기본 원칙에 뿌리를 두고 있음
-
WindowsNT는 초기에는 Linux보다 훨씬 더 잘 설계된 시스템이었음
- NT는 Win32, OS/2, POSIX를 실행할 수 있었음
- POSIX는 미국 정부의 대형 소프트웨어 계약을 위해 추가되었으나, 이후 관심을 잃음
-
NT는 세 번째 시스템으로서 두 번째 시스템 증후군을 피함
- OS/2는 기술적으로 잘못된 문제를 해결했으며, 조직적으로도 실패함
- NT는 Windows XP까지 널리 사용되지 않았음
-
개발자 관점에서 Windows와 Linux의 차이점이 있음
- 명령줄과 글로빙 방식에서 Windows가 더 우수함
- Win32의 wchar_t 사용은 문제임
-
NT 커널은 우아함을 가지고 있지만, 오픈 소스가 아님
- 다른 사용자 공간과 데스크탑 환경을 가진 Windows는 흥미로울 것임
-
Linux의 FUSE와 같은 융합이 있었음
- Win NT의 파일 시스템 접근 방식은 많은 파일 시스템 작업을 매우 느리게 만듦
- Microsoft는 WSL1을 포기하고, SQLLite나 ZIP 파일 같은 컨테이너를 사용함