관리 메뉴

HAMA 블로그

Vert.x 와 Node.js 비교 본문

Vert.x

Vert.x 와 Node.js 비교

[하마] 이승현 (wowlsh93@gmail.com) 2015. 5. 19. 11:14

http://helloworld.naver.com/helloworld/textyle/163784


vert.x는 현재 가장 뜨겁게 부상하고 있는 서버 프레임워크입니다. 모든 서버 프레임워크가 그렇듯이 고성능과 다양한 프로토콜 지원을 장점으로 내세우고 있습니다. vert.x는 여기서 한 발 더 나아가 서버 네트워크 환경을 구축하고 운영하는 환경까지도 고려하고 있습니다. 즉, vert.x는 하나의 '서버 프로세스 데몬'을 제작하는 것뿐만 아니라, 클러스터링 환경에서 동작하는 여러 서버 프로세스 데몬을 제작하는 방법에 대한 고민까지 담고 있습니다.

그렇기 때문에 vert.x가 어떤 방식으로 고성능을 내고 있는지, 어떤 네트워크 환경을 고려하고 있는지 충분히 시간을 들여 알아볼 가치가 있다고 할 수 있습니다.

vert.x의 철학

vert.x는 Node.js로부터 영향을 받은 프로젝트다. vert.x는 Node.js처럼 Event-based 프로그래밍 모델을 제공하는 서버 프레임워크다. 그렇기 때문에 vert.x의 API는 Node.js와 매우 유사하다. 둘 모두 비동기 형태의 API를 제공한다.

Node.js는 JavaScript로 만들어졌지만, vert.x는 Java로 제작되었다. 하지만 vert.x를 Node.js의 Java 버전이라고 이해하기에는 무리가 있다. vert.x가 Node.js로부터 영향을 받은 것은 사실이지만, vert.x는 Node.js와 다른 고유한 철학을 가지고 있기 때문이다.

대표적인 vert.x의 설계 철학을 정리하면 다음과 같다.

 

참고) Netty와 vert.x의 관계

vert.x의 성능을 논하기 전에 Netty와 vert.x의 관계를 정리할 필요가 있다. vert.x는 Netty를 사용한다. 즉, 다중 I/O 처리에 Netty를 사용한다. 그렇기 때문에 vert.x와 Netty의 성능 차이를 확인하는 것은 무의미하다.
vert.x는 Netty와는 다른 독자적인 API와 기능을 제공하는 다른 목적의 서버 프레임워크다. Netty는 로우레벨 수준의 I/O를 다룰 수 있는 프레임워크고, vert.x는 그보다는 하이레벨 영역을 다룬다.

Node.js와의 성능 비교

vert.x가 제공하는 기능이 Node.js와는 다르더라도 둘 사이의 성능을 비교하는 것은 충분히 의미 있는 일이다. 그림1과 그림2는 vert.x(Java, Ruby, Groovy)와 Node.js의 성능을 비교한 자료다(출처:http://vertxproject.wordpress.com/2012/05/09/vert-x-vs-node-js-simple-http-benchmarks/).

그림 1은 HTTP 서버를 만들고 200/OK 응답만을 주었을 때의 성능을 비교한 결과다. 그림 2는 72 바이트 크기의 정적 HTML 파일을 응답 결과로 제공하는 경우에 성능을 비교한 결과다. vert.x 제작자가 밝힌 성능이고 스스로도 엄격한 환경에서 실시한 테스트가 아니므로 상대적인 성능 격차에만 주목하는 것이 좋을 것으로 보인다.

ad70637d150cff0744f460a6da1bcb00.png

그림 1 200/OK 응답만 주었을 때의 성능 비교

572fdeba65175722f09387935f981788.png

그림 2 72바이트 크기의 정적 파일 제공 성능 비교

주목할만한 점은 Node.js보다 vert.x-JavaScript의 성능이 좋다는 것이다. 이 성능 비교 결과가 신뢰성이 매우 높다고 하더라도, 단순히 Node.js에 비해 vert.x가 낫다고 말하기는 어려울 수 있다. Node.js는 Socket.io와 같은 훌륭한 모델을 제공하고 있을 뿐만 아니라, 많은 레퍼런스를 확보하고 있기 때문이다.

vert.x 용어들

vert.x는 vert.x만의 고유 용어를 정의하거나, 일반적인 용어를 vert.x에서 다시 정의해서 사용하기도 한다. vert.x를 잘 이해하려면 vert.x가 정의한 용어를 잘 이해해야 한다. vert.x에서 사용하는 대표적인 용어를 정리해 보았다.

Verticle

vert.x에서 배치(deploy)의 기본 단위다. Java의 경우라면 main 메서드가 있는 클래스가 된다. Verticle은 또한 main 메서드에서 참조되는 다른 스크립트를 포함할 수 있다. .jar 파일이나 리소스를 포함할 수 있다. 애플리케이션은 하나의 Verticle로 이루어질 수도 있고, event bus를 통해 서로 통신하는 여러 개의 Verticle로 이루어질 수도 있다. Java로 생각하면 독립적으로 실행 가능한 Class 또는 .jar 파일로 이해할 수 있겠다.

vert.x 인스턴스

Verticle은 vert.x 인스턴스 안에서 실행되고, vert.x 인스턴스는 자신의 JVM 인스턴스 안에서 실행된다. 단일 vert.x 인스턴스 안에서는 동시에 실행되는 많은 Verticle이 존재할 수 있다. 각각의 Verticle은 고유의 클래스 로더를 가질 수 있다. 이로 인해 Verticle 간에 스태틱 멤버, 글로벌 변수 등을 통한 직접적인 상호작용을 막을 수 있다. 네트워크상의 여러 호스트에서 동시에 많은 vert.x 인스턴스가 실행될 수 있고 event bus를 형성해서 vert.x 인스턴스 간에 클러스터링되도록 설정할 수 있다.

동시성(concurrency)

Verticle 인스턴스는 항상 동일한 스레드에서 실행됨이 보장된다. 모든 코드를 단일 스레드 동작 형태로 개발할 수 있기 때문에, vert.x를 사용하는 개발자에게 개발하기 편한 환경을 제공하는 것이라 할 수 있다. 게다가 레이스 컨디션이나 데드락이 발생하지 않게 할 수도 있다.

Event-based Programming Model

vert.x는 Node.js 프레임워크와 비슷하게 Event-based 프로그래밍 모델을 제공한다. vert.x로 서버 프로그래밍을 할 때 개발해야 하는 코드의 대부분은 이벤트 핸들러에 관한 것이다. 예를 들어, TCP 소켓으로부터 데이터를 수신하기 위해 핸들러를 설정하는 것이나 데이터가 도착할 때 호출될 핸들러를 제작하는 것이다. 이외에도 'Event bus에서 메시지를 수신할 때', 'HTTP 메시지를 수신할 때', '커넥션이 종료되었을 때', '타이머가 종료 되었을 때' 알림을 받기 원한다면 핸들러를 작성하면 된다.

Event Loops

vert.x 인스턴스는 내부적으로 스레드 풀을 관리한다. vert.x는 가급적 스레드 풀의 개수를 CPU 코어 수와 일치할 수 있게 한다.

그리고 이 각각의 스레드에서는 Event Loop를 실행한다. Event Loop란 확인해야 할 이벤트를 루프(loop)를 돌면서 확인하는 것이다. 가령 소켓에 읽을 데이터가 있거나, 어떤 타이머에 이벤트가 발생했는지 확인하는 것과 같은 것들이다. 루프를 돌다가 처리해야 할 이벤트가 있다면, 해당 핸들러를 호출하는 방식으로 vert.x가 동작한다(물론 이때 핸들러 처리 시간이 길다거나 블로킹 I/O가 있다거나 할 때는 별도의 작업이 필요하다. 다음 게시글에서 소개할 예정이다.).

Message Passing

Verticle 간의 통신은 Event Bus를 이용한다. Verticle을 actor라고 생각하면, Message Passing은 Erlang 프로그래밍 언어에서 유명해진 actor 모델과 유사하다. vert.x 서버에서는 많은 Verticle 인스턴스 생성 및 이들 간의 message passing을 통해 Verticle 코드에 대한 멀티 스레드 실행이 없이도 사용 가능한 코어에 맞게 시스템 확장이 가능하다.

Shared data

Message passing이 매우 유용하긴 하지만 모든 종류의 애플리케이션 동시성 상황에서 최고의 접근 방법은 아니다. 캐시가 대표적인 예다. 어떤 캐시를 어느 하나의 Verticle만 가지고 있다면 매우 비효율적이 된다. 이 캐시가 다른 Verticle에도 필요한 내용이라면 Verticle이 각각 같은 내용의 캐시 데이터를 관리하여야 하기 때문이다.

그렇기 때문에 vert.x는 전역에서 접근할 수 있는 방법을 제공한다. 바로 Shared Map이다. 그리고 Verticle 사이에서는 오직 불변(immutable) 데이터만 공유되게 하고 있다.

vert.x Core

이름 그대로 vert.x의 핵심 기능이다. Verticle에서 직접적으로 호출될 수 있는 기능은 모두 이 Core에 담겨있다. 당연하게 이 Core는 vert.x가 지원하는 프로그래밍 언어 API에서 접근할 수 있다.

vert.x 아키텍처

vert.x의 대략적인 아키텍처는 다음 그림과 같다.

374e032351d88c70dc05736e3079e6ca.png

그림 3 vert.x 아키텍처(원본 출처: http://www.javacodegeeks.com/2012/07/osgi-case-study-modular-vertx.html)

vert.x의 기본 실행 단위는 Verticle이고 동시에 여러 Verticle이 하나의 vert.x 인스턴스에서 실행될 수 있다. Verticle은 Event-Loop 스레드에서 실행된다. 하나의 호스트는 물론 네트워크상의 다른 여러 호스트에서 여러 vert.x 인스턴스가 실행될 수 있는데, 이때 Verticle이나 Module 간에는 Event Bus를 통해 통신할 수 있다.

요약하면, vert.x 애플리케이션은 Verticle 또는 Module 의 조합으로 이루어지며 이들 간의 통신은 Event Bus를 사용한다.

vert.x 프로젝트 구조

다음 그림은 github의 vert.x 페이지에서 소스 코드를 복제(clone)해 Eclipse에서 본 vert.x 프로젝트 구조다.

49e1c3d8d3329e1bd3a1043166caf566.png

그림 4 vert.x 소스 트리

전체적인 구성을 살펴보면 다음과 같다.

  • 핵심 library인 vertx-core
  • 배포 및 라이프사이클을 관리하는 vertx-platform
  • Core Java API를 다른 언어로 노출하는 vert-lang

프로젝트 빌드(build) 시스템으로는 Ant와 Maven의 장점을 갖췄다는 Gradle를 사용한다.

vert.x 설치 및 간단한 예제 실행

vert.x를 사용하려면 반드시 JDK7이 필요하다. vert.x는 JDK7에 있는 invokeDynamic을 사용하기 때문이다.

vert.x는 매우 간단하게 설치할 수 있다. https://github.com/purplefox/vert.x/downloads에서 압축된 설치 파일을 원하는 위치에 다운로드해 압축을 푼 다음, bin 디렉터리를 PATH 환경 변수에 추가하면 설치를 완료할 수 있다. 커맨드 창에서 vertx version을 실행해 버전 정보가 제대로 나오면 설치가 성공한 것이다.

이제는 "Hello World!"를 출력하는 간단한 웹 서버를 JavaScript로 작성하고 실행해 보자. 다음과 같이 코드를 작성한 후 server.js로 저장한다. Node.js 코드와 거의 흡사한 형식이다.

1
2
3
4
5
load('vertx.js');
 
vertx.createHttpServer().requestHandler(function(req) {
    req.response.end("Hello World!");
}).listen(8080, 'localhost');

생성한 server.js 애플리케이션을 다음과 같이 vert.x 명령어로 실행한다.

1
%> vertx run server.js

브라우저를 열고 http://localhost:8080에 접속해 "Hello World!" 메시지를 볼 수 있으면 성공이다.

다른 언어로 작성 된 예제를 살펴보자. 다음은 Java로 작성한 예제다. 정적 파일을 읽어 HTTP 응답으로 제공하는 웹 서버를 작성해 본 것이다.

1
2
3
4
5
6
7
8
Vertx vertx = Vertx.newVertx();
vertx.createHttpServer().requestHandler(new Handler<httpserverrequest>() {
    public void handle(HttpServerRequest req) {
        String file = req.path.equals("/") ? "index.html" : req.path;
        req.response.sendFile("webroot/" + file);
    }
}).listen(8080);
</httpserverrequest>

다음은 Groovy로 작성한 코드로 앞의 Java로 작성한 예제와 같은 기능을 한다.

1
2
3
4
5
def vertx = Vertx.newVertx()
vertx.createHttpServer().requestHandler { req ->
    def file = req.uri == "/" ? "index.html" : req.uri
    req.response.sendFile "webroot/$file"
}.listen(8080)

NHN과 vert.x

NHN의 플랫폼 개발 부서에는 vert.x가 정식으로 릴리스되기 전부터 개발 과정을 지켜보고 있었다. vert.x의 가능성을 높이 샀기 때문이다. 그리고 2012년 6월부터 메인 개발자인 Tim Fox와 교류하여 vert.x를 발전시켜 나갈 수 있도록 논의를 진행하고 있다. 예를 들어, Socket.io는 Node.js에서만 사용할 수 있었는데, 이를 vert.x에서도 Java로 사용할 수 있게 포팅 작업을 진행했고 현재 개발이 완료된 상태다. 다음은 github의 vert.x 레파지토리에 있는 pull request 요청 링크다.

산출물인 socket.io vert.x 모듈은 현재 개발 중인 RTCS 2.0 버전(vert.x + Socket.io)에 사용될 예정이다.

Node.js가 지금처럼 활성화된 것은 Socket.io 덕분이었는데, vert.x에서 Socket.io를 사용할 수 있다면 vert.x 또한 많은 사용 사례가 생길 것으로 예상한다. 또한 이 socket.io vertx 모듈을 임베디드 라이브러리 형태로 사용하면 Java 기반의 애플리케이션에서도 socket.io를 사용할 수 있게 된다는 점에서 의미가 있다 하겠다.

참고) RTCS 란?

RTCS(Real Time Communication System)는 NHN의 Real Time Web 개발 플랫폼으로, 브라우저와 서버 간에 실시간으로 메시지를 전달할 수 있게 도와주는 플랫폼이다. RTCS는 현재 야구9단, 미투데이 채팅, 밴드(BAND) 채팅에 적용되어 있다.

마치며

vert.x는 2012년 5월에 첫 버전이 나왔다. 2009년에 첫 버전이 나온 Node.js에 비하면 역사가 매우 짧다고 할 수 있다. 그렇기 때문에 아직 레퍼런스가 많지 않다. 하지만 vert.x는 VMware의 든든한 후원을 받고 있고 Cloud Foundry에서 구동할 수 있기 때문에, 앞으로 많은 레퍼런스가 확보될 것으로 보인다.

참고 자료


Comments