똥 인진 된장인지 모르고 헤쳐 나가고 있습니다. 파일 관련 문제를 해결 하던 중 nio란걸 찾았습니다.
얼마나 무식 했던지, 이런걸 남들은 애저녁에 해쳐 나간걸 이제서야 나중에 또 찾아 보려 정리 하면서
써먹고 있습니다. 아직 정확히 이해도 않된 상태에서 헤메이고 있습니다. 오우 ~ 쥐좌쑤~
자바(JAVA) NIO 패키지 소개
1. nio 패키지 소개
New I/O는 JDK1.4에서 새로 추가된 패키지이다. JDK1.4의 정식 명칭은 Java 2 Standard Edition JDK1.4이다. 흔히 Meriln이라고 부르는데 이는 개발시 프로젝트의 이름이다. 참고로 Meriln은 중세시대 아더왕의 전설에 나오는 마법사의 이름이기도 하지만 쇠황조롱이라는 매의 일종인 새의 이름이기도 하다.
New I/O는 java.nio 패키지로 제공되는 기능으로 크게 버퍼 관리 클래스류, 확장된 네트워크 그리고 파일 I/O, 문자 집합 지원, 그리고 정규식 문자 표현에 새로운 특징들과 개선된 성능을 제공한다. java.nio 패키지는 다음과 같은 클래스류로 나누어진다.
- java.nio
- java.nio.channels
- java.nio.channels.spi
- java.nio.charset
- java.nio.charset.spi
여기서 spi가 붙은 것을 볼 수 있는데 이는 SPI(Service Provider Interface)로 프로그래머가 제공하는 클래스로 대체할 수 있는 기능을 제공해준다. 이는 관련된 클래스들의 기본 구현을 프로그래머가 바꿀 수 있다는 뜻이 된다. 단, 이것은 특별한 경우에만 해당되므로 이런 것이 있다는 정도만 알아두자.
1> 특징.
- 기본 데이터형용 버퍼를 클래스로 제공해 준다.
- Character-set 인코더들과 디코더.
- 패턴과 어울린 기능은 Perl-style 정규식들로 설정.
- 채널, 새로운 I/O 추상화.
- 메모리 매핑과 파일의 lock(잡금장치)를 지원해주는 인터페이스.
- non-blocking 입출력이 가능.
2> 패키지 소개
- java.nio.package : 자바 기본형 유형에 맞는 버퍼 클래스들.
- java.nio.channels.package : 채널과 셀렉터.
- java.nio.charset.package : 문자 암호화들.
- java.nio.channels.spi.package : Service 프로바이더는 채널들을 위해 분류.
- java.nio.charset.spi.package : Service 프로바이더는 문자셑를 위해 분류.
- java.util.regex.package : 정규식들에 의해서 지정된 패턴들에 대해서 문자 표현에 대한 클래스들.
- java.lang.CharSequence.인터페이스 : 다양한 종류의 문자 순서에의 통일된 read 전용 액세스를 제공.
3> 정리
java.nio 패키지에서 눈여겨 봐둘것은 지금까지 지원이 되지 않았던 io의 nonblocking의 지원이다. 이러한 nonblocking의 지원으로 주요한 장점은 크게 다음 두가지이다.
- 스레드는 더이상 읽기나 쓰기에 블록킹되지 않는다.
- selector의 도입으로 클라이언트의 많은 접속을 처리할 서버의 부하가 상당히 줄어든다.
그리고 또 다른 한가지 java.nio 패키지에서 네트워크 기능이 강화 되었다. 채널의 도입으로 새롭게 강화된 네트워크를 다루려면 반드시 java.net 패키지의 이해는 필수이다.
==> 여기서는 nio패키지를 크게 두부분으로 나누어서 강좌를 할 예정이다. 하나는 java.nio의 Buffer류 클래스와 java.nio의 Channels 클래스이다.
[자바 IO와 NIO의 차이점]
스트림을 중심으로 하는 자바에서 기존 입출력(IO)은 블로킹 모드입니다.
Blocking은 자바의 Synchronized 키워드와 같다고 생각하면 이해가 쉽습니다.
즉, 어떤 작업을 하기 위해 먼저 접근한 요청이 다 끝나기 전에는 뒤이어 접급한 요청들은 먼저 들어온 요청이 다 끝나기를 기다려야 하는 것인데 만약 앞선 요청이 어떤 문제점에 의해 완전히 처리되지 않고 블럭된 상태로 있게 된다면 뒤이은 요청들은 영원히 앞선 요청이 끝나기만을 기다릴 것입니다. 이에 반해 Non-Blocking은 들어온 요청을 바로 처리하는 것인데 앞선 요청이 다 끝나기를 기다리지 않아도 된다는 것입니다.
1) Blocking 모드의 단점
보통 IO에서는 서버에 접속해서 accept()를 호출하는 부분에서 블러킹이 발생한다.
만약 어떤 클라이언트가 accept()를 호출하면 뒤이어 이 서버 소켓으로 접속한 클라이언트는 먼저 접속한 클라이언트의 요청이 다 처리되기를 기다려야하고 또한 동시에 여러 클라이언트들의 요청을 처리하기 위해서 별도의 스레드로 Service 클래스를 만들어서 처리하는데, 이것은 사용자가 늘어날 경우 클라이언트 한 명마다 하나의 스레드를 할당해주는 형태가 되므로 스레드 과부하를 가져오게 된다. (서버가 느려지는 현상)
2) Blocking 모드로 인한 스레드의 과다 생성
스레드는 그 자체적으로도 생성하는데 시간이 걸리는 느린 작업이기도 하고 각각의 쓰레드들이 자신만의 고유한 스택(Stack) 영역과 CPU를 점유해서 사용하기 때문에 많은 스레드를 생성해야하는 서버는 메모리와 CPU를 효율적으로 사용하지 못하게 되고 클라이언트들의 동시 처리를 위해 생성된 Service 스레드들이 대부분의 처리 시간을 요청/응답의 블러킹 부분에서 소비한다는 것도 문제점이다.
그리고 결정적으로 하나의 JVM은 몇 백개까지의 스레드를 생성해서 운영할 수 있지만 수 천개의 스레드를 생성할 수는 없다. 또한 시스템에 따라 그 시점은 다르지만 대개의 경우 특정 개수 이상의 스레드를 생성하면 급격한 성능 저하를 보이기도 하기 때문이다.
3) Blocking 모드의 대안으로써의 NIO
NIO에서는 accept()와 클라이언트의 요청/응답에 대해 블러킹이 없다. 이것을 가능하게한 것은 채널(Channel) 인터페이스를 구현하는 SelectableChannel이라는 새로운 클래스를 Non-Blocking으로 설정함으로써 accept()에 대한 블러킹을 피할 수 있도록 했고, Buffer라는 새로운 클래스의 도입으로 입출력 작업에서 블러킹을 피하고 기존 IO에서의 Stream간의 데이터 복사에 의한 가비지 생성을 예방함으로써 효율적인 버퍼링이 가능해졌다. 또한 채널과 버퍼(Direct Buffer)는 네이티브 접근을 함으로써 기존의 동기식 서버보다 훨씬 나은 성능을 갖출 수 있다.
* 버퍼
버퍼는 위에서 말했듯이 잦은 입출력으로 인한 가비지 콜렉팅을 발생하기 때문에 성능이 떨어지게 되는데 이에 대한 대안으로 나온 것이 버퍼이다. 기본적으로 일정한 영역에 버퍼의 메모리를 할당하고 미리 할당한 부분에서만 데이터의 입출력을 처리한다.
* 채널
기존에 IO방식에서는 버퍼에 접근이 불가능하고 이에 버퍼에 접근하는 입출력 구조가 필요하여 만들어진 것이 바로 채널이다. 버퍼를 입출력하기 위한 구조가 채널이다.
* 셀렉터
자신에게 등록한 서버 소켓 채널과 소켓 채널을 위해 대신 통신 선로를 감시하고 통신 선로에서 각 채널이 등록한 동작이 들어오면 해당 채널에게 알려준다. 이를 통하여 Non-Blocking 모드를 할 수 있게 되면 Blocking 모드와 Non-Blocking 모드에 대한 설정도 셀렉터에서 한다.