[JAVA] IO vs NIO


OverView


開発者として、Input/Outputデータの処理は一般的なタスクの1つです.
JavaはI/Oパッケージをサポートしてこれらの入出力を処理するが、JVM上の操作特性のため、メモリを直接管理してシステムリソースを利用したり、オペレーティングシステムレベルのAPIを直接呼び出したりすることはないため、C、C++言語と比較して最も異なる点である.
そこで、Java 4からは新しいI/Oを表すNIOパッケージが含まれており、Java IOとNIOが一致しないクラスを修正し、非同期チャネル性能を向上させたNIO 2パッケージがJava 7に既存のNIOサブパッケージに含まれている

IO vs NIO


IO入出力StreamChannelバッファを区別バッファなしバッファ非同期XサポートOブロック/ブロックなし/ブロックなし

IO(java.io)キーコンセプト


1. Stream
Streamとは、配列や文字列などのデータの集合を指し、データの入力と出力に使用されます.
プログラムとI/O機器の間でI/Oデータを転送する
1バイトのデータを一度に転送すると、入力ストリームと出力ストリームが分離されます.
Input Streamを作成してデータを読み込み、Output Streamを作成してデータを出力する必要があります.
2. Blocking mode
read()、write()を実行すると、書き込むデータがあるまでブロックされます.
IO Threadがブロックされている場合、他のことはできません.ブロックを終了するために中断することはできません.唯一の方法はストリームを閉じることです.
ex) IO blocking example
InputStream inputstream = new FileInputStream("input-text.txt");

int data = inputstream.read(); // Blocking!
while(data != -1) {
  doSomethingWithData(data);
  data = inputstream.read();
}
inputstream.close();

NIO(java.nio)キーコンセプト


1. Buffer
データブロックを転送するための一時記憶装置は、基本的にI/O転送速度の差を補うための性能である.入力速度に比べて出力速度が遅い場合、効率を上げるために一時的にデータを格納するスペース.

2. Channel
Streamとは異なり、同時に読み書きが可能なI/Oクラスです.
データを交換するために、Threadとデータに入るバッファとの間にトンネルが確立される.
また、本機IO、Scatter/Gatterは、効率的なIO処理を実現します.(集約処理-->システムコールの削減)

3. Non-blocking mode
これはI/O操作時にThreadがブロックされない特性です.
NIOにおける非ブロッキングは、I/O操作の準備ができているチャネルを選択することによってのみ操作スレッドによって処理されるため、操作スレッドはブロックされない.<-> NIO에서 블로킹은, IO와 달리 Thread를 interrupt 함으로써 빠져나올 수 있다.4. CharsetDecoder
読み取り可能文字と元のバイトマッピング(エンコーダ、decorder api)
5. Selector
NIO nonブロックのキーオブジェクト
SelectableChannelで多重化を有効にし、I/Oが用意されているすべてのチャネルへのアクセスを提供します.
Selectorに複数のchannelを登録し、selectを実行して入力/書き込み可能なchannelを返します.
すなわち、1つのスレッドは、複数の入力チャネルを監視することができる.

NIO server Achitecture



NIO Serverデータ処理手順


[Send]

  • コレクタ単一スレッドキューを作成し、セレクタにチャネルを登録します.この過程で,セレクタは単一スレッドであり,マルチスレッドのように処理でき,移動操作は多重化といえる.

  • チャネルは、処理するイベントを双方向バッファ(書き込み)に登録します.

  • Bufferは、関連するビジネスロジックまたは関連するシステムにイベント(notify)を送信します.
  • [Receive]

  • ビジネスロジックまたは関連システムによって処理されるデータを双方向バッファとして受信する.이때 버퍼(가상 주소)를 사용하여 물리 메모리에 커널 영역의 가상 주소와 매핑시켜 커널 영역에서 유저 영역으로 데이터를 복사하지 않고 바로 참조한다. --> zero copy!!


  • Nettyのチャネルは、双方向バッファから処理されたイベントを登録します.

  • クライアントがリクエストを発行すると、セレクタは関連するチャネルを検索します.(SelectonKeyが管理しています.)

  • 見つかったチャネルは、処理されたイベントをクライアントに返します.

  • 新しいクライアントが要求を発行する場合は、セレクタに関連する接続socketチャネルを登録して、非同期でブロックなくデータを要求します.
  • NIO File read

    public static void main(String[] args) {
    	Path path = Paths.get("file.txt");
        
        // 채널 객체를 파일 읽기 모드로 생성.
        try (FileChannel ch = FileChannel.open(path, StandardOpenOption.READ)) {
            // 1024 바이트 크기를 가진 Buffer 객체 생성
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            ch.read(buffer);
    
            buffer.flip();
            Charset charset = Charset.defaultCharset();
            String inputData = charset.decode(buffer).toString();
    
            buffer.clear();
        } catch (Exception e) {
             e.printStackTrace();
        }
    }

    NIO File write

    public static void main(String[] args) {
        Path path = Paths.get("file.txt");
    
        try (FileChannel ch = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
            String data = "우가1999";
            Charset charset = Charset.defaultCharset();
            ByteBuffer buffer = charset.encode(data);
            ch.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

    IOとNIOの選択


    NIOは1つのスレッドを使用して複数のチャネルを管理できるため、伸縮性は良好であるが、非ブロッキング特性を使用してデータを処理するとより複雑になる可能性がある.
    少量のデータを送信するたびに数千の接続(ex:chat server)を同時に管理する必要がある場合は、NIOを使用してサーバを実装するとさらにメリットがあります.同様に、他のコンピュータと複数のオープン接続を維持する必要がある場合、外部接続を1つのスレッドとして管理することがより有利である.

    ただし、接続クライアント数が少なく、転送されるデータ量が多く、順序で処理する必要がある場合は、IO実装サーバを使用することが望ましい.
    NIOのバッファ割り当てサイズにも問題が発生し、受信したインスタント処理IOよりも複雑なすべてのI/O操作でバッファを使用する必要があります.

    ref
  • https://www.baeldung.com/java-io-vs-nio
  • https://brunch.co.kr/@myner/47
  • https://dev-coco.tistory.com/42
  • https://altongmon.tistory.com/284
  • https://junshock5.tistory.com/149