Web Framework Benchmark

최근 각광받고 있는 server-side language 및 그에 따른 web framework들의 성능(performance)이 얼마나 차이가 있는지 궁금해졌다. 보통 Ruby는 생산성(productivity)은 좋지만 성능은 좋지 않다라든지, 대용량 처리에 Erlang이 성능이 좋다라든지 이야기가 많은데, 정량적으로 얼마나 차이가 나는 것인지 실제로 확인해보려고 한다. 성능에 대해 좀더 정확히 알고 있다면, 성능과 개발기간 등의 요구사항에 맞는 language 및 web framework을 선택하는데 유용할 것 같기 때문이다.

1. Language & web frameworks


다음과 같은 기준으로 benchmark를 할 language와 framework를 선정해 보았다.

  • 생산성이 좋다고 알려진 것
  • 성능이 좋다고 알려진 것
  • 요즘 많이 쓰이는 것

1.1 Ruby + Sinatra

Ruby는 생산성이 좋다고 알려져서 최근에 스타트업에서 많이 이용하고 있다. 보통은 Ruby를 사용할 때 Rails를 web framework로 이용하는데, 테스트의 편의를 위해 Sinatra라고 하는 lightweight framework를 이용하였다. 또 Ruby에 기본으로 포함된 web server인 WEBrick이 성능이 좋지 않아서, ApachePassenger 조합의 web server를 이용하였다.

Ruby: v1.9.2

Sinatra: v1.3.2

Web server : Apache + Passenger

1.2 Java + Play framework 1

Java는 PHP와 더불어 가장 많이 쓰이는 server side language인 것 같다. 보통 많이 쓰이는 Spring대신에 최근에 인기 있는 Play framework(이하 Play)를 사용하였다. 실험에 사용된 Play의 버전은 가장 최신의 stable한 버전인 1.2.4이다.

Java: v6

Play: v1.2.4 (netty v3.2.5async-http-client v1.6.5)

1.3 Scala + Play framework 2

Scala는 functional language로 Java Virtual Machine(JVM)상에서 동작한다. 오랫동안 최적화 작업을 거친 JVM 상에서 동작하기 때문에 안정적이라고 알려져 있다. 또, Java와도 호환이 잘되는 것으로 알려져 있다. Scala는 ‘Scalable’에서 따온 이름이라고 하는데, 역시 그 이름처럼 Language 차원에서 병렬 프로그래밍을 지원하고 있어서 대용량 처리 시에 성능이 좋고, scalable 하다고 한다. 또, functional language답게 syntax가 간결해서 개발 생산성이 좋은 듯 하다.

Scala용 framework 중에서는 Lift, Play, Scalatra등이 많이 쓰이는데, 개인적으로 경험이 있는 Play를 선택하였다. 단, Play의 1.x 버전의 경우 Scala의 경우에 비동기(asynchronous) 관련 기능이 지원이 되지 않아서, 현재 개발중인 Play 2를 이용하였다. 소스를 받아 직접 빌드해서 사용했기 때문에 버전이 따로 없고, Beta와 곧 release할 RC1의 사이의 버전 정도로 보면 되겠다.

Scala: v2.9

Play: v2.0 개발 버전 (netty v3.3.0async-http-client v1.7.0)

1.4 Node.js

Client-side language인 JavaScript를 server-side에서 이용할 수 있도록, Chrome의 JavaScript 엔진인 V8을 포팅한 것이 node.js라고 한다. JavaScript가 기본적으로 비동기적으로 동작하기 때문에, node.js를 이용하여 서버에서도 이렇게 프로그래밍하는 경우 병렬 프로그래밍에 유리해 성능이 좋다고 알려져 있다. 최근에 주목을 받고 있어서, 진짜로 얼마나 좋은 지 궁금해서 대상에 포함시켜 보았다.

테스트의 편의를 위해서 Express라는 lightweight framework을 이용하였다.

Node.js: v0.6.7

Express: v2.5.6

1.5 Erlang

Erlang은 1980년대에 Ericsson에 의해 만들어진 functional language다. Erlang이라는 이름도 ‘Ericsson Language’를 줄인 것이라고 한다. CouchDB가 Erlang으로 만들어졌다고 알려져 있고, 최근에 WhatsApp이라는 어플이 Erlang을 이용해서 서버 프로그래밍을 했는데, 서버 1대가 2백만대의 client connection을 관리한다고 해서 깜짝 놀란 적이 있다.

Erlang에는 inets라는 HTTP client/server 모듈이 포함되어 있는데, 이것 대신에 Erlang에서 성능이 좋다고 알려진 Misultin이라는 web server를 이용하였다. Erlang Web Server 비교 자료는 이 글을 참고하였다.

Erlang: R15B

Web server: Misultin v0.8

1.6 Else

참고로, PHP는 초기 생산성은 좋으나 코드가 스파게티화 되는 경우를 많이 봐서 개인적으로 선호하지 않고, ASP는 Windows에서만 동작해서 제외 했다. 또 요즘 Python+Django도 많이 쓰는 것으로 알고 있는데, 생산성과 성능에서 Ruby와  비슷할 것으로 생각되서 제외했다.

2. Test Tools


HP에서 만든 httperf라는 툴로 테스트를 해보았다. autobench라는 통해서 httperf를 이용하면, 부하를 주는 서버를 여러대로 설정할 수 있고, 또 자동으로 부하를 조금씩 늘려가며 테스트를 할 수 있다.

3. Test System Deployment


테스트를 위한 구성은 다음과 같이 3가지의 시스템으로 구성된다.

3.1 Clients

부하를 생성하는 머신이다. 2대로 구성하였고, 스펙은 다음과 같다.

  • CPU: 32 cores (8 Processors(Intel(R) Xeon(R) CPU X3470 @ 2.93GHz), 4 cores per processor)
  • Memory: 8 GB
  • 2대 모두 동일함

3.2 Server

비교 대상이 되는 web framework가 동작하는 서버이다. 이 서버에 비교 대상이 되는 web framework의 서비스를 포트만 달리해서 모두 띄워놓았다.

스펙은 다음과 같다.

  • CPU: 8 cores (2 Processors(Intel(R) Xeon(R) CPU X3470 @ 2.93GHz), 4 cores per processor)
  • Memory: 8 GB

3.3 External Server

web framework가 연동하는 외부 서버이다. web framework이 작업을 수행하는 중에 또 다른 서비스의 결과를 얻어서 처리하는 경우를 가정하고, 이 서버에 request를 요청하도록 하였다.

이 서버에서 처리하는 request가 오래 걸리는 job이라 가정하고, 100 ms를 sleep하고 response를 보내도록 하였다.

이 서비스는 Ruby로 만들었고, 앞서 비교 대상 중 Ruby의 세팅과 동일하다. 서버 스펙은 다음과 같다.

  • CPU: 8 cores (2 Processors(Intel(R) Xeon(R) CPU X3470 @ 2.93GHz), 4 cores per processor)
  • Memory: 16 GB

4. Test Scenario


4.1 Ping Test

Clients에서 Server로 단순 http request을 한다. Server는 http request를 받아서 바로 “Ping”이라는 문자열을 response로 보낸다.

4.2 API Call Test

Clients에서 Server로 http request를 보내면, Server에서 이를 받아 다시 External Server로 http request를 한다. Server는 External Server로부터 response를 받으면, Client에 response를 보낸다.

Ruby의 경우에 API Call을 동기적(synchronous)으로 한다. 나머지는 비동기적(asynchronous)으로 한다.

4.3 Long Ping Test

API Call Test의 경우에 External Server의 performance에 의해 그 결과가 영향을 받을 수 있다. 항상 일정하게 response를 줄 수 있다면, 보다 정확하게 각 web framework의 성능을 비교할 수 있을 거라는 생각이 들었다.

그래서, 항상 일정 시간 후에 response를 주는 가상의 External Server를 생각해보았고, External Server의 API를 호출하는 대신 단순히 일정 시간 sleep해버리면 결국은 항상 일정 시간 후에 response를 주는 External Server일 거라고 가정하고 테스트를 해보았다.

Ruby의 경우에 API Call Test 때와 마찬가지로 synchronous한 sleep을 이용했다.

5. Test Result


X축은 client에서 server로 보내는 request 수이고, Y축은 server에서 request를 받아주는 수이다. 단위는 requests/seconds이다.

5.1 Ping Test

autobench_admin --clients [clients] --single_host --host1 [host] --port1 [port] --uri1 /ping  --low_rate 20 --high_rate 1600 --rate_step 20   --num_call 100 --num_conn 1000 --timeout 5 --file [filename]

ping

자세한 결과보기

5.2 Api Call Test

autobench_admin --clients [clients] --single_host --host1 [host] --port1 [port] --uri1 [path]  --low_rate 10 --high_rate 200 --rate_step 10   --num_call 10 --num_conn 100 --timeout 5 --file [filename]

api

자세한 결과보기

Node.js의 경우에 client의 request를 제대로 받아주지 못하고 있다. 보통 asynchronous하게 동작을 한다고 하면, External Server의 응답이 지연이 되더라도 일단 client의 request를 받아주어야 할 것 같은데 결과가 조금 의아하게 나왔다.

5.3 Long Ping Test

autobench_admin --clients [clients] --single_host --host1 [host] --port1 [port] --uri1 /long_ping  --low_rate 50 --high_rate 2000 --rate_step 50   --num_call 10 --num_conn 100 --timeout 5 --file [filename]

long-ping

자세한 결과보기

Scala의 throughput이 중간 중간 떨어지는 것을 볼 수 있는데, 이것은 garbage collector의 영향인 것으로 보인다. 테스트를 하면서 서버 상태를 보니, Java와는 다르게 Scala에서 메모리를 많이 사용하고 있었는데, 이것이 GC 동작을 하게 한 것으로 보인다. 참고로, Play2가 아직 개발 중인 버전이라 그런 것으로 생각된다.

6. 결과 분석


6.1 Erlang

역시 소문대로 Erlang은 빨랐다. 그런데 많이 사용하지 않는 language라 reference와 라이브러리들을 찾기가 조금 어려웠다. 또, 문법이 익숙하지 않은 개발자에게는 초기에 learning curve가 있을 것으로 예상이 된다. 하지만, 성능이 중요하다면 고려해 볼만하다.

6.2 Java & Scala

같은 JVM 계열인 Java + Play1과 Scala + Play2가 성능차이가 나고 있는 점이 눈에 띈다. 비록 Play 버전이 다르기는 하지만, http를 실제로 핸들링하는 netty와 async http client는 버전 차이가 크게 나지 않기 때문에, 언어적인 특성으로 성능에 차이가 있었던 것으로 짐작된다. (최근에 play framework의 소스를 보게 되었는데, http request 전후로 framework 단에서 해주는 작업이 꽤 되었다. Play2는 Play1과 전혀 다른 구조로 되어 있기 때문에 성능 차이가 있었던 걸로 생각된다.  updated at 2012-05-03)

6.3 Node.js

node.js는 조금은 실망스러운 결과를 보여주고 있는데, 그 이유는 아직 node.js가 multi core를 지원하지 않아서 인 것 같다. 그래도, single core만 쓰는 걸 고려하면 성능이 좋은 편이라 할 수 있다. Core가 2개인 저사양의 서버에서도 테스트를 잠시 했는데, Java + Play 1과 비슷한 성능을 보여주었다. 앞으로 node.js가 multi core가 지원되면 확실히 빨라질 것으로 예상된다.

짚고 넘어가야 할 부분은, JavaScript 문법이 조금 verbose하기 때문에 생산성에 문제가 있을 것으로 생각된다. CoffeeScript 같은 meta language를 써서 JavaScript 코드를 생성하는 방법도 있는데, 이렇게 해보니 debugging이 불편한 단점이 있었다. 요즘 많이 주목받고 있는 만큼 빠르게 발전할 것으로 기대된다.

6.4 Ruby

처음에 Ruby의 default web server인 WEBrick으로 테스트를 했을 때는 성능이 매우 안좋았다. 그래서, Apache web server를 Passenger를 이용하여 연결했더니, 성능이 꽤 좋아졌다. 다른 것에 비교해서 성능이 떨어지기는 하지만, 개발 생산성을 고려해보면 프로젝트의 요구사항에 따라서 선택해볼 여지가 있지 않나 생각된다.

28 thoughts on “Web Framework Benchmark

  1. 잘 보고 가네. python 쓰는 건 없나? 그나저나 스칼라는 왜 한번씩 푹푹 꺼지는 거임?

    • 글내용에도 썼는데, 파이썬은 루비랑 결과가 비슷할거 같구 또 냐가 잘 모른다 ㅎㅎ

      글구 scala결과 이뻐진거 같은 건 gc영향인 듯. 실험을 여러번해서 평균 및 편차를 알 수 있도록하는 것이 좋겠다고 김원호 컴퓨터공학 박사께서 조언해주드라 ㅎㅎ

  2. 펄이나 파이썬은 루비에 비해 훨씬 높은 성능을 가지고 있는 것으로 알고 있습니다. 루비는 유연한 반면 느린 속도로 악명이 높죠.

    최근 파이썬에서는 Flask가 인기를 얻고 있고 펄에서는 Dancer가 인기를 얻고 있는데 이 둘은 루비의 Sinatra와 같은 경량 프레임워크입니다. 다음에 테스트 하실 일이 있다면 이 둘을 목록에 넣어주셨으면 합니다.

  3. 오~ 좋은 정보 감사합니다. 포스팅이 깔끔하네요.
    NodeJS에 관심이 있는데 Cluster 모듈로 멀티코어를 사용하면 어떨지 궁금하네요.

    • 댓글을 늦게 봤네용.

      아쉽게도 테스트 장비를 모두 반납해서 이제는 테스트가 어려울 듯 해요.
      그런데 최근에 다른 벤치마크 자료를 보니, 코어 수에 따라서 거의 linear하게 performance가 좋아지는 것 같습니다.

  4. Pingback: Java 개발자를 위한 Scala 소개 | Inspired

    • 읽어주셔서 감사합니다.

      종종 들리실 때마다 새로운 컨텐츠가 있도록 열심히 쓸께요🙂
      (요즘 글 게을리 써서 반성중..ㅠㅠ)

  5. Pingback: web framework 비교분석 | Crooner

  6. Thanks for your marvelous posting! I definitely enjoyed
    reading it, you are a great author.I will make certain to bookmark
    your blog and will eventually come back later in life.
    I want to encourage yourself to continue your great writing, have a
    nice day!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s