본문 바로가기

Netty

Netty 컴포넌트별 프로세스 단계와 역할

Netty의 네트워크 통신 과정에서 각 컴포넌트가 어떤 단계에서 어떤 역할을 하는지 상세히 설명하겠습니다.

 

전체 프로세스 개요

Netty의 네트워크 통신은 크게 다음 단계로 진행됩니다:

  1. 서버 초기화 및 바인딩
  2. 클라이언트 연결 수락
  3. 데이터 수신 처리 (인바운드)
  4. 데이터 송신 처리 (아웃바운드)
  5. 연결 종료

 

1. 서버 초기화 및 바인딩 단계

ServerBootstrap

  • 역할: 서버 설정의 중앙 집중화
  • 수행 작업:
    • EventLoopGroup 설정 (Boss와 Worker 그룹)
    • 서버 채널 클래스 지정 (NioServerSocketChannel)
    • 채널 옵션 설정 (SO_BACKLOG, SO_REUSEADDR 등)
    • 초기 ChannelHandler 등록
ServerBootstrap bootstrap = new ServerBootstrap()
    .group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)
    .childHandler(new ChannelInitializer<SocketChannel>() {
        // 새로운 연결마다 파이프라인 설정
    });

Boss EventLoopGroup

  • 역할: 새로운 클라이언트 연결 수락 전담
  • 수행 작업:
    • 서버 소켓에서 Accept 이벤트 감지
    • 새로운 클라이언트 채널 생성
    • Worker EventLoop에 채널 등록

 

2. 클라이언트 연결 수락 단계

ServerSocketChannel (서버 채널)

  • 역할: 클라이언트 연결을 받아들이는 서버 소켓 추상화
  • 수행 작업:
    • 포트 바인딩
    • 클라이언트 연결 대기
    • 새로운 SocketChannel 생성

SocketChannel (클라이언트 채널)

  • 역할: 개별 클라이언트와의 통신 채널
  • 수행 작업:
    • Worker EventLoop에 등록
    • ChannelPipeline 초기화
    • 읽기/쓰기 이벤트 처리 준비

Worker EventLoopGroup

  • 역할: 실제 I/O 작업 처리
  • 수행 작업:
    • 등록된 채널들의 I/O 이벤트 감지
    • 채널별 ChannelHandler 호출
    • 하나의 EventLoop는 여러 채널 담당 가능

 

3. 데이터 수신 처리 (인바운드) 단계

EventLoop

  • 역할: I/O 이벤트 감지 및 처리 조율
  • 수행 작업:
    • Selector를 통해 읽기 이벤트 감지
    • 해당 채널의 파이프라인에 이벤트 전달
    • 순차적 이벤트 처리 보장

ChannelPipeline

  • 역할: 인바운드 이벤트의 처리 흐름 관리
  • 수행 작업:
    • Head에서 Tail 방향으로 이벤트 전파
    • 각 핸들러에 순차적으로 이벤트 전달
    • 핸들러 체인 관리

ByteBuf

  • 역할: 네트워크에서 수신한 바이트 데이터 저장
  • 수행 작업:
    • 소켓에서 읽은 원시 바이트 데이터 저장
    • 읽기/쓰기 인덱스를 통한 효율적 데이터 접근
    • 메모리 풀링을 통한 성능 최적화

ChannelInboundHandler (순서대로 실행)

1. ByteToMessageDecoder (디코더)

  • 역할: 바이트 스트림을 의미있는 메시지 객체로 변환
  • 수행 작업:
     
    ByteBuf → 프로토콜별 메시지 객체
    예: HTTP 요청, JSON 객체, 커스텀 프로토콜 메시지

2. MessageToMessageDecoder (추가 디코딩)

  • 역할: 1차 디코딩된 메시지를 더 상위 레벨 객체로 변환
  • 수행 작업:
     
    기본 메시지 객체 → 비즈니스 로직용 객체
    예: JSON 문자열 → POJO 객체

3. Business Logic Handler

  • 역할: 실제 비즈니스 로직 처리
  • 수행 작업:
    • 메시지 검증
    • 비즈니스 로직 실행
    • 응답 메시지 생성
    • 다음 핸들러로 응답 전달

 

4. 데이터 송신 처리 (아웃바운드) 단계

ChannelPipeline

  • 역할: 아웃바운드 이벤트의 처리 흐름 관리
  • 수행 작업:
    • Tail에서 Head 방향으로 이벤트 전파 (인바운드와 반대)
    • 각 아웃바운드 핸들러에 순차적으로 이벤트 전달

ChannelOutboundHandler (역순으로 실행)

1. Business Logic Handler

  • 역할: 응답 메시지 생성 및 전송 시작
  • 수행 작업:
     
    ctx.writeAndFlush(responseMessage);

2. MessageToMessageEncoder

  • 역할: 고수준 객체를 중간 형태로 변환
  • 수행 작업:
     
    비즈니스 객체 → 프로토콜 메시지
    예: POJO 객체 → JSON 문자열

3. MessageToByteEncoder

  • 역할: 메시지 객체를 바이트 스트림으로 변환
  • 수행 작업:
     
    프로토콜 메시지 → ByteBuf
    예: HTTP 응답 → 바이트 배열

Channel

  • 역할: 실제 네트워크 소켓으로 데이터 전송
  • 수행 작업:
    • ByteBuf의 데이터를 소켓에 쓰기
    • 운영체제의 송신 버퍼로 데이터 전달

 

5. 연결 종료 단계

EventLoop

  • 역할: 연결 종료 이벤트 감지 및 처리
  • 수행 작업:
    • 소켓 연결 끊김 감지
    • channelInactive 이벤트 발생

ChannelHandler

  • 역할: 정리 작업 수행
  • 수행 작업:
    • 리소스 해제
    • 연결 상태 업데이트
    • 로깅 및 모니터링

ByteBuf

  • 역할: 메모리 정리
  • 수행 작업:
    • 참조 카운트 감소
    • 메모리 풀로 반환 또는 GC 대상화

 

컴포넌트 간 상호작용 흐름

[클라이언트 연결] 
    ↓
[Boss EventLoop] → 연결 수락 → [Worker EventLoop에 채널 등록]
    ↓
[Worker EventLoop] → I/O 이벤트 감지
    ↓
[ChannelPipeline] → 이벤트 전파
    ↓
[ByteToMessageDecoder] → 바이트를 메시지로 변환
    ↓
[Business Handler] → 비즈니스 로직 처리
    ↓
[MessageToByteEncoder] → 메시지를 바이트로 변환
    ↓
[Channel] → 네트워크로 응답 전송

 

핵심 특징

  1. 이벤트 기반: 모든 작업이 이벤트 발생과 처리로 진행
  2. 비동기 처리: I/O 작업이 블로킹되지 않음
  3. 파이프라인 패턴: 처리 단계가 체인으로 연결
  4. 스레드 안전성: 각 채널은 하나의 EventLoop에서만 처리
  5. 메모리 효율성: ByteBuf 풀링과 참조 카운팅으로 최적화

이러한 구조를 통해 Netty는 높은 성능과 확장성을 제공하면서도 복잡한 네트워크 프로그래밍을 단순화합니다.