IO로 인해 발생하는 병목 현상

📌 IO(Input Output)

IO는 무엇일까?

입력과 출력의 약자이다.
자바에서 IO는 스트림을 통해 이루어진다.
파일 IO뿐만 아니라, 어떤 디바이스를 통해 이루어지는 작업 모두 IO라고 한다.
콘솔에 출력하는 것도 스트림을 통해 출력하는 것이다.
System.out.println("Hello World");
out은 PrintStream을 System에 static으로 정의한 변수이다.

IO는 운영체제에서 어떻게 수행되는가?

하드 디스크에 있는 데이터를 읽어오려면, 어떻게 수행되는지 보면 아래와 같은 순서로 수행된다.
1.
자바에서 메서드를 호출한다.
2.
파일을 읽어오는 메서드에서 운영체제의 커널에 파일을 읽어달라고 요청한다.
3.
커널이 하드 디스크로부터 파일을 읽어, 자신의 커널에 있는 버퍼에 복사한다. (DMA에서 수행)
4.
JVM으로 데이터를 전달한다.
5.
스트림 클래스로 데이터를 처리한다.

스트림(Stream) 클래스에는 어떤 것이 있을까?

주요 클래스 모음

IO는 어떤 문제점이 있을까?

IO에서 발생하는 시간은 CPU를 대기하는 시간에 속한다. (사용하는 시간과 대기 시간 중) 따라서 IO는 성능에 가장 영향을 많이 미친다.
IO와 관련된 디바이스가 느리면 애플리케이션 속도도 느려진다.

무엇을 주의해야 하고, 어떻게 개선할까?

주의점

한 번 열었던 스트림은 반드시 닫아줘야 한다. 리소스가 부족해질 수 있다.
File 클래스의 lastModified() 메서드는 주의해야 한다.
속도에서 큰 문제가 있는 것은 아니지만, IO 작업을 수반한다.
따라서 OS의 IO의 영향을 많이 받을 수 밖에 없다.

개선하기

파일 처리할 때 되도록 IOException을 따라 구분하여 처리하는 것이 좋다.
FileReader로 파일을 읽어와야 할 때, BufferedReader를 사용하는 것이 가장 빠르다.
BuffredReader br = new BufferedReader(new FileReader(fileName));
Java
버퍼 없이 FileReader를 사용하는 것이 가장 느렸고, 그 다음으로 버퍼 포함한 FileReader가 빠르고, 가장 빠른 것은 BufferedReader를 사용한 것이 가장 빨랐다.
많은 IO 작업을 수행한다면, 데몬 스레드(Daemon Thread)를 하나 생성하는 것도 방법이다.
💡
데몬 스레드(Daemon Thread)? 일반 스레드의 작업을 보조적인 역할을 수행하는 스레드를 말한다.

📌 NIO(New IO)

JDK 1.4부터 추가되었다.
커널이 하드 디스크로부터 파일을 읽어, 자신의 커널에 있는 버퍼에 복사하는 과정에서 대기 시간이 발생하는데 이런 단점을 보완하기 위해 NIO가 등장했다.

NIO에서 추가된 개념

버퍼 도입
채널 도입
문자열의 엔코더와 디코더 제공
Perl 스타일의 정규 표현식에 기초한 패턴 매칭 방법 제공
파일을 잠그거나 메모리 패핑이 가능한 파일 인터페이스 제공
서버를 위한 복합적인 Non-blocking IO 제공

주의할 점

NIO를 사용하면서 네트워크나 파일에 있는 데이터를 읽어 들일 때, ByteBuffer를 사용한다. 그러나 주의해야 할 점이 있다. allocateDirect() 메서드가 있는데 이는 자바 JVM에 올려서 사용하는 것이 아니라, OS 메모리에 할당된 메모리를 네이티브한 JNI로 처리하는 DirectByteBuffer 객체를 만든다. 따라고 해당 객체는 계속 생성하면 안된다. 사용하려면 싱글톤으로 만들어 하나의 객체를 활용하는 것이 낫다.

📌마무리

IO 작업은 잘못하면 전반적인 시스템 응답 속도에 많은 영향을 줄 수 있다.
필요없이 반복적으로 파일을 읽거나, 쓰도록 되어 있지 않은지 확인해야 한다.
내가 개발하는 시스템이 IO 관련 문제가 심각하다면, NIO에 대해 학습할 필요가 있다.
JDK 7 이상이라면 NIO2에서 추가된 기능을 확인해서 성능을 개선해보면 많은 도움이 될 수 있다.

📌 참고 자료

TOP