netty 시작하기 (1)

Post on 19-Jul-2015

470 Views

Category:

Software

42 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Netty 시작하기 (1)고성능 네트워크 애플리케이션 프레임워크

김대현@hatemogi

0

지금 보시는 발표 자료는...

위 주소에서 직접 볼 수 있고, [SPC]를 누르면 다음 슬라이드로, [Shift­SPC]를누르면 이전 슬라이드로 이동합니다.

http://hatemogi.github.io/netty­startup

김대현

2015, Netty 기반 서버 개발2013, 사내 Redis SaaS 개발팀장, 160+ VM2010, 클라우드, 네트워크 파일동기화 프로토콜 설계2010, MyPeople, 네트워크 아키텍쳐 설계2009, Cafe 채팅 부하분산 서버 개발2004, Cafe 한줄메모장 개발, 일일 3억 PV

과정1. Netty의 기본 설명2. 문제 풀이3. 예제 이해 / 실습 개발

목표

Event­Driven, 비동기 I/O 이해Netty로 개발 경험(조만간) 실무에 응용

4시간 진행 주제

1. 비동기 개념, 기본 인터페이스(Channel) 정리2. 3. 4.

예제와 실습

1. Discard 서버, Echo 서버2. HTTP 서버3. 채팅 서버4. 웹소켓 채팅 서버

고성능 메모리 모델과 유연한 파이프라인깔끔한 쓰레드 모델, Future/Promise 활용풍부한 코덱과 WebSocket

매 시간 구조

1. 설명 (20분)2. 예제 설명 / 데모 (10분)3. pair 실습 (25분)

총 9개 문제 풀이

다음의 공통점

NginxHAProxyMemcachedRedisNode.js?

왜 Netty를 쓸까?고성능쓰기 편하다 (유연하고 쉽다)

Netty가 고성능인 이유

Non­blocking Asynchronous 처리가 기본적은 쓰레드로 많은 요청을 처리GC부하를 최소화하는 Zero­copy ByteBuf 지원

Netty가 편한 이유

각종 네트워크 프로토콜 (코덱) 기본 지원필요한 부분을 쉽게 조립해 쓸 수 있는 구조멀티쓰레딩 처리 없이도...

Netty 버전

5.0.0.Alpha2 ‑ 04­Mar­2015 (Development)4.1.0.Beta4 ‑ 04­Mar­2015 (Development)4.0.26.Final ‑ 04­Mar­2015 (Stable, Recommended)3.10.1.Final ‑ 23­Mar­2015 (Stable)

이 자료와 실습은 4.0.26.Final을 기준으로 합니다.

동기와 비동기Synchronous vs. AsynchronousBlocking vs. Non­blocking

우리말로 하자면...

요청하고 결과를 계속 기다리기완료되면 알려달라고 요청하고 다른 일 하기

고객센터에 전화를 했는데... 모든 상담원이 통화중입니다.

1. 연결될 때까지 기다리기2. 전화해달라는 기록 남기고 끊기

동기 or 비동기

커피 주문지하철 이용, 자가 운전업무요청 메일, 업무문의 전화팀장의 업무지시

동기 (Synchronous) 코드 Blocking call

// 동기 방식void greeting(Context ctx) String req = ctx.readLine(); ctx.write("안녕, " + req); System.out.println("완료");

비동기 (Asynchronous) 코드 Non­blocking call

// 비동기 방식void greeting(Context ctx) ctx.readLine().done(line -> ctx.write("안녕, " + req); ); System.out.println("완료");

Event­Driven ProgrammingIn computer programming, event­driven programming is a programmingparadigm in which the flow of the program is determined by events such as useractions (mouse clicks, key presses), sensor outputs, or messages from otherprograms/threads. Event­driven programming is the dominant paradigm used ingraphical user interfaces and other applications (e.g. JavaScript webapplications) that are centered on performing certain actions in response to userinput. Wikipedia

사건 기반 프로그래밍

사건 기반 프로그래밍(영어: Event­driven programming; EDP)은 비주얼 베이직과 같이,사용자의 명령·마우스 클릭·다른 프로그램의 메시지·키보드 글쇠 입력 등의 ‘사건’에 따라, 제어흐름이 결정되어 일을 하도록 하게끔 만들어진 프로그래밍 언어 방식을 뜻한다. 위키백과

등잔 밑의 Event­Driven 코드

자바스크립트iOS 앱Android 앱데스크탑 애플리케이션

$("button").on("click", function(event) console.log(event); alert("클릭"););

True or False

비동기와 Event­driven은 같은 뜻이다?Event­Driven은 데스크탑앱 클라이언트에만 적합하다?비동기식 싱글쓰레드에서는 Blocking Call을 할 수 없다?

업무요청시

업무 요청하고 옆에서 기다리고 있으면?업무 요청하고 돌아갔다가, 나중에 다시 와서 확인하면?업무 요청하면서, "다되면 저한테 알려주세요"하면?

Netty는 Async Event­Driven

됩니다만...

어? 그럼 그냥 Java의 NIO를 쓰면 안되나요

Netty의 핵심 인터페이스Channel

ChannelFuture

ChannelHandler

ChannelHandlerContext

ChannelPipeline

EventLoop

Channel

읽기, 쓰기, 연결(connect), 바인드(bind)등의 I/O 작업을 할 수 있는 요소 또는 네트워크 연결모든 I/O 작업은 비동기 ­> ChannelFuture

핵심 메소드

ChannelFuture write(Object obj)ChannelFuture flush(Object obj)ChannelFuture writeAndFlush(Object obj)ChannelFuture closeFuture()ChannelPipeline pipeline()SocketAddress remoteAddress()

ChannelFuture

Channel의 I/O 작업의 결과ChannelFutureListener를 등록 결과에 따른 작업

핵심 메소드

ChannelFuture addListener(GenericFutureListener<...> listener)Channel channel()boolean isSuccess();Throwable cause();ChannelFuture await()ChannelFuture sync()

ChannelHandler

Netty의 핵심 요소!Netty의 I/O 이벤트를 처리하는 인터페이스ChannelInboundHandlerAdapter

ChannelOutboundHandlerAdapter

전체 메소드

void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)void handlerAdded(ChannelHandlerContext ctx)void handlerRemoved(ChannelHandlerContext ctx)

ChannelHandlerContext

ChannelHandler는 ChannelHandlerContext를 통해다음 ChannelHandler에게 이벤트를 넘기거나,동적으로 ChannelPipeline을 변경할 수 있음 ­ [실습4]

핵심 메소드

Channel channel()ChannelPipeline pipeline()ChannelFuture write(Object msg)ChannelHandlerContext fireChannelActive(Object msg)ChannelHandlerContext fireChannelRead(Object msg)

ChannelPipeline

Channel에 드나드는 inbound / outbound 이벤트를 처리 처리, ChannelHandler 리스트

두번째 시간에 상세 설명

주요 메소드

Intercepting Filter 패턴

ChannelPipeline addLast(ChannelHandler... handlers)ChannelPipeline addLast(String name, ChannelHandler handler)ChannelHandler remove(String name)<T extends ChannelHandler> T remove(Class<T> handlerType)

EventLoop

등록된 Channel들의 모든 I/O 작업을 처리구현체 NioEventLoopGroup를 주로 사용

주요 메소드

boolean inEventLoop()<T> Future<T> submit(Callable<T> task)<V> Promise<V> newPromise()<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)

Channel관련 인터페이스 전체 구조

EventLoop

Channel

Channel

ChannelChannelPipeline

ChannelHandler 1 ChannelHandler 2 ChannelHandler N

예제와 실습용 프로젝트

Git clone

Netty 4.x JavaDoc

https://github.com/hatemogi/netty­startup

git clone https://github.com/hatemogi/netty-startup

처음에는 실패하는 유닛테스트가 준비돼 있고, 실습문제를 모두 풀면 유닛 테스트가 모두 통과돼야합니다.

http://netty.io/4.0/api/index.html

첫 예제: DiscardServer

DiscardServer.javaDiscardServerHandler.java

src/nettystartup/h1/discard

src/nettystartup/h1/discard/DiscardServer.java

public final class DiscardServer public static void main(String[] args) throws Exception EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new DiscardServerHandler()); ChannelFuture f = b.bind(8010).sync(); System.err.println("Ready for 0.0.0.0:8010"); f.channel().closeFuture().sync(); finally workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully();

src/nettystartup/h1/discard/DiscardServerHandler.java

class DiscardServerHandler extends ChannelInboundHandlerAdapter @Override public void channelRead(C..H..Context ctx, Object msg) throws Exception ByteBuf buf = (ByteBuf) msg; try // discard finally buf.release(); // 이 부분은 두번째 시간에 설명합니다. @Override public void exceptionCaught(C..H..Context ctx, Throwable cause) cause.printStackTrace(); ctx.close();

DiscardServer 테스트

telnet localhost 8010

Trying ::1...Connected to localhost.Escape character is ']'.helotest

]telnet> closeConnection closed.

Netty와 유닛테스팅EmbeddedChannel을 활용

EmbeddedChannel ch = new EmbeddedChannel(new HandlerToBeTested());

EmbeddedChannel

public class EmbeddedChannel extends AbstractChannel public EmbeddedChannel(ChannelHandler... handlers)

public Object readInbound() ... public Object readOutbound() ... public boolean writeInbound(Object... msgs) ... public boolean writeOutbound(Object... msgs) ...

public void checkException() ...

test/.../h1/discard/DiscardServerHandlerTest.java

public class DiscardServerHandlerTest @Test public void discard() String m = "discard test\n"; EmbeddedChannel ch = new EmbeddedChannel(new DiscardServerHandler()); ByteBuf in = Unpooled.wrappedBuffer(m.getBytes()); ch.writeInbound(in); ByteBuf r = (ByteBuf) ch.readOutbound(); assertThat(r, nullValue());

첫번째 실습: EchoServerEchoServer

EchoServerHandler

EchoServerHandlerTest

src/nettystartup/h1/echo/EchoServer.java

public final class EchoServer public static void main(String[] args) throws Exception EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class); // TODO: [실습 1-1] 이 부분을 채워서 EchoServerHandler를 등록합니다 ChannelFuture f = b.bind(8020).sync(); f.channel().closeFuture().sync(); finally workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully();

src/nettystartup/h1/echo/EchoServerHandler.java

class EchoServerHandler extends ChannelInboundHandlerAdapter @Override public void channelRead(ChannelHandlerContext ctx, Object msg) // TODO: [실습1-2] 받은로 응답하는 코드를 한 줄 작성합니다. release는 필요하지 않습니다. @Override public void channelReadComplete(ChannelHandlerContext ctx) ctx.flush(); @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) cause.printStackTrace(); ctx.close();

test/nettystartup/h1/echo/EchoServerHandlerTest.java

public class EchoServerHandlerTest @Test public void echo() String m = "echo test\n"; EmbeddedChannel ch = new EmbeddedChannel(new EchoServerHandler()); ByteBuf in = Unpooled.copiedBuffer(m, CharsetUtil.UTF_8); ch.writeInbound(in); ByteBuf r = (ByteBuf)ch.readOutbound(); releaseLater(r); assertThat("응답이 없습니다", r, notNullValue()); assertThat("참조수는 1이어야 합니다",r.refCnt(), is(1)); assertThat("수신한 텍스트가 결과로 와야합니다", r.toString(CharsetUtil.UTF_8), equalTo(m));

실습 정리

Netty로 네트워크 서버를 만들어 봤습니다.ChannelHandler의 기초를 익혔습니다.메모리 모델은 다음 시간에 설명합니다.

다음 시간에는...

http://hatemogi.github.io/netty­startup/2.html

top related