Page tree
Skip to end of metadata
Go to start of metadata

부제: NIO부터 Netty까지


Introduction


인터넷 사용 인구의 폭발적인 증가와 글로벌한 소셜서비스들로 인해 대용량 트래픽처리와 데이터캐싱, 비동기처리 등은

현대의 서버 개발환경에서 늘 마주하게 되는 주제들입니다.

5주차스터디에서는, JDK1.4+ 부터 제공되는 NIO와 이를 wrapping한 Netty를 학습하고, 효율적인 방법을 토론합니다.

JAVA IO 기본

  • stream이란?

    • 스트림은 데이터 소스(File, DB, Socket)에 저장되어 있는 데이터를 다른 데이터 소스에 전달하고자 할 때 사용한다.
    • 키보드의 입력을 모니터에 출력할 때도 스트림을 사용한다.
  • stream 특징
    • stream은 FIFO(first in first out, 선입선출)이다.
    • stream은 단방향이다. 자바에서는 읽기와 쓰기가 동시에 되지 않기 때문에 입력 스트림과 출력 스트림을 각각 생성해야 한다.
    • stream은 데이터 처리가 완료될 때까지 stream을 사용하는 스레드는 waiting 상태에 빠진다.
  • Java IO의 기본 사용 예
    • Java IO는 한 개의 IO만을 사용하는 것이 아니라 여러 개의 IO를 조합해서 사용하는 것이 일반적이다. decorator 디자인 패턴을 활용하고 있다.
    • decorator 디자인 패턴????  참고 : http://iilii.egloos.com/3850836
  • 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 사용하기

  • http://eincs.net/2009/08/java-nio-bytebuffer-channel/ 문서 참고한다. 중요한 내용만 정리하면 다음과 같다.
  • 커널 버퍼를 직접 접근하려면 ByteBuffer를 사용해야 한다.
  • Buffer 에는 현재 쓰거나 읽을 위치, 유효하게 읽을 수 있는 위치, 현재 용량의 위치 등을 나타내는 포인터가 네가지가 있습니다. position, limit, capacity, mark 로 붙여진 이 네가지 포인터에 대해서 빠삭하게 숙지하고 계셔야 Buffer를 잘 사용하실 수 있습니다. 다음은 이 네 가지 포인터에 대한 간략한 설명입니다.
    • position : 현재 읽을 위치나 현재 쓸 위치를 가리킵니다.. ByteBuffer에서 get()함수로 읽기를 시도할 경우 position위치부터 읽기 시작하며, put()함수로 ByteBuffer에 쓰기를 시도할경우 position 위치부터 쓰기를 시작합니다.. 읽거나 쓰기가 진행될 때마다 position의 위치는 자동으로 이동합니다.
    • limit : 현재 ByteBuffer의 유요한 쓰기 위치나 유효한 읽기 위치를 나타냅니다. 다시 말해, "이 버퍼는 여기까지 읽을 수 있습니다" 혹은 "여기까지 쓸 수 있습니다"를 나타냅니다. 헷갈리시죠? 자세한 사용법은 아래서 알아보도록 합시다. 다르게 말하면 "여기서부터는 쓸 수 없습니다", "여기서부터는 읽을 수 없습니다" 라고 표현 가능합니다.
    • capacity : ByteBuffer의 용량을 나타냅니다. 따라서, 항상 ByteBuffer의 맨 마지막을 가리키고 있습니다. 그 때문에 position과 limit와는 달리 그 위치랄 바꿀 수가 없죠^^
    • mark : 편리한 포인터입니다. 특별한 의미가 있는 것은 아니고, 사용자가 마음대로 지정할 수 있습니다. 특별히 이 위치를 기억하고 있다가 다음에 되돌아가야할 때 사용합니다. 이 포인터에 대해선 차차 사용할 일이 있을 때 사용하실테고, 이 포스팅에선 자세히 다루지는 않겠습니다.
  • 예제를 통해 이 4가지 개념을 명확히 이해할 수 있도록 하면 좋겠다.
  • NIO의 Channel은 Buffer에 있는 내용을 다른 어디론가 보내거나 다른 어딘가에 있는 내용을 Buffer로 읽어들이기 위해 사용됩니다. 예를 들면 네트워크 프로그래밍을 할 때 Socket을 통해 들어온 내용을 ByteBuffer에 저장하기 위해서나, ByteBuffer로 Packet을 작성 후 Socket으로 흘려 보낼 때 Channel을 사용합니다
  • FileChannel은 Blocking 모드만 가능하다. 그 이유는 각 운영체제나 시스템다 File 입출력시 Non-Blocking을 지원해주지 않는 시스템이 있기 때문이라고 한다.
  • 네트워크 프로그래밍을 담당하는 ServerSocketChannel이나 SocketChannel의 경우는 Selector를 활용해 Non-Blocking 프로그래밍이 가능하다.
  • Channel은 직접 인스턴스화 할 수가 없다!, OutputStream/InputStream에서 만들어야한다!

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();
        }
    }
}
  • https://github.com/javajigi/slipp-java에 초간단 웹 서버 버전 구현해 올려 놓음.
    • Web Server - IO.pdf 에 웹 서버를 구현하는 단계를 Step By Step으로 구성해 놓음. 이 소스 코드를 바탕으로 Step By Step으로 웹 서버 구현하고 리팩토링하는 연습 가능

 

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)
    1. 쓰레드의 작동이 끝났을 때
    2. 프로그램이 종료되었을 때 
    3. 사용자가 CTRL + C를 눌렀을 때
    4. 운영체제가 종료되거나 사용자가 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);
	}
}

참고자료

  • No labels

7 Comments

  1. 그 동안 우리들이 IO API를 사용하기는 했는데 구체적으로 알고 사용한 것은 아니라고 생각한다. 따라서 스터디에서는 IO 관련해 궁금한 부분들을 자유롭게 논의할 수 있으면 좋겠다.

    논의를 하려면 논의하기 전에 IO에 대한 이해를 하기 위해 간단하게 실습할 수 있는 예제를 찾아보고 같이 실습해 보는 것도 좋겠다는 생각이 든다. 근데 이 예제를 찾기가 쉽지 않을 듯하다. 나도 슬슬 스터디 준비차 IO 공부 좀 해야겠다. 어떻게 하면 개념을 쉽게 전달할 수 있을까에 대해서 말이야.

  2. 갑자기... 3학년 2학기 장학금을 가로막은 운영체제시간이 생각나요... 미리 공부 열심히 해가겠습니다 꾸벅.

  3. 저도 잘 몰라영 ^^;;

    예제나 이미지 등은 위키에 추가하고

    추후에 ppt를 위키에 업로드 하겠습니당

  4. 내일 스터디중에 제일 어려운 내용일듯 싶어요 ㄷㄷㄷ

    1. 어려운 주제지만 석진이가 정말 쉽게 설명해 줄꺼야? 맞지 석진아?

      1. ㅎㅎ 선빵불패.. 먼가 이렇게 연기를 모락모락 피어놓고
        막상 별 거 없을거에요.

  5. 이야.... 이번에 스터디는 정말 시간이 모자랐겠는데요?

    좋은 자료 고마워요!!! ㅎㅎ 대권이형께는 실습할 기회를 못드려서 너무 미안하네요;;;

    자료는 정말 감사합니다!!! 틈틈이 재밌게 읽어볼게요 ㅋ