부제: NIO부터 Netty까지
Introduction
인터넷 사용 인구의 폭발적인 증가와 글로벌한 소셜서비스들로 인해 대용량 트래픽처리와 데이터캐싱, 비동기처리 등은
현대의 서버 개발환경에서 늘 마주하게 되는 주제들입니다.
5주차스터디에서는, JDK1.4+ 부터 제공되는 NIO와 이를 wrapping한 Netty를 학습하고, 효율적인 방법을 토론합니다.
JAVA IO 기본
- 스트림은 데이터 소스(File, DB, Socket)에 저장되어 있는 데이터를 다른 데이터 소스에 전달하고자 할 때 사용한다.
- 키보드의 입력을 모니터에 출력할 때도 스트림을 사용한다.
- stream 특징
- stream은 FIFO(first in first out, 선입선출)이다.
- stream은 단방향이다. 자바에서는 읽기와 쓰기가 동시에 되지 않기 때문에 입력 스트림과 출력 스트림을 각각 생성해야 한다.
- stream은 데이터 처리가 완료될 때까지 stream을 사용하는 스레드는 waiting 상태에 빠진다.
- Java IO의 기본 사용 예
- Java IO 패키지 Naming Rule
- InputStream, OutputStream이 포함된 클래스들은 byte단위의 입출력을 담당한다. 특성에 따라서 앞에 단어를 추가한다.
- - ex) FileInputStream file을 읽는 스트림, ByteArrayStream byteArray를 읽는 스트림
- Reader와 Writer는 2byte 문자단위의 입출력을 담당한다. 특성에 따라서 앞에 단어를 추가한다.
- Reader와 Writer를 사용하는 가장 큰 이유는 국제화이다. InputStream, OutputStream는 8비트 스트림만을 지원한다.
- c언어의 기본 문자셋으로 사용되는 ASCII와 자바에서 기본 문자셋으로 사용되는 Unicode의 차이에 대한 이해
- 동기화 문제
- 기본데이터타입을 사용할 때를 제외하고, 박싱하거나 레퍼런스 변수를 사용하는 경우 해당 변수 값들은 모두 힙에 저장되어 있다.
- 이때 힙에 저장되어 있는 녀석들을 'Object' 라고 부른다.
- 이 Object가 가지고 있는 변수 값들이 Multi-thread에 의해서 변경되려고 할 때 동기화 문제가 발생한다.
- 즉 동기화문제가 발생하는 최소 단위는 객체이다.
- 자바에서는 동기화 문제를 해결하기 위해서 모든 객체에 락을 포함시켰다.
- - 세마포어 http://ko.wikipedia.org/wiki/%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4
- 락은 객체에 여러 스레드가 동시에 접근하는 것을 방지하기 위한 것으로 힙 영역에 객체가 저장될 때 자동으로 생성된다.
- 락의 사용
- - Synchronized 키워드를 사용한다.
- Socket 에 대한 언급필요한가??
- Input,Output.pdf : 스트림 개념, 자바의 Input과 Output과 관련하여 대략적으로 정리한 문서
Java IO 성능 이슈
기존의 자바 IO는 커널 버퍼를 직접 핸들링 할 수 없어서 느리다.
- 소켓이나 파일에서 stream을 읽으면 커널 버퍼에 쓰여지게 된다. 그런데 자바 코드에서는 이 커널 버퍼에 직접 접근할 수 없다. 이 커널 버퍼의 데이터는 다시 JVM 내부 메모리에 불러온 후에야 접근할 수 있다.
- 즉, 커널에서 JVM 내부 메모리로 복사하는데 상당한 오버헤드가 발생한다.
- 기본의 Java가 디스크에서 파일을 읽는 과정은 다음과 같다.
- Process(JVM)이 file을 읽기 위해 kernel에 명령을 전달
- Kernel은 시스템 콜(read())을 사용하
- 디스크 컨트롤러가 물리적 디스크로 부터 파일을 읽어옴
- DMA를 이용하여 kernel 버퍼로 복사
- Process(JVM)내부 버퍼로 복사
- 따라서 다음 과 같은 문제점 이 생길 수 있죠.
- JVM 내부 버퍼로 복사할 때, CPU가 관여
- 복사 Buffer 활용 후 GC 대상이 됨
- 복사가 진행중인 동안 I/O요청한 Thread가 Blocking
- 위 와 같은 오버헤드가 생길 수 있습니다. 이에 대해 자세히 알아보도록 하겠습니다.
기존 자바 IO는 Blocking IO 라서 느리다!
- Thread에서 블로킹이 발생하기 때문에 느리다.
- 기존 Java I/O로는 끔찍하게 비효율적인 Server Program(네트워크 서버)을 만든다.
- 기존 I/O의 Server는 블로킹 되므로 느리다.
- 클라이언트 접속할 때마다 Thread가 생성됩니다.
Thread와 동시성 문제
Thread Life Cycle
JAVA NIO(new IO)
개요 ? Non-blocking I/O
NIO는 왜 등장한 것인가?
Channel
NIO는 기존의 Java I/O보다 왜 더 빠른가?
NIO는 Direct Buffer 로 커널 버퍼를 직접 핸들링하기 때문에 빠르다!
- NIO에서는 커널 버퍼를 직접 이용할 수 있게 해주는 Buffer Class를 지원한다! 커널 버퍼를 직접 이용할수 있는건 ByteBuffer.directAllocate(SIZE); 로 생생된 ByteBuffer뿐이며, 다른 Buffer들은 기존의 방식과 똑같다.
NIO에서 System Call을 간접적으로 사용가능하게 해주기 때문에 빠르다!
- c나 c++로 만들어진 Server Program은 Thread를 생성하지 않고도 많은 수의 클라이언트를 처리할 수 있습니다. 이를 가능케 해주는 것이 OS 레벨에서 지원하는 Scatter/Gather 기술과 Select() 시스템 콜입니다. Scatter/Gather은 시스템콜의 수를 줄이는 기술인데요, 덕분에 I/O를 빠르게 만들 수 있죠.
- 이런 것을 가능하게 해주는 Class가 바로 Channel과 Selector입니다.
NIO 사용하기
Reactor Pattern
네트워크 개발 패턴
Netty
NIO기반의 라이브러리
NIO 참고 문서
Java IO, NIO에 대한 초간단 예제
윈도우즈 파일시스템 이론
http://cappleblog.co.kr/538
윈도우즈 8 파일시스템 refs
http://www.infoq.com/news/2012/01/ReFS
Java IO로 파일 읽고, 쓰기(또는 다른 예제)
- 기존에 이미 많이 사용한 경험이 있다.
- 파일 읽고, 쓰는 정도의 간단한 예제면 충분하지 않을까?
Java NIO로
웹 서버 구현
프로세스(Process): 컴퓨터에서 연속적으로 실행되고 있는 프로그램을 말하는 것으로 여러개의 프로세서를 사용하면 멀티프로세싱이고 여러개의 프로그램을 같은 시간에 시분할 방식으로 돌리면 멀티태스킹이라 말한다.
쓰레드(Thread): 프로세스내에서 실행되는 흐름의 단위를 말하는 것으로 하나의 프로그램은 최소한 하나의 쓰레드(main thread)를 가진다. 프로그램에 따라 둘 이상의 쓰레드를 동시에 실행할수 있는데 이를 멀티쓰레드라고 부른다.
Java 기본 IO를 활용한 웹 서버 구현
public class StudyServer {
private String final int PORT = 8080;
public static void main(String ar[])throws IOException{
//서버생성
HttpServer server = HttpServer.create(new InetSocketAddress(PORT) , 0);
//context생성
server.createContext("/study", new WebServerHandler());
server.start();
System.out.println("server started..");
}
private static class WebServerHandler implements HttpHandler{
public void Handle(HttpExchange t) throws IOException{
System.out.println("Accepted");
String response ="i `m web server";
t.sendResponseHandlers(HttpURLConnection.HTTP_OK.response.lengh() );
OutputStream os = t.getResponseBody();
os.write( response.getBytes() );
System.out.println("complete");
os.close();
}
}
} |
Java NIO를 활용한 웹 서버 구현
실습계획
- 다음과 같이 진행해 보면 어떨까?
- github 어딘가에 아래와 같은 템플릿 소스 코드
- 1단계 : Java IO를 활용해 Web Server 구현
- 짝 끼리 서버 / 클라 번갈아가면서 실습
- 네트윅은 짝끼리 무조건 되게 하는 걸로.. 그런걸로...
- 예제를 확장하거나.. 통신스펙을 보고 직접 만들거나
- 2단계 : Java NIO를 활용해 Web Server 구현(실습 시간이 너무 길어질 경우 이 단계는 데모로만 구현해도 좋지 않을까?)
- Java IO로 구현한 예제를 Java NIO로 구현
- 3단계 : Netty를 활용해 Web Server 구현
sllip study.pptx
서버를 만들기 위한 Tip
- 종료처리 (addShutdownHook)
- 쓰레드의 작동이 끝났을 때
- 프로그램이 종료되었을 때
- 사용자가 CTRL + C를 눌렀을 때
- 운영체제가 종료되거나 사용자가 Log Off해서 세션이 더 이상 존재하지 않을 때
- java.lang.Runtime.addShutdownHook
- runFinalizersOnExit 은 종료 시에 안정성을 이유로 deprecated 되었음.
public class ShutdownTutorial {
public void addShutdownHandler() {
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run(){
System.out.println("프로그램이 종료되었을 때 동작합니다.");
@Todo
//사용자 최종 변경 내역 저장, 로그 저장 , 최종 세션 저장
}
});
}
public static void main(String ar[]){
ShutdownTutorial tutorial = new ShutdownTutorial();
tutorial.addShutdownHandler();
System.out.print("프로그램을 종료합니다.\n");
System.exit(0);
}
}
|
참고자료