• Java NIO는 New Input/Output 약자로 채널(Channel)이 양방향 버퍼를 통해
    외부 데이터와 통신한다. 즉, NIO는 IO와 달리 읽기/쓰기를 하나의 통로로 해결한다.

  • NIO의 가장 큰 특징으로 비동기 / non-blocking 방식을 지원한다.
    • Non-Blocking Model 이란 I/O 작업이 진행되는 동안 유저 프로세스의 작업을 중단시키지 않는 방식이다.

    • 비동기(Asynchronous) 이란 I/O 작업이 진행되는 동안 유저 프로세스는 관심이 없다. 그저 자신의 일을 하다가 이벤트 핸들러에 의해 알림(notify)이 오면 처리하는 방식이다
  • 또한, NIO는 (버퍼, 채널, 셀렉터)를 이용해 성능이 좋다.

    • 버퍼 - 커널에 의해 관리되는 시스템 메모리를 직접 사용할 수 있는 Buffer 클래스

    • 채널 - 읽기, 쓰기 하나씩 쓸 수 있는 단반 향식 스트림, 채널은 읽기 쓸기 둘 다 가능한 양방향 입출력 클래스이다. 네이티브 IO, Scatter/Gatter 구현으로 효율적 IO처리 ( 시스템 콜 줄이기, 모아서 처리)

    • 셀렉터 - 네트워크 프로그래밍 효율을 높인다. 클라이언트 하나당 스레드 하나를 생성해서 처리하기에 스레드가 많이 생성 도리 수록 급격한 성능 저하를 가졌던 단점을 개선하는 Reactor패턴의 구현체

참조: https://www.slideshare.net/kslisenko/networking-in-java-with-nio-and-netty-76583794

 

  • NIO 서버 데이터 처리 순서
    • (Send)
      1. 1.  Selector(Acceptor Single Thread Queue)를 생성하고 SelectorChannel(ServerSocket)들을 등록(Write)한다. (이과정에서 Selector는 단일 스레드로 멀티스레드처럼 처리가 가능하는데 이동작이 multiplexing이라 할 수 있다. )

      2. 2.  Channel 들은 처리할 이벤트를 양방향 Buffer에 등록(Write)한다.

      3. 3.  Buffer는 해당 이벤트(notify)를 연관된 비즈니스 로직 or 연관된 시스템에게 보낸다.
    •  (Receive)
      1. 1.  비즈니스 로직 or 연관된 시스템이 처리한 데이터를 양방향 Buffer로 받는다. (이때 버퍼(가상 주소)를 사용하여 물리 메모리에 커널 영역의 가상 주소와 매핑시켜 커널 영역에서 유저 영역으로 데이터를 복사하지 않고 바로 참조한다. 즉, I/O 대기 없이 Non-Blocking방식으로 데이터를 처리한다.)

      2. 2.  Netty의 Channel 은 양방향 Buffer로부터 처리된 이벤트를 등록(Write)한다.

      3. 3.  클라이언트에서 요청이 오면 (큐에 있는 데이터를 기다리지 않고 비동기적 (이벤트 notify)으로 처리하는) Selector는 연관된 Channel을 찾아준다. (SelectionKey로 관리한다.)

      4. 4.  찾은 Channel에서는 처리된 이벤트를 클라이언트에게 회신한다.

      5. 5.  신규 클라이언트에서 요청이 오면 연관된 connection인 socket Channel을 Selector에 등록하여 비동기 Non-blocking 하게 데이터를 요청한다.

 

  • New I/O 향상을 위한 OS(운영체제) 수준의 기술
    • 1.  버퍼 사용
      • 데이터를 한 개씩 여러 번 반복적으로 전달하는 것보다 중간 버퍼를 두고 모아서 한 번에 전달한다.
        (커널 영역 버퍼에 직접 접근) 1바이트씩 읽기, 한 줄씩 읽기, 파일 단위로 한 번에 읽기 차이

      • 파일을 버퍼를 이용해서 읽는 이유는 문자를 효율적으로 입출력하여 CPU 부하를 줄일 수 있기 때문이다. 한 글자 읽을 때마다 출력 입력하면 cpu block이 발생하여 느리다.

      • 보통 Java에서 한 문자씩 읽는 게 아니면 다 String으로 읽는다. 한 문장씩 읽는 것과 한 번에 읽는 것의 차이는 파일의 내용을 다 읽어서 이미 메모리에 가지고 있는지 없는지 확인한다.

    • 2.  Scatter/Gather 사용
      • 자바 안에서 여러 버퍼를 만들어 사용하는데 만약 동시에 각각 버퍼에 데이터를 쓰거나 읽는다면 시스템 콜을 여러 번 불러서 읽거나 쓰게 된다.

      • 시스템 콜(커널 영역에 접근, 파일 IO)을 호출하는 것은 가벼운 작업이 아니므로 비효율적인데,
        Scatter와 Gather는 프로세스에서 사용한 버퍼 목록들을 한 번에 넘긴다.
      • 즉, 운영체제에선 최적화된 로직에 따라 버퍼들을 순차적으로 데이터를 읽고 쓰는 기능이다.

    • 3.  가상 메모리는 프로그램이 사용할 수 있는 주소 공간을 늘리기 위해 운영체제에서 지원하는 기술.
      • 실제 프로그램이 실행되는 필요한 페이지(단위)의 가상 주소만 물리 메모리에 넣는다.

      • 장점 2가지를 얻는데, 실제 메모리 크기보다 큰 가상 메모리 공간을 사용 가능,
      • 다른 하나는 여러 개의 가상 주소가 하나의 물리 메모리를 참조함으로 메모리를 효율적 접근 가능.

NIO 데이터 처리시 처리할 데이터를 가상 버퍼에 넣음으로 Zero-copy하여 NonBlocking 방식으로 처리한다.

  • 즉, 유저 영역의 양방향 버퍼의 가상 주소와 커널 영역의 가상 주소가 같은 물리 메모리를 참조하게 매핑시키면 커널 영역에서 유저 영역으로 데이터를 복사하지 않아도 된다. CPU의 Blocking 대기 시간이 걸리지 않는다.
    네티 인 액션 책에선 해당 OS기술을 Zero-Copy라고 부른다.

  • 4. 메모리 맵 파일
    • 유저 가상 메모리와 커널 가상 메모리가 보는 물리메모리 중 디스크의 내용까지 일치시키는 기술이다.

  • 5. 파일락
    • 스레드 동기화와 비슷한 개념 어떤 프로세스가 어떤 파일에 락을 획득했을 때, 다른 프로세스가 파일을 동시에 접근하지 못하게 제한하는 기술이다.
    • 이때 파일 전체 혹은 일부분을 잠가서 사용하는데 바이트 단위로 계산해서 잠금 부분을 계산한다.
    • 일부분만 잠가서 사용함으로써 락이 설정되지 않은 다른 위치에서 여러 프로세스들이 동시에 다른 작업을 할 수 있다.

'JAVA' 카테고리의 다른 글

추상화, 상속, 객체지향의 장점  (0) 2020.08.11
다형성이란?  (0) 2020.08.11
캡슐화란?  (0) 2020.08.11
빌드 도구, Maven 이란?  (0) 2020.08.08
GC(Garbage Collector)이란?  (0) 2020.08.07

+ Recent posts