나는 리눅스 커널 메일링 리스트 에티켓의 맥락에서 이에 대해 생각하기 시작했습니다. 세계에서 가장 유명하고 가장 성공적이고 중요한 무료 소프트웨어 프로젝트인 Linux 커널은 광범위한 관심을 받아왔습니다. 이 프로젝트의 창립자이자 리더인 리누스 토발즈(Linus Torvalds)에 대해서는 여기서 소개할 필요가 없을 것입니다.
Linus는 때때로 LKML에 대한 자신의 발언으로 논란을 일으키곤 합니다. 그 자신이 인정한 바에 따르면 이러한 불꽃은 종종 사용자 공간을 파괴하는 것과 관련이 있습니다. 이것은 내 질문으로 이어집니다.
사용자 공간을 파괴하는 것이 왜 나쁜 것인지에 대한 역사적 관점을 얻을 수 있습니까? 내가 아는 바로는 사용자 공간을 깨뜨리려면 애플리케이션 수준에서 수정이 필요하지만 커널 코드가 개선된다면 그게 나쁜 걸까요?
내가 이해한 바로는 Linus가 명시한 정책은 무엇보다도 코드 품질을 포함하여 사용자 공간을 파괴하지 않는 것입니다. 이것이 왜 그렇게 중요합니까? 이 정책의 장점과 단점은 무엇입니까?
(분명히 그러한 정책을 지속적으로 적용하는 데는 몇 가지 단점이 있습니다. Lynas는 이 주제에 대해 LKML의 최고 책임자와 때때로 "동의하지 않음"을 겪었기 때문입니다. 제가 아는 한, 그는 항상 이 문제에 대해 자신만의 길을 갔습니다. ).
답변1
그 이유는 역사적이 아니라 실제적입니다. Linux 커널 위에서 실행되는 수많은 프로그램이 있습니다. 커널 인터페이스가 이러한 프로그램을 손상시키는 경우 모든 사람이 해당 프로그램을 업그레이드해야 합니다.
이제 대부분의 프로그램이 실제로 커널 인터페이스(시스템 호출), 그러나 인터페이스에만 해당C 표준 라이브러리(씨포장지시스템 호출 주변). 아, 그런데 어떤 표준 라이브러리인가요? 글립케? uClibC? 푸드 라이브러리? 바이오닉? 무실? 등.
그러나 운영 체제별 서비스를 구현하고 표준 라이브러리에 의해 노출되지 않는 커널 인터페이스에 의존하는 프로그램도 많이 있습니다. (Linux에서는 이들 중 다수가 다음을 통해 수행됩니다./proc
그리고/sys
.)
그런 다음 정적으로 컴파일된 바이너리가 있습니다. 커널 업그레이드로 인해 그 중 하나가 중단된 경우 유일한 해결 방법은 해당 항목을 다시 컴파일하는 것입니다. 소스 코드가 있는 경우: Linux는 독점 소프트웨어도 지원합니다.
소스를 사용할 수 있더라도 모든 정보를 수집하는 것은 고통스러울 수 있습니다. 특히 하드웨어 버그를 수정하기 위해 커널을 업그레이드하는 경우에는 더욱 그렇습니다. 사람들은 하드웨어 지원이 필요하기 때문에 시스템의 나머지 부분과 독립적으로 커널을 업그레이드하는 경우가 많습니다. 내부에리누스 토발즈의 말:
사용자 프로그램을 깨뜨리는 것은 용납되지 않습니다. (...) 우리는 사람들이 수년 동안 오래된 바이너리를 사용해 왔다는 것을 알고 있으며, 새 버전을 출시한다고 해서 이를 버릴 수 있다는 의미는 아닙니다. 당신은 우리를 신뢰할 수 있습니다.
그도 설명했다이것을 강력한 규칙으로 만드는 한 가지는 종속성 지옥을 피하는 것입니다. 종속성 지옥은 새로운 커널이 작동하도록 하려면 다른 프로그램을 업그레이드해야 할 뿐만 아니라 모든 것이 일부 버전에 의존하기 때문에 다른 프로그램을 업그레이드한 다음 업그레이드해야 하는 것입니다. 모든 것.
그것은일부잘 정의된 단방향 종속성이 있을 수 있습니다. 슬프지만 때로는 피할 수 없는 일이기도 합니다. (…) 나쁜 점은 양방향 의존성이 있다는 것입니다. 사용자 공간 HAL 코드가 새 커널에 의존하는 경우에는 괜찮습니다. 하지만 사용자는 이 코드가 "금주의 커널"보다는 "지난 몇 달의 커널"이 되기를 원할 것으로 생각됩니다.
그러나 양방향 종속성이 있으면 문제가 발생합니다. 이는 동시에 업그레이드해야 한다는 것을 의미하며 이는 용납될 수 없습니다. 이는 사용자에게도 안타까운 일이지만, 더 중요하게는 개발자에게도 안 좋은 일입니다. 왜냐하면 "오류가 발생했습니다"라고 말할 수 없거나 이등분 또는 유사한 종류의 작업으로 범위를 좁히려는 시도와 같은 작업을 수행할 수 없기 때문입니다.
사용자 공간에서 이러한 상호 의존성은 일반적으로 서로 다른 라이브러리 버전을 유지함으로써 해결되지만 하나의 커널만 실행할 수 있으므로 커널로 수행하려는 모든 것을 지원해야 합니다.
공식적인,
[시스템 호출 문 안정] 이전 버전과의 호환성은 최소 2년 동안 보장됩니다.
그러나 실제로는
대부분의 인터페이스(예: 시스템 호출)는 변경되지 않으며 항상 사용할 수 있습니다.
./sys
/proc
/sys
즉,
사용자 공간을 깨뜨리려면 애플리케이션 수준에서 수정이 필요합니다.
코어가 하나뿐이고 시스템의 나머지 부분과 독립적으로 업그레이드하려고 하기 때문에 이것은 좋지 않습니다. 그러나 복잡한 상호 의존성을 갖는 응용 프로그램이 많이 있습니다. 수백만 개의 서로 다른 설정에서 수천 개의 응용 프로그램을 최신 상태로 유지하는 것보다 커널을 안정적으로 유지하는 것이 더 쉽습니다.
답변2
모든 상호의존 시스템에는 기본적으로 두 가지 옵션이 있습니다. 추상화 및 통합. (의도적으로 기술적인 용어를 사용하지 않습니다.) 추상화하면 API를 호출할 때 API 뒤의 코드가 변경될 수 있지만 결과는 항상 동일하다는 의미입니다. 예를 들어 호출할 때 fs.open()
그것이 네트워크 드라이브인지, SSD인지, 하드 드라이브인지 상관하지 않고 항상 작업을 수행하는 데 사용할 수 있는 열린 파일 설명자를 얻습니다. "통합"의 목표는 방식이 바뀌더라도 일을 수행하는 "최상의" 방법을 제공하는 것입니다. 예를 들어, 네트워크 공유에서 파일을 여는 것은 디스크에서 파일을 여는 것과 다를 수 있습니다. 두 방법 모두 최신 Linux 데스크탑에서 널리 사용됩니다.
개발자의 관점에서는 "모든 버전에서 작동" 또는 "특정 버전에서 작동"의 문제입니다. OpenGL이 좋은 예입니다. 대부분의 게임은 특정 버전의 OpenGL을 사용하도록 설정되어 있습니다. 소스에서 컴파일해도 상관 없습니다. OpenGL 1.1을 사용하여 게임을 작성하고 3.x에서 실행하려고 하면 좋은 경험을 하지 못할 것입니다. 반면에 일부 호출은 관계없이 작동할 것으로 예상됩니다. 예를 들어, fs.open()
내가 사용하고 있는 커널 버전에 신경쓰고 싶지 않다고 말하고 싶습니다 . 나는 단지 파일 설명자를 원합니다.
각 접근 방식에는 이점이 있습니다. 통합은 이전 버전과의 호환성을 희생하면서 "최신" 기능을 제공합니다. 추상화는 "최신" 호출에 안정성을 제공하지만. 그러나 이것이 가능성이 아니라 우선순위의 문제라는 점은 주목할 가치가 있습니다.
대중의 관점에서 볼 때 실제로 타당한 이유가 없다면 복잡한 시스템에서는 추상화가 항상 더 좋습니다. 예를 들어, fs.open()
커널 버전에 따라 상황이 어떻게 다르게 작동하는지 상상해 보세요. 그러면 간단한 파일 시스템 상호 작용 라이브러리는 수백 가지의 서로 다른 "파일 열기" 방법(또는 블록)을 유지해야 합니다. 새로운 커널 버전이 나오면 "업그레이드"할 수 없으며 사용하는 모든 소프트웨어를 테스트해야 합니다. 커널 6.2.2(가짜)는 텍스트 편집기를 손상시킬 수 있습니다.
일부 실제 사례의 경우 OSX는 사용자 공간 파괴에 신경 쓰지 않는 경향이 있습니다. 그들의 목표는 "추상화"보다는 "통합"을 더 자주 수행하는 것입니다. 모든 주요 운영 체제 업데이트마다 문제가 발생합니다. 이는 한 가지 접근 방식이 다른 접근 방식보다 낫다는 의미는 아닙니다. 이것은 선택이자 디자인 결정입니다.
결론은 Linux 생태계는 개인이나 그룹이 여가 시간에 기여하거나 도구가 유용하기 때문에 기여하는 훌륭한 오픈 소스 프로젝트로 가득 차 있다는 것입니다. 이를 염두에 두고 일단 재미가 없어지고 PIA가 되기 시작하면 개발자들은 다른 곳으로 갈 것입니다.
예를 들어, 에 패치를 제출했습니다 BuildNotify.py
. 제가 이타적이어서가 아니라 이 도구를 사용하고 기능을 원하기 때문입니다. 쉽기 때문에 여기에 패치가 있습니다. 복잡하거나 번거로우면 안쓰고 BuildNotify.py
다른거 찾아보게 되더라구요. 커널이 업데이트될 때마다 텍스트 편집기가 중단된다면 다른 운영 체제를 사용하게 될 것입니다. 커뮤니티에 대한 나의 기여(아무리 작더라도)는 지속되거나 존재하지 않을 것입니다.
그래서 디자인 결정은 시스템 호출을 추상화하여 이 작업을 수행할 때 fs.open()
제대로 작동하도록 하는 것이었습니다. 이는 fs.open
전염병이 발생한 후에도 오래 지속될 것임을 의미합니다.fs.open2()
역사적으로 이는 POSIX 시스템의 전반적인 목표였습니다. "이것은 일련의 호출과 예상 반환 값이며 이식성 이유로 다시 한 번 그 사이의 값을 파악합니다." Linus가 이 방법을 선택한 이유는 그의 마음속에 있으며, 여러분은 그에게 정확한 이유를 물어봐야 합니다. 하지만 저라면 복잡한 시스템의 통합보다는 추상화를 선택하겠습니다.
답변3
이것은 디자인 결정이자 선택입니다. Linus는 극히 드물고 특별한 상황(예: 보안 관련)을 제외하고는 커널 변경으로 인해 애플리케이션이 중단되지 않는다는 점을 사용자 공간 개발자에게 확신시킬 수 있기를 원합니다.
장점은 사용자 공간 개발자가 임의적이고 변덕스러운 이유로 새 커널에서 갑자기 코드가 손상되는 것을 발견하지 못한다는 것입니다.
단점은 커널이 오래된 코드, 오래된 시스템 호출 등을 영원히(또는 적어도 유효 수명 이상으로) 유지해야 한다는 것입니다.