나는 소프트웨어 개발에 대한 나의 관심, 특히 가장 광범위한 문제를 해결하면서 가능한 한 적은 타협을하는 인체 공학적으로 소프트웨어 시스템을 만드는 퍼즐에 열정적입니다. 또한 Andrew Kelley의 정의에 의해 협력하는 시스템을 완전히 이해하는 데 관심이있는 개발자를 의미하는 시스템 개발자로 생각하고 싶습니다. 이 블로그에서는 다음과 같은 문제를 해결하는 데 대한 내 아이디어를 공유합니다. 꽤 도전이 아니야? 블로그에서 나는 "Performant Web Server"부분에 중점을 둡니다. 그곳에서 나머지는 잘 정리되어 있거나 추가 할 것이 없기 때문에 새로운 관점을 제공 할 수 있다고 생각합니다. 주요 경고 -
코드 샘플이 없을 것입니다.실제로 테스트하지 않았습니다. 그렇습니다. 이것은 큰 결함이지만 실제로는 이것을 구현하는 데는 많은 시간이 걸리지 않습니다. 내가 가지고 있지 않은 블로그를 게시하고 전혀 게시하지 않는 것 사이에서 나는 전자를 붙잡 았습니다. 당신은 경고를 받았습니다.
그리고 우리는 응용 프로그램에서 어떤 부분을 조립합니까?
당신이 편한 프론트 엔드이지만 최소한의 종속성을 원한다면 wasm form htmx에 zig가 있습니다.
어쨌든 코 루틴이 과대 평가 되었습니까?
Coroutines (사용자 공간 스레드)가 더 높은 체중이 빠르고 빠르다는 것은 일반적인 지식입니다. 그러나 정확히 어떤면에서? (여기서 답은 대부분 추측입니다. 소금 한 알을 가져 가서 직접 테스트하십시오)
기본적으로 스택 공간이 적은 상태로 시작합니다 (4MB 대신 2KB). 그러나 이것은 수동으로 조정될 수 있습니다.
GO 런타임, 예를 들어, 멀티플렉스는 Goroutines를 OS 스레드로 향하게합니다. 스레드는 페이지 테이블과 프로세스가 소유 한 기타 리소스를 공유합니다. 믹스에 CPU 분리 및 친화력을 도입하면 스레드가 각각의 CPU 코어에서 지속적으로 실행되면 모든 OS 데이터 구조는 교환 할 필요없이 메모리에 머무르며, 사용자 공간 스케줄러는 협력적인 멀티 태스킹 모델을 사용하기 때문에 CPU 시간을 정밀도로 할당합니다. 경쟁은 가능합니까?
커널과 협력 할 수 있습니까?
독립적 인 실행 단위에 대한 "진정한"OS 수준의 추상화는 스레드가 아니라고 주장 할 것입니다. 실제로 OS 프로세스입니다. 실제로, 여기서의 구별은 분명하지 않습니다. 스레드와 프로세스를 구별하는 모든 것은 다른 PID 및 TID 값입니다. 파일 설명자, 가상 메모리, 신호 처리기, 추적 리소스에 관해서는 자식이 "클론"SYSCALL에 대한 인수에 명시되어 있는지 여부. 따라서 "프로세스"라는 용어를 사용하여 자체 시스템 리소스를 소유 한 실행 스레드 (주로 CPU 시간, 메모리, 열린 파일 설명자)를 의미합니다.
이제 이것이 중요한 이유는 무엇입니까? 각 실행 단위에는 시스템 리소스에 대한 자체 요구가 있습니다. 각 복잡한 작업은 단위로 분류 될 수 있으며, 각 작업은 자체적으로 예측 가능하며 리소스 요청 (메모리 및 CPU 시간)을 만들 수 있습니다. 그리고 더 일반적인 작업을 향한 하위 작업의 트리가 더 커지면 시스템 리소스 그래프는 긴 꼬리가있는 종 곡선을 형성합니다. 그리고 꼬리가 시스템 리소스 제한을 초과하지 않도록하는 것은 귀하의 책임입니다. 그러나 어떻게 이루어지고, 그 한계가 실제로 초과되면 어떻게됩니까?
대부분의 주류 소프트웨어 스택에 대한 이러한 시나리오를 다루는 유일한 현실적인 방법은 시스템에 "지방"을 남기고 (벨 곡선의 꼬리에 대한 미사용 리소스)와 동시 요청 수를 제한하는 것입니다. 그럼에도 불구하고, 우리는 OM을 살해 당하거나 가끔씩 한 번에 한 번에 반응하지 않을 것입니다. 이러한 타협은 많은 사람들에게 허용되며 실제로 소프트웨어 시스템에 충분히 도움이됩니다. 하지만 우리는 더 잘할 수 있습니까?
동시성 모델
리소스 사용량은 프로세스 당 추적되므로 이상적으로는 예측 가능한 각 소규모 실행 단위에 대한 새로운 프로세스를 생성하는 것입니다. 그런 다음 CPU 시간과 기억을위한 Ulimit을 설정했습니다. Ulimit은 소프트 및 하드 제한을 가지고있어 소프트 한계에 부딪히면 프로세스가 우아하게 종료 될 수 있으며, 발생하지 않으면 버그로 인해 하드 한계를 치면 강제로 종료됩니다. 불행히도, Linux에서 새로운 프로세스를 산란하는 것은 느리기 때문에 많은 웹 프레임 워크와 Temporal과 같은 다른 시스템에서 요청 당 새로운 프로세스가 지원되지 않습니다. 또한, 프로세스 전환은 더 비싸다. 이는 Cow 및 CPU 고정으로 완화되지만 여전히 이상적이지 않다. 불행히도 장기 실행 프로세스는 피할 수없는 현실입니다.
짧은 수명의 프로세스의 깨끗한 추상화에서 더 많이 갈수록 OS 수준의 작업이 더 많을수록 우리 자신을 돌봐야합니다. 그러나 많은 실행 스레드 사이에서 IO를 배치하기 위해 io_uring을 사용하는 것과 같이 얻을 수있는 이점도 있습니다. 실제로, 큰 작업이 하위 작업으로 구성된 경우 - 우리는 그들의 개별 자원 활용에 실제로 관심이 있습니까? 프로파일 링을 위해서만. 그러나 큰 작업을 위해 자원 벨 곡선의 꼬리를 관리 (차단) 할 수 있다면 충분할 것입니다. 따라서 우리는 동시에 처리하고자하는 요청만큼 많은 프로세스를 스폰 할 수 있으며,이를 오래 지속되도록하고, 각각의 새로운 요청에 대해 Ulimit을 간단히 재조정합니다. 따라서 요청이 리소스 제약 조건을 오버런하면 OS 신호를 가져오고 다른 요청에 영향을 미치지 않고 우아하게 종료 할 수 있습니다. 또는 높은 리소스 사용량이 의도적 인 경우 고객에게 더 높은 리소스 할당량을 지불하도록 지시 할 수 있습니다. 나에게 꽤 좋은 것 같다.
Linux를 사용한 협력 멀티 태스킹
syscall sched_yield가있어서 스레드가 작업 부분을 완료했을 때 CPU를 포기할 수 있습니다. 매우 협조적인 것 같습니다. 주어진 크기의 타임 슬라이스를 요청할 수있는 방법이있을 수 있습니까? 실제로 - 스케줄링 정책 sched_deadline이 있습니다. 이것은 실시간 정책으로, 요청 된 CPU 타임 슬라이스의 경우 스레드가 중단되지 않음을 의미합니다. 그러나 슬라이스가 오버런되면 선점이 시작되고 스레드가 교환되어 박탈 당합니다. 또한 슬라이스가 언더 런 인 경우 - 스레드는 Sched_Yield를 호출하여 조기 마감을 표시하여 다른 스레드를 실행할 수 있습니다. 그것은 두 세계의 최고처럼 보입니다 - 협력적이고 선사의 모델.
한계는 sched_deadline 스레드가 포크 할 수 없다는 사실입니다. 이로 인해 동시성에 대한 두 가지 모델이 남아 있습니다. 요청 당 프로세스 자체를 설정하고 효율적인 IO를위한 이벤트 루프 또는 시작부터 각 마이크로 작업에 대해 스레드를 스폰하고 각각의 마감일을 설정하고 서로 의사 소통을 위해 큐를 사용하는 프로세스가 제공됩니다. 전자는 더욱 추방적이지만 사용자 공간에서 이벤트 루프가 필요하며 후자는 커널을 더 많이 사용합니다.
.
임베디드 스크립팅 언어로서의 파이썬 이것은 지그가 빛나는 고성능, 저도, 낮은 수준의 측면을위한 것입니다. 그러나 응용 프로그램의 실제 비즈니스와 관련하여 유연성은 대기 시간보다 훨씬 가치가 있습니다. 프로세스에 실제 사람들이 문서에 서명하는 경우 - 컴퓨터의 대기 시간은 무시할 수 있습니다. 또한 공연의 고통에도 불구하고 객체 지향 언어는 개발자에게 비즈니스 영역을 모델링 할 수있는 더 나은 프리미티브를 제공합니다. 그리고이 중 가장 먼 곳에서 Flowable 및 Camunda와 같은 시스템은 경영진 및 운영 직원이 더 많은 유연성과 더 낮은 입국 장벽으로 비즈니스 논리를 프로그래밍 할 수 있도록 허용합니다. Zig와 같은 언어는 이것에 도움이되지 않으며 당신의 방식으로 만 서 있습니다.
반면에 파이썬은 가장 역동적 인 언어 중 하나입니다. 클래스, 객체 - 그들은 후드 아래의 모든 사전이며, 당신이 좋아하지만 런타임에 조작 할 수 있습니다. 이는 성능 페널티가 있지만 클래스와 객체로 비즈니스를 모델링하고 많은 영리한 트릭을 실용적으로 만듭니다. 지그는 그 반대입니다. Zig에는 의도적으로 영리한 트릭이 거의 없으므로 최대의 제어를 제공합니다. 상호 작용하도록함으로써 그들의 힘을 결합 할 수 있습니까?
실제로 우리는 C ABI를 지원했기 때문에 우리는 할 수 있습니다. Python 통역사를 ZIG 프로세스 내에서 실행할 수 있으며 별도의 프로세스가 아니라 런타임 비용 및 접착제 코드의 오버 헤드를 줄일 수 있습니다. 이를 통해 파이썬 내에서 Zig의 맞춤형 할당자를 활용하여 개별 요청을 처리하기위한 경기장을 설정하여 쓰레기 수집기의 오버 헤드를 제거하지 않으면 메모리 캡을 설정할 수 있습니다. 주요 제한 사항은 쓰레기 수집 및 IO의 CPYTHON 런타임 스폰 스레드입니다. 그러나 나는 그 증거를 찾지 못했습니다. AbstractMemoryLoop의 "컨텍스트"필드를 사용하여 코 루틴 메모리 추적을 통해 Python을 Zig의 사용자 정의 이벤트 루프에 연결할 수 있습니다. 가능성은 무한합니다.
우리는 동시성, 병렬 처리 및 다양한 형태의 OS 커널 통합의 장점에 대해 논의했습니다. 탐사에는 벤치 마크와 코드가 부족하여 제공되는 아이디어의 품질을 보완하기를 바랍니다. 비슷한 것을 시도해 보셨습니까? 당신의 생각은 무엇입니까? 피드백을 환영합니다 :)
추가 독서
https://linux.die.net/man/2/clone
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3