Skip to content

netpoll

Go 의 netpoll 은 Go 런타임 (runtime) 이 구현한 핵심 I/O 멀티플렉싱 메커니즘으로, Go 가 간결한 동기 프로그래밍 모델 (연결당 하나의 Goroutine) 로 고성능 네트워크 서비스를 구현할 수 있게 합니다. 본질은 운영체제底层 I/O 멀티플렉싱 시스템 호출 (예: Linux 의 epoll) 을 Go 의 Goroutine 스케줄러와 깊이 결합한 것입니다.

Netpoll 과 원본 GoNet 비교

  1. Goroutine 수

    • Go Net: 하나의 Goroutine 아래에 하나의 연결만 있습니다.
    • NetPoll: 하나의 Goroutine 아래에 여러 연결이 있습니다.
  2. Goroutine 컨텍스트 전환 스케줄링 부하

    • Go Net: 고동시성 시 전환 부하가 큽니다. GoNet 은 연결당 하나의 goroutine 이므로 goroutine 수가 많으면 전환이 빈번합니다.
    • NetPoll: 고동시성 시 전환 부하가 작습니다. NetPoll 은 여러 연결이 하나의 goroutine 을 공유하므로 전환 횟수가 적습니다.
  3. 메모리 소비

    • Go Net: 메모리 소비는 연결 수와 양의 상관관계가 있으며 고동시성 시 Goroutine 수 폭주로 메모리 압박이 발생할 수 있습니다.
    • NetPoll: 버퍼 풀을 미리 할당합니다.
  4. 트리거 방식

    • Go Net: 엣지 트리거 ET 를 사용합니다. 한 번에 데이터를 모두 읽어 구현이 간단합니다.
    • NetPoll: 레벨 트리거 LT 를 사용합니다. 데이터 버퍼용으로 충분히 큰 메모리를 미리 할당할 필요가 없습니다.
  5. 커널과 사용자 층 버퍼 풀 공유 지원 여부, 데이터 복사 한 번 감소

    • Go Net: 지원하지 않습니다.
    • NetPoll: 지원합니다. Buffer 풀을 관리하여 사용자에게 직접 전달하여 데이터 복사를 한 번 줄입니다.
  6. 적용 시나리오

    • Go Net: 저동시성 단순 시나리오
    • NetPoll: 고동시성 저지연 시나리오

netpoll 설계 아이디어

  1. 기본 아키텍처 원본 네트워크 라이브러리는 epoll lt 모드를 기반으로 개발되었으며 기본 아키텍처는 아래 그림과 같습니다. netpoll 기본 아키텍처

  2. goroutine 사용 poll 객체 풀이 존재하며 각 poll 객체는 하나의 epoll 을 가지고 있으며 별도로 하나의 goroutine 에 대응합니다. goroutine 수와 poll 객체 수가 일치하며 각 poll 객체는 여러 파일 디스크립터 fd 를 리스닝할 수 있습니다.

  3. IO 읽기/쓰기 로직

    • 각 poll 객체는 하나의 goroutine 을 시작하여 현재 epoll 의 읽기 가능, 쓰기 가능 등의 이벤트를 지속적으로 폴링합니다.
    • 각 epoll 은 여러 fd 와 연관되며 각 fd 는 하나의 Buffer 와 연관됩니다.
    • fd 에서 읽기 가능 이벤트를 감지하면 데이터를 Buffer 에 읽습니다.
    • Buffer 의 데이터를 지속적으로 폴링하여 처리하며 데이터 읽기가 완료되면 후속 처리 로직의 코루틴 풀 GoPoll 에 실행을 알림합니다.
    • 커널과의 시스템 호출 상호작용은 완전히 netpoll 이 제어하며 사용자 층의 Conn 읽기/쓰기는 공용 Buffer 를 조작할 뿐입니다.
  4. 장단점

    • 장점: 고동시성 지원 능력이 더 강합니다.
      • (1) Buffer 의 데이터를 폴링하여 처리하므로 데이터가 처리되지 못하는 상황이 발생하지 않습니다.
      • (2) 하나의 goroutine 이 여러 연결에 대응하므로 연결이 매우 많더라도 리소스 스케줄링 전환 오버헤드가 크지 않습니다.
      • (3) 사용자와 커널이 buff 를 공유하여 데이터 복사 작업을 한 번 줄여 효율을 향상시킵니다.
    • 단점: 더 많은 메모리를 차지합니다.

Golang by www.golangdev.cn edit