# Sans-IO: 네트워크 서비스에 효과적인 Rust의 비밀

> Clean Markdown view of GeekNews topic #15692. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=15692](https://news.hada.io/topic?id=15692)
- GeekNews Markdown: [https://news.hada.io/topic/15692.md](https://news.hada.io/topic/15692.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-07-05T10:03:04+09:00
- Updated: 2024-07-05T10:03:04+09:00
- Original source: [firezone.dev](https://www.firezone.dev/blog/sans-io)
- Points: 3
- Comments: 1

## Topic Body

- Firezone에서는 Rust를 사용하여 Android 폰, MacOS 컴퓨터 또는 Linux 서버에서 확장 가능한 안전한 원격 액세스를 구축함  
- `connlib`라는 연결 라이브러리를 사용하여 네트워크 연결과 WireGuard 터널을 관리함  
- 여러 번의 반복 끝에 sans-IO라는 설계에 도달하여 빠르고 철저한 테스트, 깊은 커스터마이징, 높은 신뢰성을 제공함  
  
`connlib`는 Rust로 작성되었으며 sans-IO 설계를 따름  
- Rust의 속도와 메모리 안전성 덕분에 네트워크 서비스 구축에 적합함  
- `tokio` 런타임, `tungstenite` WebSockets, `boringtun` WireGuard 구현, `rustls` API 트래픽 암호화 등 사용  
- sans-IO 설계는 여러 곳에서 소켓을 통해 바이트를 보내고 받는 대신 순수 상태 기계로 프로토콜을 구현함  
  
#### Rust의 비동기 모델과 "함수 색칠" 논쟁  
  
- 비동기 함수는 다른 비동기 함수에서만 호출될 수 있음  
- 비동기 함수 깊숙이 있는 함수는 호출하는 모든 함수도 비동기 함수로 만들어야 함  
- 이로 인해 종속성의 비동기 여부에 대해 무관심한 코드를 작성하고자 하는 사람들에게 문제가 될 수 있음  
  
#### sans-IO 소개  
  
- sans-IO의 핵심 아이디어는 OOP 세계의 의존성 역전 원칙과 유사함  
- 정책(무엇을 할지)은 구현 세부 사항(어떻게 할지)에 의존하지 않아야 함  
- `Transmit` 구조체를 사용하여 데이터를 전송하는 대신 `Transmit`을 방출함  
  
#### 의존성 역전 적용  
  
- `Transmit` 구조체를 사용하여 데이터를 전송하는 대신 `Transmit`을 방출함  
- 이벤트 루프는 부작용을 구현하고 실제로 `UdpSocket::send`를 호출함  
  
##### 상태 기계  
  
- STUN 바인딩 요청의 상태 기계 다이어그램은 `Sent`와 `Received` 두 가지 상태를 가짐  
- `StunBinding` 구조체와 관련 함수들을 정의하여 상태 기계를 구현함  
  
##### 이벤트 루프  
  
- 이벤트 루프는 상태 기계를 구동하며, `poll_transmit`과 `handle_input`을 사용하여 데이터를 처리함  
  
##### 시간 추상화  
  
- `poll_timeout`과 `handle_timeout` API를 사용하여 시간 기반 요구 사항을 처리함  
  
#### sans-IO의 전제  
  
- sans-IO 설계는 종속성의 비동기 여부에 대한 결정을 애플리케이션으로 미룸  
- sans-IO 설계는 조합이 쉽고, 유연한 API를 제공하며, 테스트가 용이하고, Rust의 기능과 잘 맞음  
  
##### 쉬운 조합  
  
- `StunBinding`의 API는 대부분의 네트워크 프로토콜에 적용 가능함  
- Firezone의 `snownet` 라이브러리는 ICE와 WireGuard를 결합하여 네트워크 설정에 관계없이 작동하는 "마법" IP 터널을 제공함  
  
##### 유연한 API  
  
- 이벤트 루프를 직접 작성하면 코드 튜닝이 가능하고 유지 관리가 쉬움  
  
##### 빠른 테스트  
  
- sans-IO 코드는 부작용이 없으므로 테스트가 매우 용이함  
- Firezone에서는 참조 상태 기계를 구현하여 `connlib`의 실제 상태와 비교하는 테스트를 수행함  
  
##### 엣지 케이스와 IO 실패  
  
- sans-IO 설계는 프로토콜 구현을 실제 IO 부작용과 분리하여 엣지 케이스와 오류 처리를 쉽게 만듦  
  
#### Rust + sans-IO: 천생연분?  
  
- Rust는 소유권과 가변성을 명시적으로 모델링하여 sans-IO 설계와 잘 맞음  
- sans-IO 설계는 `&mut`를 자유롭게 사용하여 상태 변경을 표현하고, `async` Rust와는 달리 동기 API만 사용함  
  
#### 단점  
  
- 이벤트 루프를 직접 작성하면 미묘한 버그가 발생할 수 있음  
- 순차적 워크플로우는 더 많은 코드를 요구할 수 있음  
- Rust 커뮤니티에서 sans-IO 설계는 아직 널리 사용되지 않음  
  
#### 마무리  
  
- sans-IO 코드는 처음에는 생소하지만 익숙해지면 매우 즐거움  
- Rust는 상태 기계를 모델링하는 데 훌륭한 도구를 제공함  
- sans-IO 설계는 오류 처리를 입력 처리의 일부로 강제하여 네트워킹 코드를 작성하는 올바른 방식처럼 느껴짐  
  
### GN⁺의 의견  
  
- sans-IO 설계는 Rust의 소유권 모델과 잘 맞아 네트워크 프로토콜 구현에 매우 적합함  
- 이벤트 루프를 직접 작성하면 코드의 유연성과 유지 관리가 용이해짐  
- 테스트가 용이하여 안정적인 코드를 작성하는 데 큰 도움이 됨  
- 그러나 Rust 커뮤니티에서 널리 사용되지 않아 관련 라이브러리가 부족할 수 있음  
- 새로운 기술을 도입할 때는 학습 곡선과 커뮤니티 지원을 고려해야 함

## Comments



### Comment 26977

- Author: neo
- Created: 2024-07-05T10:03:04+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=40872020) 
- Rust의 async/await 문법 도입 전에는 수동으로 상태 기계를 구현했었음
  - Rust의 async/await 문법 덕분에 생산성이 크게 향상되었음
  - Rust의 async는 자동 상태 기계로 변환되어 I/O 지점에서 값을 저장해줌

- VT100 라이브러리를 작성하면서 Rust의 캡슐화 패턴 문제를 깨달았음
  - 캡슐화에 집착하는 것이 문제를 일으킴
  - 컴퓨터는 입력, 데이터 변환, 출력을 수행하는 기계임을 상기시킴

- 채널을 사용하여 데이터를 전송하는 디자인과 비교
  - 코드가 복잡해짐
  - 메시지 타입을 수동으로 구현해야 함
  - 송신기를 명시적으로 제공해야 함
  - 네트워크 전송 실패 시 결과를 얻지 못함
  - 그러나 편리한 점도 있음

- Haskell 생태계에서 논리와 실행을 분리하는 아이디어가 있음
  - `tokio::select!` 호출을 어떻게 캡슐화했는지 언급되지 않음
  - sans-IO 스타일로 캡슐화된 함수 구현에 관심이 있었음

- Rust의 async 함수는 상태 기계로 컴파일됨
  - sans-io와 async를 결합하려는 시도가 있었는지 궁금함
  - 주요 문제는 사용성 및 Pin 처리임

- 상태를 노출하면 async 함수가 '순수'해질 수 있음
  - OpenSSL을 async Rust에 바인딩하려고 시도했음

- Firezone이 놀라운 도구임
  - Rust-libp2p와 유사한 패턴을 발견했음

- 컴파일러가 async 코드를 sans io로 자동 변환할 수 있으면 좋겠음
  - 수동 변환은 오류가 발생하기 쉬움

- 기사와 댓글을 읽고 hexagonal 또는 ports/adapters 아키텍처 스타일을 재발명한 것 같음

- 실제 트래픽이 게이트웨이를 통해 지나가는지, 아니면 연결 설정에만 사용되는지 궁금함
