Yuzhuo Jing and Peng Huang, Johns Hopkins University OSDI 2022
개요
Lightwegith한 커널내 Fork를 만들어서, Auxiliary Task라 불리우는 Process의 sub group을 안전하게 Isolate된 환경에서 돌릴 수 있도록 하였다. Orbit을 통해서, Auxiliary Task를 구현하게 되면, Fault isolated, Resource isolation 그리고 Performance isolation을 이룰 수 있디. 이를 통해서 Orbit은 Overvability 와 Isolation그리고 Performance를 동시에 잡을 수 있는 Solution을 제시하였다. 이를 위한 새로운 protection-domain의 정의를 Orbit을 통해서 정의하였다.
Problems
Application의 task중에서 optimize, examine, debug 그리고 control목적으로 사용되는 task들이 있는데, 그것들을 Auxiliary Task라고 부른다. 만약 Auxiliary Task가 Main process의 자원에 제약없이 접근 가능하다면, Auxiliary Task의 문제가 main 프로세스로 전파된다. 주 이유는, OS에 Process와 Thread사이에 해당하는 Context가 없다는 것이다. 기존 Work들은 이러한 용도로는 부합하지 못하다는 문제가 있었다.
Importance
Auxiliary Task를 기존의 Fork, Process, LwC와 같은 방식으로 구현하게 되면, Main process의 Performance에 영향을 끼치거나, Auxiliary Task의 Bug가 Main Process에 까지 전파되는 문제가 있었다. 이를 해결하면 Auxiliary Task의 구현을 완벽하게 할 수 있다.
Fork와 같은 방식은, Fork시스템콜이 매우 무거운 콜인점과, CoW가 전체 Application에서 이루어 짐으로, Performance degradation이 심해진다는 점, 그리고 Parent process의 상태를 Update할 수 없다는 점이 단점으로 뽑히게 된다. 이러한 문제를 해결하기 위해서는 새로운 Protection domain의 정의가 필요하다.
Background
우선 논문은 Protection scenario를 3개로 구분하였다.
- Extensibility: Application의 기능 확장을 하는 Extenstion을 안전하게 분리하여 실행시키기 위한 방법으로 SFI와 같은 방식이 사용된다. 대표적인 연구로 NaCL을 들 수 있다. E.g., User-defined function, Browser extension 등등
- Secure partition: Application의 일부분을 Main logic과 분리하여 안전하게 실행하기 위한 방법으로 분리되는 부분은 Application의 기능중 Secure sensitive한 부분이 된다. 대표적인 연구로 Wedge나 LwC가 있다. E.g., Session handler, Key signing 등등
- Maintenance (Auxiliary tasks): Application과는 독립적으로 실행되나, Application의 State를 감시하고 유지 보수하기 위해서 필요한 기능들을 분리하여 안전하게 실행시키기 위한 방법이다. Orbit이 제안한 개념이며, 연구되지 않은 부분이기도 하다. E.g., Fault detection, Performance monitor, Resource management, Recovery 등등
이떄 Auxiliary Task들은 다음과 같은 특징을 가진다.
- 주로 Read program state -> Perform inspection -> Task action -> Modify some state의 단계로 구성된다.
- 작업에 따라서 Read하는 프로그램의 State의 양은 많을 수도 적을 수도 있다.
- Asynchronously하게 Main Application과 같이 동작하는 Auxiliary Task들도 있다.
- Auxiliary Task는 Performance와 Safety가 모두 중요하나, Shared memory처럼 Performance를 올리면 Safety가 떨어지는 Trade-off관계에 있다.
Fork나 Sandbox가 불충분한 이유
- Fork의 경우
- Fork의 경우에는 강한 Isolation을 제공하나, Performance에 영향을 준다. 매 Fork시마다 Address space의 복사가 필요하며 CoW를 이용하더라도, 만약 Aux task에서 메모리를 많이 접근하면 Page fault처리 시간이 매우 늘어난다. 또한 Main application의 State수정이 필요할 경우, Fork의 경우에는 Child process라서 Parent process와는 분리된 Address space를 가지고 있기 떄문에, 구현이 복잡하다.
- Sandbox-based Execution 모델의 경우
- SFI를 이용한 Sanbox 모델은 Aux Task의 철학과는 맞지 않는다. 우선 Aux Task들은 Application개발자에 의해서 작성되며 신뢰가능하다. Sandbox와는 다르게 프로그램의 실수에 의해 문제가 발생하는 경우가 대0부분이며, 분리된 Execution domain이 필요하지 않다. 또한 Sandbox된 프로그램은 Application state와 분리되어 있기때문에, Fork의 경우처럼 Observability측면에서 확장이 힘들다.
- RPC나 Shared memory의 경우
- RPC모델을 사용하기 위해서는 Developer가 직접 변수를 RPC Procedure call로 주고 받아야 하여 불편하다. 또한 RPC의 오버헤드도 무시할 수 없다. Shared memory와 같은 경우에는 Main application과 Aux Task같의 Consistency를 맞추기 힘들고, Safety issue에서 자유롭지 못하다는 단점이 있다.
위에 설명한 대부분의 문제는 OS Abstraction이 분명한 Isolation domain을 가진 경우를 상정하고 개발되어 있기 때문이다. 이에 개발자들은 thread처럼 high observability를 가지나 low safety를 가지는 thread에 의존하거나 strong isolation을 가지나 low observability를 가지는 process모델에 의존할 수 밖에 없었다. 그렇다면 이러한 간극을 좁히는 디자인은 없을까? 이 질문이 본 논문의 문제의식이다.
+ Light-Weight Contexts가 불충분한 이유
Light-weight context와 같은 연구는 Secure partition과 snapshot rollback에 특화되어 있다. 그러나 Orbit과 같은 경우에는 Maintenance task의 분리와 Observability 그리고 MVCC를 이용한 안전한 Main Application State변경에 특화되어 있따.
이론적으로는 LwC에 Observability + Concurrency control를 추가하여, Orbit과 유사한 기능을 구현할 수 있지만, 이는 상당한 재설계가 필요하다. 일례로, Secure partition은 기본적으로 Main Application에 대한 접근을 Deny하기 때문에, CoW 성능에 대한 고려가 없으며, Process와 Thread의 간격을 줄인다는 LwC의 Lighweight이라는 장점을 희석시킬 가능성이 있다.
또한 Snapshot-based로는 MVCC와 같은 버전관리를 제공하기 힘들기 떄문에, LwC설계 그 자체로 Orbit과 같은 Observability asynchronous tool을 완벽히 따라가기에는 설계 철학과 기법이 다를 수 밖에 없다.
Main Idea
Auxiliary Task가 Isolated된 domain에서 다른 Task에 대한 Read-only observation만 가능한 새로운 Kernel provided protection domain을 제시하였다. Orbit을 이용하면 다음의 장점이 있다.
- Strong isolation
- Convenient Programming Model
- AUtomatic State Synchronization
- Controlled Alteration
- First-class Entity
Design
- Automatic State Synchronization
- Orbit area와 같은 Main process와 shared된 공간은 Kernel에 의해서 자동으로 동기화 된다. State가 너무 많으면 동기화 시키는데 오래걸린다. 따라서 orbit area라는 새로운 Address space를 통해서 선언된 메모리 영역만이 자동 동기화 되도록 하였다. Main program은
orbit_area_create
라는 명령어를 통해서 공유할 address space를 선언할 수 있도록 하였다.
- Lightweight Copy-on-write
- Orbit은 분리된 Address space를 가지고 있으며, Orbit에서 Main process의 접근을 위해서라면, <cord>orbit_alloc(free할 경우에는
orbit_free
)이라는 API를 통해서 메모리 영역이 Orbit에 의해서 Mirror되어 있다는 것을 표시해야 한다. 이렇게 표시된 영역은 CoW로 표시되어서, 나중에 Orbit에서 접근하는 경우 최신 CoW를 통해서 snapshot된 메모리 영역을 제공한다. 이떄 만약 CoW과정에서 Page접근을 막기 위해서 kernel에서 Lock을 잡으면 Main application이 느려지는 문제가 발생할 수 있는데, orbit은 이를 Application 으로 delegate함으로써 해결하였다.
- Modification by scratch space
- 때론 Auxiliary task에서 main process의 값을 Update해야 할 수도 있는데, 이를 해결하기 위해서 권한있는 Orbit은 특정 API를 통해서만 Main process의 값을 바꿀 수 있도록 하였다. Synchronization을 위해서 우선 write가 발생하면 scratch page에 먼저 적고, orbit에서 push를 부르고 main에서 pull하는 방식으로 (MVCC), Commit되게 하였다. 만일 Orbit이 Return하면 Program에 Signal을 보내고, Main program이 다음 Aux Task를 수행할 때까지 기다린다.
- First-class Entity
- Orbit의 task방식의 Execution을 지원하며, Orbit을 부른 Main process는 concurrent하게 orbit이 끝날때까지 기다리거나, 아니면 Asynchronous하게 실행시킬 수 있다. 이러한 기능을 제공하기 위해서 Kernel은 여러 Orbit의 Execution을 조절할 수 있는 system call들을 제공하였다.
Criticize
Thread와 Process사이의 간극을 메울 수 있는 새로운 Protection-domain의 개발이다. Process 와 Thread사이의 빈공간을 채운 LwC처럼 Orbit은 Process와 Thread사이의 빈 공간을 Light Weight Fork란 방식으로 채운 아이디어는 흥미로운 아이디어라 할 수 있다. 특히 Auxiliary Task라는 사람들이 조금은 무관심 했을 수도 있는, 그러나 Fault isolation의 domain이 있으면 좋은 부분을 집어내어 그 해결책을 새로운 Protection domain을 통해서 제시하였다는 점이 흥미로웠으며, 이는 매우 좋은 Contribution point라고 생각한다. 또한 다양한 Optimization기법들을 소개함으로써, 어떻게 Light-weight fork를 구현할지에 대한 Educational한 부분도 매우 중요한 논문의 부분이라고 생각된다.
하지만 Design & Implementation에서는 몇가지 아쉬운 점이 있었다.
- Auxiliary Task를 thread가 아니라 Orbit으로 Isolate 해야 하는 Motivation point가 빈약하다. Pthread와 같은 lightweigth thread를 사용하면 안되는 이유가 Isolation말고는 없는 것 같은데, 이게 Valid한 문제일까? Auxiliary Task를 안전하게 만드는 것이 그렇게나 힘든 일인가? Pthread + SFI쓰면 안될 이유가 있을까? 이에 대한 답이 논문에서는 잘 표현되고 있지 않는 것 같다.
- 그리고 일일이 Orbit Area를 마킹하는 작업이 필요한데, Shared memory access하는 작업은 Redundant한데 이작업은 쉽다? 이해되지 않는다.
- 또한 Concurrency를 해결하기 위해서 즉 만약 orbit area가 여러 Main process들이 작업하는 영역이라면 in-consistent한 결과가 나올 수 있는데, 이는 Application에서 Aux Task에서 lock을 잡기 편하게 대부분은 Global lock을 사용하는 경우가 많다는 가정하에 해결하였다. 그러나, Safety측면에서도 이는 Consistency의 보장을 어렵게 하며, 일반적으로 Fork시에 모든 메모리 영역은 자동으로 동기화된다는 가정하에 작성되는 많은 프로그램의 Concurrency model에도 맞지 않는 Ad-hoc적인 방법이라 생각한다. 앞서 설명한 Orbit area마킹작업과 함께, 이는 쉽게 기존의 프로그램을 Orbit의 철학을 담은 프로그램으로 변환시킬 수 있어야 한다는 본 논문의 취지와 맞지 않는 것이라 생각한다.
- Fine-grained한 shadow memory를 제공하는 (Orbit alloc)방법도 새로운 연구 방향으로 잡을 수 있을까?