Java I/O
이 질문에 답변 가능하신가요?
"서버에서 1GB 파일을 클라이언트에게 전송할때 발생하는 모든 I/O에 대해 설명해주세요."
스트림(Stream)의 정의와 종류
스트림은 프로그램에서 데이터를 순차적으로 읽고 쓰기 위해 사용되는 일련의 데이터 흐름입니다. 스트림은 데이터를 바이트 단위 또는 문자 단위로 처리할 수 있으며, 파일, 네트워크 소켓, 메모리 버퍼 등 다양한 데이터 소스와 대상에 대해 동일한 방식으로 작업할 수 있게 합니다. 스트림은 한 방향으로만 데이터가 흐릅니다 (읽기 전용 또는 쓰기 전용).
스트림의 종류
Byte Stream (바이트)
Character Stream (문자)
차이점
바이트 스트림은 바이너리 데이터를 처리하기 때문에 파일, 이미지, 오디오 등의 비텍스트 데이터(=바이너리 데이터)를 다루기에 적합합니다.
바이너리 데이터란? 이미지, 오디오, 비디오, 압축 파일
문자 스트림은 문자 데이터를 처리하기 때문에 텍스트 파일을 다루기에 적합합니다. 문자 스트림은 인코딩을 처리하여 문자 데이터를 올바르게 읽고 쓸 수 있게 합니다.
Byte Stream
바이트 단위로 데이터를 처리합니다. 주로 바이너리 데이터를 읽고 쓸 때 사용합니다.
입력 스트림 (Input Stream): 데이터를 읽어오는 스트림
InputStreamFileInputStreamByteArrayInputStreamObjectInputStream- 직렬화에 사용FilterInputStreamBufferedInputStreamDataInputStreamPushbackInputStream
출력 스트림 (Output Stream): 데이터를 쓰는 스트림
OutputStreamFileOutputStreamByteArrayOutputStreamObjectOutputStream- 직렬화에 사용FilterOutputStreamBufferedOutputStreamDataOutputStreamPrintStream
Character Stream
문자 단위로 데이터를 처리합니다. 주로 텍스트 데이터를 읽고 쓸 때 사용합니다.
입력 스트림 (Reader): 데이터를 문자 단위로 읽어오는 스트림
ReaderFileReaderCharArrayReaderBufferedReaderInputStreamReader(바이트 스트림을 문자 스트림으로 변환)StringReader
출력 스트림 (Writer): 데이터를 문자 단위로 쓰는 스트림
WriterFileWriterCharArrayWriterBufferedWriterOutputStreamWriter(바이트 스트림을 문자 스트림으로 변환)StringWriterPrintWriter
I/O 사례 (정리 잘해논 블로그 링크)
파일 입출력
예제 코드 - 바이트
FileInputStream,FileOutputStream이미지 파일 읽기 및 쓰기 예제
예제코드 - 텍스트
BufferedReader,BufferedWriter를 이용해 텍스트파일 복사 프로그램 예제
네트워크 I/O
예제 코드 - 텍스트
텍스트 파일만 받고 보낼때
BufferedReader,BufferedWriter이용아래 코드 실행 후 http://localhost:8080/?name=yoochul 접속
예제 코드 - 텍스트 + 바이트
바이너리 or 텍스트 모두 대응을 위해서는
DataOutputStream이용DataOutputStreamvsBufferedOutputStream기능적 차이
DataOutputStream: 기본 데이터 타입을 쉽게 기록할 수 있도록 메서드를 제공합니다.BufferedOutputStream: 버퍼링을 통해 성능을 최적화합니다.
사용 목적:
DataOutputStream: 데이터 형식에 따른 정확한 기록이 필요할 때 사용됩니다.BufferedOutputStream: 빈번한 I/O 작업을 최적화할 때 사용됩니다.
조합 사용:
두 클래스를 조합하여 사용할 수 있습니다. 예를 들어, 데이터 타입을 기록하면서 버퍼링의 이점을 얻기 위해
BufferedOutputStream을DataOutputStream의 하위 스트림으로 사용할 수 있습니다. 예시:
예제 코드 - 나의 실수
과제할때 텍스트 전송 API를 이용하는데 이미지가 전달이 안되서 Base64로 바꿔서 보냈었던것 같다.
객체 직렬화
예제 코드
ObjectOutputStream이용한 직렬화와 역직렬화 예제
NIO (New I/O)
NIO란?
NIO(New Input/Output)는 Java 1.4부터 도입된 패키지(
java.nio및 관련 서브패키지)로, 더 효율적이고 확장 가능한 I/O 작업을 지원하기 위해 설계되었습니다. NIO는 비동기 I/O와 채널-버퍼 기반 I/O를 제공합니다. 이를 통해 기존의 블로킹 I/O 방식보다 높은 성능과 유연성을 제공합니다.
기존 I/O와의 차이점
블로킹 vs 논블로킹 I/O:
기존 I/O (java.io): 기본적으로 블로킹 I/O 모델을 사용합니다. 즉, I/O 작업이 완료될 때까지 스레드가 블로킹됩니다.
NIO (java.nio): 논블로킹 I/O 모델을 지원합니다. 즉, I/O 작업이 즉시 완료되지 않아도 스레드가 블로킹되지 않습니다.
스트림(Stream) vs 채널(Channel):
기존 I/O: 스트림 기반입니다. 데이터를 읽고 쓰기 위해 InputStream과 OutputStream을 사용합니다.
NIO: 채널 기반입니다. 데이터는 채널을 통해 읽고 쓰며, 채널은 버퍼와 직접 상호작용합니다.
버퍼(Buffer):
기존 I/O: 데이터를 읽고 쓸 때 중간 저장소로서의 버퍼를 명시적으로 사용하지 않습니다.
NIO: 데이터는 항상 버퍼를 통해 읽고 쓰입니다. 버퍼는 고정 크기의 메모리 블록으로, 데이터를 효과적으로 관리합니다.
비동기 처리:
기존 I/O: 비동기 처리를 지원하지 않습니다.
NIO: 셀렉터(Selector)를 통해 비동기 I/O 작업을 관리할 수 있습니다. 셀렉터는 여러 채널의 I/O 상태를 모니터링하여 비동기적으로 작업을 처리합니다.
버퍼(Buffer)와 채널(Channel)
버퍼 (Buffer)
버퍼는 고정 크기의 메모리 블록으로, NIO에서 데이터를 읽고 쓰는 데 사용됩니다. 버퍼는 데이터의 일시적 저장소 역할을 합니다. 주로 사용되는 버퍼 타입은 다음과 같습니다:
ByteBufferCharBufferShortBufferIntBufferLongBufferFloatBufferDoubleBuffer
채널 (Channel)
채널은 I/O 작업을 위한 데이터의 통로 역할을 합니다. 채널은 비동기 I/O 작업을 지원하며, 항상 버퍼와 상호작용합니다. 주요 채널 타입은 다음과 같습니다:
FileChannel: 파일의 데이터를 읽고 씁니다.SocketChannel: TCP 소켓의 데이터를 읽고 씁니다.ServerSocketChannel: TCP 소켓에 연결된 클라이언트를 수신합니다.DatagramChannel: UDP 소켓의 데이터를 읽고 씁니다.
예제 코드
NIO를 이용한 파일 처리 및 네트워크 통신 예제:
NIO 이용한 파일 처리 예제
NIO 이용한 네트워크 통신 예제
비동기 I/O (Asynchronous I/O)
Java 7에서 도입된 NIO.2는 비동기 I/O 작업을 지원하는 java.nio.channels 패키지를 제공합니다. 주요 클래스는 다음과 같습니다:
AsynchronousFileChannel: 비동기적으로 파일을 읽고 쓰기 위한 채널입니다.AsynchronousSocketChannel: 비동기적으로 소켓을 통한 네트워크 연결을 처리합니다. 비동기 작업의 결과는 Future 객체나 CompletionHandler 인터페이스를 통해 받을 수 있습니다.AsynchronousServerSocketChannel
비동기 I/O의 개념
비동기 I/O는 입력 또는 출력 작업이 즉시 반환되고, 실제 작업 완료는 별도의 이벤트나 콜백을 통해 비동기적으로 처리되는 방식입니다. 비동기 I/O는 프로그램이 I/O 작업이 완료될 때까지 기다릴 필요가 없게 하여, 자원을 보다 효율적으로 사용할 수 있게 합니다.
필요성
성능 향상: 블로킹 I/O는 I/O 작업이 완료될 때까지 스레드가 멈추는 반면, 비동기 I/O는 작업이 백그라운드에서 진행되므로 CPU 자원을 보다 효율적으로 사용할 수 있습니다.
스케일링: 많은 클라이언트와의 연결을 동시에 처리해야 하는 서버 애플리케이션에서 비동기 I/O는 스레드 수를 줄이고, 컨텍스트 스위칭 비용을 감소시켜 확장성을 높입니다.
사용자 경험: 사용자 인터페이스에서 I/O 작업이 사용자 경험을 방해하지 않도록 비동기 I/O를 사용하면 응답성이 향상됩니다.
예제 코드
AsynchronousFileChannel 비동기 파일 읽기/쓰기 예제 코드:
Asynchronous I/O와 New I/O 주요 차이점비동기 I/O와 New I/O는 모두 자바에서 효율적인 I/O 처리를 제공하지만, 접근 방식과 사용 사례가 다릅니다. 비동기 I/O는 주로 NIO.2에서 제공되며, 작업 완료 시 콜백 또는 Future 객체를 사용하여 알림을 받습니다. 반면, New I/O는 NIO 패키지에서 제공되며, 논블로킹 I/O와 선택기(Selector)를 사용하여 여러 채널의 상태를 관리합니다. 애플리케이션의 요구사항에 따라 적절한 방법을 선택하는 것이 중요합니다.
도입된 자바 버전
Java 7 (NIO.2)
Java 1.4
기본 개념
비동기 I/O (I/O 작업 완료 시 알림)
논블로킹 I/O 및 선택기(Selector)
제어권 반환
즉시 제어권 반환
즉시 제어권 반환
알림 방식
콜백 함수, Future 객체 등
선택기를 통한 상태 확인
주요 클래스
AsynchronousFileChannel, AsynchronousSocketChannel
FileChannel, SocketChannel, Selector, ByteBuffer
주요 용도
고성능 서버, 대규모 데이터 처리
고성능 서버, 대규모 네트워크 응용 프로그램
코드 복잡성
높음 (복잡한 흐름 제어)
높음 (상태 확인 및 처리)
I/O 성능 최적화 방법들
I/O 성능 개선을 위한 팁과 트릭
버퍼링 (Buffering): 데이터를 한 번에 큰 덩어리로 읽고 쓰는 방식으로, I/O 작업의 빈도를 줄여 성능을 향상시킵니다.
BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter
비동기 I/O (Asynchronous I/O): 입출력 작업이 완료될 때까지 블로킹되지 않으며, 이를 통해 다른 작업을 동시에 수행할 수 있습니다.
NIO.2:
AsynchronousFileChannel,AsynchronousSocketChannel
메모리 매핑 (Memory Mapped I/O): 메모리 맵 파일 (Memory-Mapped File)은 파일 내용을 메모리에 직접 매핑하여, 디스크 I/O를 최소화하고 매우 빠른 파일 접근을 가능하게 합니다. 메모리 맵 파일은 대용량 파일 처리나 파일에 대한 랜덤 액세스가 빈번한 경우에 특히 유용합니다.
Java NIO:
MappedByteBuffer를 사용하여 파일을 메모리에 매핑합니다.
Direct Buffer 사용: Direct Buffer는 JVM 힙 외부의 메모리를 사용하여 I/O 성능을 향상시킵니다. Java NIO의
ByteBuffer를 사용할 때allocateDirect메서드를 사용하면 됩니다.병렬 처리 (Parallel Processing)
파일 채널 (FileChannel):
FileChannel을 사용하여 파일 복사 작업을 최적화할 수 있습니다.프로파일링과 튜닝: 애플리케이션의 I/O 성능 병목을 식별하기 위해 프로파일링 도구를 사용합니다. 이를 통해 I/O 작업의 성능을 모니터링하고 최적화할 수 있습니다.
Java Flight Recorder (JFR): JDK에서 제공하는 프로파일링 도구로, 애플리케이션의 성능을 분석할 수 있습니다.
java -XX:StartFlightRecording=filename=recording.jfr,dumponexit=true,settings=profile MyApp
네트워크 I/O 최적화:
Nagle's Algorithm 비활성화: TCP_NODELAY 옵션을 사용하여 작은 패킷을 즉시 전송합니다.
socket.setTcpNoDelay(true);
TODO: 실제 사례 실험해보기
위에 성능 최적화 팁들 이용해서 최적의 성능 찾아보기
워밍업
클라이언트 - 서버 구조의 간단한 이미지와 텍스트 파일 업로드/다운로드 구현
대용량 텍스트 테스트
1GB 대용량 csv 파일 / 1000명 동시 요청
압축해서 전송 시간 테스트
스트림 방식 vs 한번에 전송 테스트
대용량 이미지 테스트
8K 고화질 이미지 / 1000명 동시 요청
Last updated



