Java NIO

Hyunjun Jang·2021년 11월 6일
1

NIO란?

자바 4부터 새로운 입출력(New Input Output)이라는 뜻에서 java.nio 패키지에 포함 되었는데 자바 7로 버전 업그레이드 되면서 자바 IO 와 NIO 사이의 일관성 없는 클래스 설계를 바로 잡고 비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가되었다.

NIO.2는 java.nio의 하위 패키지(java.nio.channels, java.nio.charset, java.nio.file)에 통합되어 있음

JVM이라는 프로세스 위에서 동작하는 추상화된 비교적 고수준의 언어이기 때문에 자바는 느리다.
기타 GC(Garbage Collection)의 메모리 점유 문제등 느린 이유는 많이 있지만 그중 I/O 처리 문제점을 개선하고자 나온 패키지가 java.nio이다.

NIO 패키지포함되어 있는 내용
java.nio다양한 버퍼 클래스
java.nio.channels파일 채널, TCP 채널, UDP 채널 등의 클래스
java.nio.channels.spijava.nio.channels 패키지를 위한 서비스 제공자 클래스
java.nio.charset문자셋, 인코더, 디코더 API
java.nio.charset.spijava.nio.charset 패키지를 위한 서비스 제공자 클래스
java.nio.file파일 및 파일 시스템에 접근하기 위한 클래스
java.nio.file.attribute파일 및 파일 시스템의 속성에 접근하기 위한 클래스
java.nio.file.spijava.nio 패키지를 위한 서비스 제공자 클래스

IO 와 NIO의 차이점

구분IONIO
입출력 방식스트림 방식채널 방식
버퍼 방식논버퍼버퍼
비동기 방식지원 안함지원
블로킹/논블로킹 방식블로킹방식만 지원블로킹/논블로킹 둘다 지원

Stream 기반 vs. Buffer 기반

스트림 지향적인 Java IO는 스트림에서 한 번에 하나 이상의 바이트를 읽는다는 것을 의미한다. 스트림에서 읽은 데이터를 앞뒤로 이동해야 하는 경우 먼저 버퍼에 캐시해야 한다.

IO는 스트림 기반 => 스트림은 입력 스트림과 출력 스트림이 구분되어 있음

Java NIO의 버퍼 지향 접근 방식은 약간 다르다. 데이터는 나중에 처리되는 버퍼로 읽는다. IO 방식과 다르게 필요에 따라 버퍼에서 앞뒤로 이동할 수 있으며 이러한 방식으로 인해서 처리하는 동안 더 많은 유연성을 얻을 수 있다.

그러나 버퍼를 완전히 처리하는 데 필요한 모든 데이터가 버퍼에 포함되어 있는지도 확인해야 하고 버퍼에 더 많은 데이터를 읽을 때 아직 처리하지 않은 버퍼의 데이터를 덮어쓰지 않도록 해야한다.

채널은 스트림과는 다르게 양방향 입출력 가능. 때문에 입력과 출력을 위한 별도의 채널을 만들 필요 없음

Blocking vs. Non-blocking IO

Java IO의 다양한 스트림이 블로킹 처리가 된다. 즉, 스레드가 read() 또는 를 호출하면 write() 읽을 데이터가 있거나 데이터가 완전히 쓰여질 때까지 해당 스레드는 대기상태가 되고. 그 동안 스레드는 다른 작업을 수행할 수 없다.

IO스레드가 블로킹되면 다른 일을 할 수 없고 블로킹을 빠져나오기 위해 인터럽트할 수도 없음. 유일한 방법은 스트림을 닫는 것

Java NIO의 논블록킹을 사용하면 스레드가 채널에서 데이터 읽기를 요청할 수 있으며 현재 사용 가능한 데이터만 가져오거나 현재 사용 가능한 데이터가 없는 경우 아무 것도 가져오지 않는다. 데이터를 읽을 수 있을 때까지 블로킹 상태로 유지하는 대신 스레드는 다른 작업을 계속할 수 있다.

NIO 논블로킹의 핵심 객체는 멀티플렉서인 셀렉터(Selector)이다. 셀렉터는 복수 개의 채널 중에서 준비완료된 채널을 선택하는 방법을 제공한다.

Selectors

Java NIO의 Selectors를 사용하면 단일 스레드가 여러 입력 채널을 모니터링할 수 있습니다. 이 메커니즘을 사용하면 단일 스레드에서 여러 채널을 쉽게 관리할 수 있다.

클라이언트 하나당 쓰레드 하나를 생성해서 처리하기 때문에 쓰레드가 많이 생성될 수록 급격한 성능 저하를 가졌던 단점을 개선하는 Reactor 패턴의 구현체이다.

NIO 핵심 컴포넌트

Channel

Java NIO 채널은 다음과 같은 몇 가지 차이점이 있는 스트림과 유사하다.

  • 채널을 읽고 쓸 수 있다.
  • 채널은 비동기적으로 읽고 쓸 수 있다.
  • 채널은 항상 버퍼에서 읽거나 쓴다.

채널 구현 처리

  • FileChannel : 파일에 데이터를 읽는다.
  • DatagramChannel : UDP를 통해서 네트워크에 데이터 읽기, 쓰기를 처리한다.
  • SocketChannel : TCP를 통해서 네트워크에 데이터 읽기, 쓰기를 처리한다.
  • ServerSocketChannel : TCP 수신 할수 있는 채널이 생성된다. 요청에 의해 SocketChannel 통해서 만들어진다.

Scatter/Gather 구현으로 효율 적인 IO 처리 지원

프로세스에서 사용하는 버퍼 목록을 한번의 시스템 콜로 읽고 쓸수 있게 되는 기능

Buffer

Java NIO 버퍼는 NIO 채널과 상호 작용할 때 사용된다. 데이터는 채널에서 버퍼로 읽고 버퍼에서 채널로 기록된다.

버퍼는 데이터를 쓰고 나중에 다시 읽을 수 있는 메모리 블록이다. 이 메모리 블록은 NIO Buffer 객체로 래핑되어 메모리 블록으로 작업하기 쉽게 만드는 메서드를 제공한다.

Buffer를 사용하여 데이터를 읽고 쓰는 것은 일반적으로 다음과 같은 작은 4단계 프로세스를 따른다.

  • 버퍼에 데이터 쓰기
  • buffer.flip() 호출
  • 버퍼에서 데이터 읽기
  • buffer.clear() 또는 buffer.compact() 호출

Java NIO 버퍼의 유형

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

Selectors

Java NIO Selector는 하나 이상의 Java NIO 채널 인스턴스를 검사 하고 예를 들어 읽기 또는 쓰기를 위해 준비된 채널을 결정할 수 있는 구성요소이다.

단일 스레드를 사용하여 여러 채널을 모니터 하면서 연결, 이벤트 처리, 관리를 할수 있다.

NIO Server 처리 구성 (Netty)

NIO 서버 데이터 처리 순서

  • Send

    1. Selector(Acceptor Single Thread Queue)를 생성하고 Selector에 Channel(ServerSocket)들을 등록(Write)한다.

      이과정에서 Selector는 단일 스레드로 멀티스레드처럼 처리가 가능하는데 이동작이 multiplexing이라 할 수 있다.

    2. Channel 들은 처리할 이벤트를 양방향 Buffer에 등록(Write)한다.
    3. Buffer는 해당 이벤트(notify)를 연관된 비즈니스 로직 or 연관된 시스템에게 보낸다.
  • Receive

    1. 비즈니스 로직 or 연관된 시스템이 처리한 데이터를 양방향 Buffer로 받는다.

      이때 버퍼(가상 주소)를 사용하여 물리 메모리에 커널 영역의 가상 주소와 매핑시켜 커널 영역에서 유저 영역으로 데이터를 복사하지 않고 바로 참조한다. 즉, I/O 대기 없이 Non-Blocking방식으로 데이터를 처리한다.

    2. Netty의 Channel 은 양방향 Buffer로부터 처리된 이벤트를 등록(Write)한다.
    3. 클라이언트에서 요청이 오면 큐에 있는 데이터를 기다리지 않고 비동기적 (이벤트 notify)으로 처리하는 Selector는 SelectionKey 통해 관리 되고 있는 연관된 Channel을 찾아준다.
    4. 찾은 Channel에서는 처리된 이벤트를 클라이언트에게 회신한다.
    5. 신규 클라이언트에서 요청이 오면 연관된 connection인 socket Channel을 Selector에 등록하여 비동기 Non-blocking 하게 데이터를 요청한다.

Reference

https://taes-k.github.io/2021/01/06/java-nio/
https://jeong-pro.tistory.com/145
https://dev-coco.tistory.com/42
http://tutorials.jenkov.com/java-nio/nio-vs-io.html
https://junshock5.tistory.com/149
https://www.slideshare.net/kslisenko/networking-in-java-with-nio-and-netty-76583794

profile
Let's grow together😊

0개의 댓글