Steve Jobs가 Larry Page에게 해준 이야기

2011년, 구글 CEO 자리로 복귀하게된 Larry Page가 Steve Jobs에게 만나고 싶다는 요청을 했다고 한다. 어떻게 하면 좋은 CEO가 될 수 있는지 ‘조언’을 듣고 싶다며. Jobs는 이 이야기를 듣고, 속으로는 바로 ‘Fuck you’를 했다고..

하지만, 자신 또한 젊은 시절, 많은 사람들로부터 도움을 받았기에 이것을 되돌려 주어야 한다는 생각에 만나서 진심을 담아 다음과 같이 조언해주었다고 한다.

(명문을 잘 번역할 자신이 없기에 원문 그대로 옮김)

We talked a lot about focus. And choosing people. How to know who to trust, and how to build a team of lieutenants he can count on. I described the blocking and tackling he would have to do to keep the company from getting flabby or being larded with B players. The main thing I stressed was focus. Figure out what Google wants to be when it grows up. It’s now all over the map. What are the five products you want to focus on? Get rid of the rest, because they’re dragging you down. They’re turning you into Microsoft. They’re causing you to turn out products that are adequate but not great. I tried to be as helpful as I could. I will continue to do that with people like Mark Zuckerberg too. That’s how I’m going to spend part of the time I have left. I can help the next generation remember the lineage of great companies here and how to continue the tradition. The VAlley has been very supportive of me. I should do my best to repay.

- Steve Jobs 자서전에서.

Java 개발자를 위한 Scala 소개

앞서 Scala 시작하기 포스팅을 쓰고나서, 주위로부터 Scala에 대한 관심이 커진 걸 조금씩 느낀다. 하지만, 아직도 Scala를 본격적으로 도입한 사례는 많지 않은 것 같다. 그래서, Scala의 장점과 실제 어떤 식으로 코딩을 하는 지에 대해서, 그동안 배운 것들을 공유해보려고 한다.

1. Java와 호환


Scala는 compile language이다. compile을 하면, Java Virtual Machine(JVM)상에서 동작하는 byte code가 만들어진다. 이미 검증된 VM이라 할 수 있는 JVM에서 동작하기 때문에, ruby나 python등 VM을 필요로 하는 다른 언어 등과 비교하면 안정적이다. 게다가 compile 언어이기 때문에 이러한 interpret 언어보다 빠르다.

Scala는 JVM에서 동작하면서, Java의 문법과 아주 유사하기 때문에 Java의 모든 라이브러리를 그대로 사용할 수 있다. 수많은 Java로 된 open source 라이브러리들이 모두 Scala의 라이브러리이기도 한 것이다!

2. 개발 생산성(productivity)


Scala는 object oriented language이면서 동시에 functional language이다. object oriented 방식으로 하다가도 필요한 경우, functional language적인 것들을 섞어 쓸 수 있다. 이것은 마치, 중국집에서 짜장면을 먹고나서 이태리 식당에나 어울릴 법한 티라미슈 케잌을 후식으로 먹는 것에 비유할 수 있겠다.

그러면, Scala에서 유용하게 쓰이는 functional language적인 feature 몇가지만 소개보겠다.

2.1 Loan Pattern

From Java
텍스트 파일을 읽어서 한줄씩 출력 해야 한다고 하면 Java로는 아래와 같이 만들게 될 것같다.

BufferedReader bufferedReader = null;
try {
  bufferedReader = new BufferedReader(new FileReader(filename));
  String line = null;
  while ((line = bufferedReader.readLine()) != null) {
    System.out.println(line);
  }
} catch (IOException ex) {
  ex.printStackTrace();
} finally {
if (bufferedReader != null)
  bufferedReader.close();
}

만약 위의 기능에 더해서, 텍스트 파일을 읽어서 한줄씩 읽어서 DB에 저장하는, 위와 유사한 코드를 만들고 싶다면 어떻게 해야 할까?

실질적으로는 위의 코드에서 System.out.println() 부분만 DB로 저장하는 걸로 바꾸면 되지만, 아쉽게도 앞뒤로 있는 코드들은 다시 써주어야 한다. 다시 말해 중복코드가 필연적으로 생긴다.

To Scala
Scala로는 다음과 같이 정리가 가능하다.

먼저 실제 line을 가지고 작업을 하는 것을 제외한, 앞뒤 부분에 해당하는 함수를 다음과 같이 만든다.

def withFile(filename:String)(work: String => Unit) {
  var bufferedReader = null
  try {
    bufferedReader = new BufferedReader(new FileReader(filename))
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
      work(line)
    }
  } catch {
    case ex:IOException => ex.printStackTrace()
  } finally {
    if (bufferedReader != null)
      bufferedReader.close()
  }
}

이 함수는 2개의 arguement를 받는다. 하나는 filename이고, 다른 하나는 work라는 이름의 함수이다. 7번째 줄에 보면 인자로 받은 work라는 함수를 호출하고 있는 모습이 보인다. 이것이 Object Oriented 프로그래머에게는 조금 어려운 개념인데, Scala는 Functional language이기 때문에 함수도 하나의 변수처럼 처리할 수 있다.

중요한 건 이렇게 앞뒤 귀찮은 작업을 하는 함수를 빼어(refactoring) 놓으면 다음과 같이 재사용할 수 있다.

- 한 줄씩 화면에 출력

withFile(filename) {
  line => System.out.println(line)
}

- 한 줄씩 DB에 저장 (storeToDb라는 함수가 있다는 가정하에)

withFile(filename) {
  line => storeToDb(line)
}

위와 같은 방법을 ‘loan pattern’이라고 한단다. 출처는 여기.

2.2 iteration

Scala에서는 collection의 iteration 관련해서 유용한 함수가 많다. 사실 내가 Java를 버리고 Scala를 쓰게 된 동기도, 빵꾸똥꾸 같은 Java의 iteration 때문이다. 한동안 C#, Ruby 등으로 개발하다가, 다시 Java를 써야했는데, 오랜만에 써보는 Java iteration은 C 코딩하다가 어셈블리어를 썼던 딱 그때를 생각나게 했다.

그럼 예제 코드를 잠시 보겠다. numbers라는 collection에서 짝수인 것들만 추려내야 하는 경우에, Java에서는 다음과 같이 한다.

for (Iterator iterator = numbers.iterator(); iterator.hasNext();) {
  Integer number = iterator.next();
  if (number % 2 == 0) {
    iterator.remove();
  }
}

위 코드의 출처는 여기.

Scala에서는 다음과 같이 엘레강트하게 처리한다.

numbers.filter { n => n % 2 == 0 }

이 외에도 Ruby 프로그래머의 경우에 익숙할 map, count등 iteration을 위한 유용한 함수들이 많이 존재한다.

2.3 기타

꼭 functional language 적인 것 말고도, Java에서 불편하던 것들을 문법적으로 개선한 부분이 많다. Singleton 지원, 변수의 lazy 초기화 지원 등등 여러가지가 있는데, 길어질 것 같으니 생략하도록 하겠다. ^^

3. 성능(performance)


기본적으로 Scala는 JVM에서 동작하기 때문에 Java 만큼의 성능이 나온다. 물론 C나 C++과 같이, compile 결과로 machine code가 나오는 언어에 비해서는 느리지만, Ruby, Python, JavaScript등의 interpret 언어보다는 월등히 빠르다.

여기에, Scala에서 제공하는 Actor를 이용해 message 방식의 프로그래밍을 하면 훨씬 빠를 수 있다.

3.1 Actor?

Actor는 Java로 치면 일종의 Thread이다. Scala에서는 Actor에게 어떤 작업을 하라고 message를 보내면, Actor는 작업을 해야할 것들을 자신의 queue(mailbox라고 불린다)에 넣어두고, 하나씩 꺼내서 처리한다. Actor에게 message를 보낸 쪽에서는 message의 결과를 꼭 기다려야 하는 상황이 아니면, 자신이 하던 작업을 그냥 쭈욱 한다. 다시 말해 비동기적(asynchronous)으로 처리한다. 좀더 자세한 설명은 여기를 참고.

Actor가 대용량 처리시 빠른 이유는,
1) 비동기적으로 프로그래밍할 수 있도록 하며
2) 각 Actor가 mailbox에 메시지를 queueing을 해가면서, 동시에 엄청나게 많은 메시지를 처리할 수 있기 때문이다.

사실 actor, message의 개념은 erlang에서 차용한 개념이다. 이전의 포스팅에서 잠시 언급한 적인 있는데, erlang은 대용량 처리에서 훌륭한 performance로 유명하다.

4. Actor로 두 마리 토끼(productivity, performance) 잡기

웹 서비스에서 그 규모가 커지면, 흔히 client로부터 최초의 request를 받는 frontend 서버와 좀더 세분화된 작업을 처리하는 backend 서버로 그 구조가 진화하게 된다. Twitter역시 초기에는 Ruby on Rails의 한 종류의 서버만 있었지만, traffic이 커가면서 frontend/backend 서버 방식으로 진화했다. 좀더 자세한 내용은 여기 참고.

– Twitter에서의 frontend/backend 서버 구조 (출처: Twitter Engineering Blog)

frontend 서버가 client로부터 최초의 request를 받아서 여러 backend 서버에 다시 작업을 지시하고, 결과를 받아 최종 response를 client에 보내는 경우를 생각해보자. 가급적 backend 서버의 호출은 비동기적으로 이루어저야 frontend 서버는 좀더 대용량을 처리할 수 있다.

4.1 가상 시나리오

Actor의 훌륭함(?)을 설명하기 위해 다음과 같은 트위터에서의 가상의 request를 생각해보았다.

  1. 어떤 사용자 A의 가장 최근에 등록된 follower B를 찾아서
  2. B 사용자의 트윗 목록 중 최신 트윗 하나를 얻어와
  3. 이 트윗의 RT 카운트를 얻는다.

물론 이 시나리오는 조금 억지스러운 면이 있지만, 서비스를 만들다 보면 이렇게 backend 서버와 3단 이상의 콤보를 해야하는 경우는 사실 비일비재하다.

서비스 구조는 다음과 같이 되어 있다고 가정하겠다.

  • Follower를 알려주는 backend 서버와의 연동은 followerActor에서 담당
  • 트윗 목록을 알려주는 backend 서버와의 연동은 tweetActor가 담당
  • RT 카운트를 알려주는 backend 서버와의 연동은 statsActor가 담당

4.2 구현

이것은 다음과 같이 구현될 수 있다.

val futureResult = for {
    follower <- (followerActor ? GetLatestFollower(userId)).mapTo[User]
    tweet <- (tweetActor ? GetLastestTweet(follower.id)).mapTo[Tweet]
    count <- (statsActor ? GetRetweetCount(tweet.id)).mapTo[Int]
} yield count

futureResult onSuccess {
  case n:Int => //처리
}

futureResult onFailure {
  case e:Exception => //처리
}

1~5줄을 보면, 각 backend 서비스에 대해서 하나씩 별도로 처리할 필요없이, for를 이용해 처리하고 있다. 2~4 줄에서 actor에 대한 호출은 비동기적으로 처리되고, 성공적인 결과가 나올 때만 ‘<-’ 연산자 앞의 변수 이름으로 값이 저장된다.

성공적으로 모든 backend 서버에 대한 작업들이 끝나면 8줄 부분이 호출된다. 중간에 어떤 작업에서라도 exception이 일어나면, 12번 줄 부분이 호출된다.

참고로 아래 코드는 actor에게 메시지를 보내고 결과를 기다리기 위해 ‘?’라는 연산자를 사용했다. 또 onSuccess, onFailure 등을 통해 callback을 등록했는데, 이것은 scala 언어 자체에서 지원하는 것은 아니고, Akka라는 라이브러리를 이용하면 가능하다.

마치며


최근에 node.js가 각광받고 있다. 무엇보다 node.js의 장점은 비동기적으로 쉽게 코딩할 수 있도록 해주는 것이 아닐까 한다. 혹시 Java 개발자의 경우에, node.js의 장점에 끌린다면, 이웃사촌인 Scala를 먼저 검토해보라고 권유해보고 싶다. 안정적인 VM, 이미 풍부한 open source들, 거기에 생산성을 배가시켜주는 scala의 문법. 또, 최근에는 Eclipse나 IntelliJ 같은 IDE에서 Scala 지원이 잘되고 있다.

많이 부족한 글을 끝까지 읽어주신 분들께 진심으로, 정말로 감사한 마음을 전하고 싶다. 내용 중에 설명이 부족했거나 또는 틀린 내용있으면 꼭꼭꼭 코멘트를!

오픈소스 첫경험

인터넷/모바일 관련 업계로 자리를 옮기면서 최근에는 오픈소스를 많이 이용하고 있다. 그 품질도 좋고, 또 커뮤니티에 질문을 하면 개발자들(committer)이 바로바로 답변을 해주니, 아주 도움을 많이 받고 있다.

어제는 버그 같이 보이는 것을 발견하고, 해당 오픈소스커뮤니티(구글 그룹스)에 질문을 올렸다. committer들이 바쁜지, 평소와는 다르게 하루가 넘게 답을 안해줘서, 오늘은 어디가 문제인지 직접 소스를 살펴봤다.

웹프레임워크 소스라 동작 방식이 조금 복잡했는데, 여차여차 문제가 되는 부분을 찾았고, 어플리케이션 단계에서 회피하는 방법도 찾았다. 그리고, 내용을 잘 정리해서 커뮤니티에 올렸다.

원문: https://groups.google.com/d/msg/play-framework/9OP-tEAxKaM/y39pLR2A19EJ

글을 올리고 보니, 그 사이에 committer로부터 버그인 것 같으니 이슈로 등록해달라는 글이 먼저 올라와 있었다.

원문: https://groups.google.com/d/msg/play-framework/9OP-tEAxKaM/0eB7xuNiel4J

그동안 덕본 것도 있고해서, 귀찮지만 이슈 트래커 사이트에 회원가입부터 하고 이슈를 등록했다.

원문: https://play.lighthouseapp.com/projects/82401/tickets/375-globalonstop-is-not-invoked

여기까지 하고나니, 조금 욕심이 생겼다. 내가 직접 프레임워크의 소스를 수정해보기로 했다. 먼저 github에 올라와 있는 원래 소스에서 fork를 해서 내 개인 repository를 만들었다. 코드를 수정해서 내 repository에 올리고, 이것을 반영해 달라는 pull request를 했다. Git은 한 1년 정도 써봤지만 pull request는 처음 해보는 거였는데, 다행히 많이 어렵지는 않았다.

이 오픈소스의 전체 소스를 다 파악하고 있지 못하기 때문에, 받아들여지지 않을 수도 있겠거니 했다. 그런데 곧 committer 중에 한 사람이 코멘트를 남겼는데, 소소한 것 좀 수정해줄 수 있냐는 내용이었다. 요청에 따라, 소소한 부분을 수정하고 2번에 걸친 commit을 하나로 깔끔하게 합쳐서(squash) 다시 올렸다.

원문: https://github.com/playframework/Play20/pull/249

이제 내가 만든 아주 약간의 소스는, 이 오픈소스와 한몸이 되기를 조마조마 기다리고 있다. 사실 그렇게 대단한 것은 아니지만, 항상 도움을 받기만 하다가 조금이라도 기여를 한다고 생각하니 이렇게 뿌듯할 수가 없다.

문제를 발견해서 공유하고, 버그로 등록하고, 그리고 pull request를 하는 일련의 과정을 조금씩이나마 해보면서 오픈 소스에 참여하는 방법을 조금은 익힌 것 같다. 이제 앞으로는 더욱 열심히 참여하겠노라 다짐해본다. 아자!

updated at 2012-5-3
다행히 pull request가 받아들여졌습니다. :)

주인이 되자

책을 읽으면서 눈물이 주루룩 흘렀다.

나는 사실 우리 한국 현대사를 잘 몰랐던 것 같다. 대학 신입생 때 선배들을 따라 정치 학회에 가서, 박정희, 전두환 군사 정권의 탄압에 대한 이야기를 들었지만, 그저 먼나라 이야기 같았고, 가슴이 아닌 머리로만 이해했던 것 같다.

몇 해 전, 고 김대중 전 대통령의 ‘김대중 자서전’을, 베스트 셀러라는 이유로 샀다. 1400페이지에 이르는 분량에 압도되어, 한 보름 동안은 방치했던 것 같다. 어느 일요일 오전이었던가 무심코 책을 폈다. 어렸을 적 섬마을의 똘똘한 김대중 어린이의 이야기가 흥미로웠다. 사업가로서 성공하는 이야기도 참 신났다.

즐거운 이야기는 거기까지였다.

책을 읽다보니 김대중 선생의 입장에서, 6.25 전쟁 중에 공산군에 의해 감옥에 갇혀 언제 죽을 지 모르는 공포를 경험했고, 4.19 혁명으로 잠시나마 민주화된 대한민국을 경험했다. 또, 지역 감정이 없던 시절, 강원도 인제에서 국회의원으로 당선되고 젊은 나이에 당 대변인이되지만, 5.16 쿠테타로 국회에 입성하지 못해 억울해하기도 했다.

유신정권의 탄압을 피해 일본에서 활동하던  중에 중앙정보부 요원에 의해 납치되어 생사의 갈림길에서 겨우 탈출해서 살아 남았고, 트럭이 승용차를 덮치는 의문의 사고로 죽을 뻔한 위기를 넘었다. 박정희 독재 정권 하에서 온갖 죄목을 뒤집어 쓰고 차디찬 형무소에 몇년을 지냈다. 그리고, 전두환 군사정권이 들어서고 내란죄로 사형선고까지 받고서, 사형수로서 집행일만 기다리는 극한의 공포를, 나는 느꼈다.

그렇게 그렇게 우리 선배들은 민주화를 위해 투쟁을 했다. 내가 지금 아무렇지도 않게 누리는 민주주의는 그렇게 얻어진 것이다. 시간이 됐으니 하늘에서 뚝 떨어진 것이 아니라, 인간의 존엄성을 지키고자, 수많은 사람들이 목숨을 걸고 싸워서 얻어낸 것이다. 안타깝지만 많은 사람들이 민주화된 대한민국을 못본채 그렇게 눈을 감았다.

책을 읽으며, 이들이 겪었을 울분을 생각하니 눈물이 주루륵 흘렀다. 거대한 권력앞에 공포를 느끼면서도, 옳은 것을 행하는 용기에 눈물이 주루륵 흘렀다. 나는 과연 이런 상황에 이렇게 행동할 수 있었을까 생각하니 마냥 부끄럽고, 죄송스러운 마음이 들었다.

우리는 민주화를 위해 싸운 기성세대에 빚을 지고 있다. 갚아야 할 빚이다. 빚을 갚는 방법은 단순 명료하다. 민주주의를 지켜내고 후손에게 물려주는 것이다. 아직 우리 사회에 남아 있는, 독재 시대의 반 민주주의적 가치관을 가진 기득권 세력으로부터 민주주의를 지켜내야 한다. 그러나 이것은 기득권에 빌붙은 수구 언론과 양심을 버린 학자들 때문에 쉬운 일은 아니다. 하지만, 우리가 현대사를 공부하고, 시대 정신을 이해하려 노력하면 할 수 있다. 그리고, 최근에는 대안 매체를 통해 옳은 목소리를 내는 언론도 있다. 무엇이 옳은 것인지 깊은 고민을 해야하고, 단호하게 행동 해야 한다.

우리나라의 민주주의는 아직 진행형이다. 냉철한 판단과 뚝심있는 행동으로 스스로 주인이 되자. 우리 선배들이 힘들게 쌓아올린 민주주의를 지켜내서, 우리 후배 세대에게 당당할 수 있도록 역사에 기록되자. 내가 있고, 너가 있으니 우리는 할수있다, 친구야.

Scala 시작하기

요즘 들어서 Scala를 공부하고 있다. 아직 많이 부족하지만, 지금까지 배운 것들 기록해두고, 또 혹시 조금이라도 도움이 되는 분들이 있을 지 몰라 공유해보고자 한다.

1. 들어가며


뭘 또 배워야 한단 말인가? 이미 C++, Java, Python, Ruby, JavaScript 등 많은 프로그래밍 언어들이 있는데, 왜 자꾸 새로운 언어가 나오고 있냐? 기존 걸로 안되냐?

라는 의문을 가질 수 있다. 나 역시 처음에 그런 생각을 했었다. 하지만, Scala에 대해 공부를 하다 보니, 이제는 그런 의문들이 많이 없어졌다. 어떻게 의문을 해소했었는지, 그럼 조금 자세히 이야기 해보겠다.

2. Scala?


Scala는 다음과 같은 특징이 있다.

2.1 Fuctional language이며 또한 object-oriented language이다.

Ruby나 C#을 쓰다가 Java나 C++ 같은 언어를 쓸 때 조금 답답한 것이, lambda와 같은 functioncal language적인 syntax가 없다는 것이다. 이것을 안 쓸때는 몰랐는데, 일단 손에 익으면 생산성이 매우 높아진다. Scala는 lambda를 비롯하여 여러 functional language의 문법을 지원한다. 동시에, object-oriented적인 요소도 지원하기 때문에, objected-oriented language에 익숙한 프로그래머들이 functional language를 배우고자 할 때 쉽게 다가갈 수 있다.

나는 C++이 초기에 다른 object-oriented language들을 제치고 성공할 수 있었던 가장 큰 이유가, C++이 C 문법도 지원했기 때문이라고 생각한다. C++ 컴파일러를 이용하면, C에 익숙한 프로그래머들은 C로 코딩을 하면서도, 부분부분 쉽게 object-oriented적인 요소를 사용할 수 있었다. 마찬가지로 Scala는 기존의 Java나 C++등 object-oriented language에 익숙한 프로그래머들을 functional language로 쉽게 끌어 들일 수 있는 장점이 있다.

2.2 Java Virtual Machine에서 동작한다.

Java Virtual Machine(이하 JVM)은 Java를 컴파일해서 나오는 bytecode가 동작하는 virtual machine이다. Scala는 특이하게도 소스 코드를 컴파일하면 그 결과로 JVM에서 동작하는 bytecode가 결과물로 나온다. 다시 말해 Scala는 JVM상에서 동작한다.

이것은 두 가지 중요한 의미를 갖는다. 하나는 컴파일 된 Scala 코드는 이미 10년 이상 최적화가 되어 있는 JVM 상에서 동작하기 때문에, 성능과 안정성을 어느 정도 보장한다.

또, 기존에 Java로 작성된 소스와 호환이 되기 때문에, 엄청나게 많은 Java 라이브러리들을 Scala에서 그대로 사용할 수 있다. 야호!

3. Who uses Scala?


Scala를 누가 쓰기는 쓰는가? 생각보다 많이 쓰고 있고, 점차 더 도입되는 추세인 것 같다. 대표적으로 다음과 같은 회사들이 사용한다.

3.1 Twitter

Twitter 서비스는 초기에 Ruby on Rails를 이용하여 개발되었다. 그런데 Ruby on Rails를 이용해 빨리 개발할 수는 있었지만, 이후에 traffic이 많아 지면서 성능이 문제가 되었다. 이를 해결하기 위해 Scala를 도입하였다고 한다. 트위터 개발자들의 인터뷰 참고.

3.2 FourSquare

FourSquare 서비스는 초기 버전은 PHP로 작성되었다고 한다. 하지만 사용자가 급증하자 software stack에 변화가 필요했고, Harry Heymann이라는 엔지니어가 이 작업을 주도하면서 Scala로 전면적으로 다시 개발했다고 한다. 이 과정에서 생산성 향상과 성능 향상이 있었다는 이야기도 있다. Scala 공식 홈페이지에 관련된 글이 있으니 참고.

3.3 Tumblr

Tumblr 또한 부분적으로 Scala를 쓰고 있다고 한다. Back-end용으로 쓰이고 있고, Twitter에서 만든 Scala용 라이브러리인 Finagle을 이용해 사용한다고 알려져 있다. Tumblr의 개발 방식에 대해 정리된 페이지 참고.

4. Scala 시작하기


Scala에 대한 흥미가 조금은 생겼으리라 예상해본다. 그럼 다음과 같은 자료를 활용해서 공부를 시작해보자.

4.1 Scala for the impatient

프로그래밍 경험이 어느 정도 있는 분들에게 추천하는 책이다. 제목에서도 알 수 있듯이 빨리 문법을 익혀 코딩해보고자 한다면 좋은 선택이다. 중요한 문법에 대해서 간결하게 잘 설명되어 있다. 공짜다.

4.2 Twitter Scala School

Twitter에서 만든 교육 자료이다. 아마도, 자사의 엔지니어들을 위해 만들지 않았나 생각된다. 내용이 간결하고, 예제 위주로 되어 있어서 빨리 익히기에 좋다.

4.3 Programming Scala

Scala의 동작 원리부터 차근차근 잘 설명한 책이다. Scala에 대해 좀더 깊이 이해를 하고자 하는 경우나 또는  프로그래밍 경험이 많지 않은 분들에게 추천하고 싶다. 역시 공짜다.

Programming language들이 많이 나오면서, 요즘은 각 language community들이 적극적으로 확산에 나서고 있고, 그래서 무료 자료가 참 많다. Scala를 공부하기 위해서, 굳이 돈주고 종이책 살 필요는 없을 듯 하다.

5. 개발 환경


5.1 build

Scala는 컴파일 language이기 때문에, build를 해주어야 한다. 물론 소스 하나씩 compile해서 build하는 방법도 있겠지만, 이것보다는 별도의 build 툴을 쓰면 편하다. 많은 scala 오픈 소스 프로젝트들이 최근에 simple build tool(이하 sbt)를 사용하고 있다. 사용법이 길지 않으니 꼭 사용법을 읽어보는 것이 나중에 수고를 덜어줄 것이다.

5.2 IDE

개발툴로 많이 쓰이는 것이 Eclipse와 IntelliJ IDEA이다. 2개 모두 사용해봤는데, 둘 다 괜찮다. Eclipse는 Scala IDE for Eclispe라는 plugin을 설치해야 하고, IntelliJ IDEA도 JetBrains에서 제공하는 Scala plugin을 설치해야 한다. 둘다 Syntax highlighting, debugging 등의 기능이 있어서 Vim이나 Emacs같은 에디터 보다 낫지 않나 싶다.

6. Hello World


그럼 간단한 프로그램을 만들고, debugging까지 해보겠다. 기본적인 순서는 다음과 같다.

  1. Eclipse 설치
  2. Scala IDE for Eclipse Plug-in 설치
  3. sbt 설치
  4. sbt용 디렉토리 구성
  5. sbt를 이용해 Eclipse 프로젝트 생성
  6. 소스 코드 작성
  7. Debugging

6.1 Eclipse 설치

Eclipse는 3.6(Helios) 버전을 설치한다.

6.2 Scala IDE for Eclipse

Eclipse용 scala plugin인 Scala IDE for Eclipse를 설치한다.

6.3 sbt 설치

이 링크를 이용하여 sbt를 설치한다.

참고로, sbt를 설명하는 wiki 페이지가 길지 않으니, 반드시 읽어보고 sbt의 개념이나 사용 방법을 알아두는 것이 나중에 시간을 줄일 수 있는 방법이다.

6.4 sbt용 디렉토리 구성

프로젝트의 기본 정보 및 사용하는 이 프로젝트에서 사용하는 플러그인을 설정하여 sbt용 디렉토리 및 설정파일을 구성한다. 이 부분은 sbt 메뉴얼을 참고하도록 한다.

6.5 sbt를 이용해 Eclipse 프로젝트 생성

앞에서 만든 sbt용 디렉토리로 들어가서 다음과 같이 입력하면 Eclipse용 프로젝트 파일인 .project와 .classpath가 생긴다.

> sbt eclipse

Ecilpse의 메뉴에서 ‘File’ > ‘‘Import…’를 클릭하고, 앞에서 만든 디렉토리를 선택하면 프로젝트를 열 수 있다.

6.6 소스 코드 작성

Ecilpse에서 앞에서 생성한 프로젝트를 열어보면 이미 ‘src/main/scala’ package가 생성된 것을 확인 할 수 있다. 이 package 밑에 App.scala 파일을 만들고 다음과 같이 입력한다.

object App {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

6.7 Debugging 하기

이제 거의 다 되었다. println에 breakpoint를 설정하고, 메뉴의 ‘Run’ > ‘Debug’를 선택한 후에 ‘Scala Application’을 선택하면 프로그램이 시작되고, debugger가 동작해서 breakpoint에서 멈추는 것을 확인할 수 있다. 위 소스 파일은 이 곳에서 다운로드 받을 수 있다.

7. Scala용 Framework


이제 Scala용 프로그램을 만들 준비는 끝났다. 지금부터는 웹서비스 개발을 위해 이용할 수 있는 Framework 중에 개인적으로 제일 괜찮다고 보이는 2가지를 소개하려고 한다.

7.1 Play Framework

Play Framework는 Ruby on Rails의 Java 버전이라고 보면 되겠다. MVC 패턴에 맞춰 개발할 수 있도록 해주고, 여러가지 편리한 library를 제공한다. 실제 대용량 서비스에서 많이 쓰이고 있는 framework이라 안정성에도 문제가 없다고 할 수 있겠다.

현재 stable한 1.x 버전에서는 scala를 부분적으로 지원해서 조금 아쉽다. 하지만, Play 2.0에서는 본격적으로 Scala를 지원한다. 2.0은 현재 RC버전이며, 곧 정식 버전을 release할 것으로 보인다.

7.2 Finagle

Finagle은 Twitter에서 back-end 서비스용으로 만든 framework이다. 서버 간의 통신을 지원하는데 특화 되어 있다. 무엇보다 Twitter에서 실제로 사용되기 때문에 주목 받고 있고, Tumblr등 다른 서비스에서도 이용되는 듯 하다. 기본적인 서버 간 통신 기능 외에 비동기 처리, 분산 처리, 그리고 Memchached, Redis 등을 지원한다. Twitter에서 어떤 식으로 Finagle을 사용하는 지에 대해서는 Twitter Engineering 블로그의 이 포스팅에 잘 설명이 되어 있다.

8. 마치며


당연하겠지만, 소프트웨어 개발에 있어 어떤 언어가 최고인지 정답은 없는 것 같다. 상황에 맞게 언어와 라이브러리 등을 선택해야 할 것이다. 성능과 확장성(scaling)이 매우 중요하고, 비교적 빠르게 개발해야 하는 경우 라면, 내가 생각하기에 Scala가 제일 적합한 선택인 것 같다. 단, Scala 개발자가 많지 않고 언어를 배우는데에 learning curve가 조금 있기 때문에, 개발자가 바뀌는 상황이 되었을 때 향후 유지보수는 조금 어려울 수도 있다는 점은 주의해야 한다.

무엇보다도 Scala의 장점은 succint한 syntax 덕에, 개발자가 프로그래밍 그 자체에 집중할 수 있고 이로 인해 프로그래밍이 재미있다는 점이다. 좀더 많은 개발자들이 Scala를 접해보았으면 하는 바램으로 두서없는 글을 마치겠다.

오픈(open)에 대하여

솔직하게 고백하면서 시작하겠다.

Linux를 비롯한 오픈 소스와 그 개발 방식이 유행하기 시작할 때, 일부 컴퓨터 긱(geek)들의 문화라 치부했고, 주류가 되지 못할 거라고 생각했다. Microsoft나 Oracle이 하는 것처럼 소프트웨어는 과금을 해야 하고, 이 수익을 다시 소프트웨어에 투자해야 제대로 된 소프트웨어가 나올 것이라고 생각했다.

하지만, 틀린 것 같다. 지금 세상을 움직이는 많은 소프트웨어들은 오픈소스 프로젝트이고, 그리고 점점 많은 회사들이 오픈된 개발 문화를 지향하고 있다.

오픈 소스와 오픈 소스 개발 방식 그리고 그 근저의 철학에 대해서 생각해 본 바를 정리하고자 한다. 잘못된 시각일 수도 있고, 편협한 시각일 수도 있다. 그러니 이 글을 읽으신 분께서는 어떤 내용이라도 좋으니 피드백을~

1. Open Source?

간단히 정의하면, 오픈 소스는 소프트웨어의 소스 코드를 공개해 다른 사람이 이용할 수 있도록 하는 것을 말한다. 건축으로 치면 설계도를 공개하는 것이고, 학교 생활로 비유해보면, 열심히 한 숙제를 공개해서 누구나 베낄 수 있게 하는 것이라고 할 수 있겠다.

아, 보통의 사고 방식이라면 참으로 이해할 수 없는 방식이다. 왜 나의 노하우와 노력의 결실을 공개하는 것인가? 왜 다른 사람들이 별다른 노력 없이 내가 만든 걸 쓸 수 있게 하는 것인가? 누가 이렇게 한단 말인가?

놀랍게도 지금의 인터넷 세상을 가능하게 하는 많은 기술들이 사실은 오픈 소스 프로젝트들이다. 서버 OS로 이용되는 Linux, Database 솔루션인 MySQL, 웹서버 솔루션인 Apache, 대용량 처리를 가능하게 해주는 Hadoop 등이 오픈소스다. 거꾸로 이러한 오픈소스가 없었다면 Facebook이나 Twitter, KakakoTalk등이 없었을 지도 모르겠다.

2. Open Source 개발 방식?

오픈 소스 프로젝트들은 소스를 공개하는 것과 더불어서, 자신들의 소스가 많이 쓰일 수 있도록 여러 적극적인 활동을 한다. 익명의 개발자가 코드에 기여(contribution)를 할 수 있도록 프로세스를 갖추고 있고, 소스의 내부 구조(architecture)와 사용 방법에 대해 블로그와 컨퍼런스 등을 통해 알린다. 이러한 활동을 열심히 하는 오픈 소스 프로젝트들이 더욱 많이 사용되고 살아남는다.

요즘은 소프트웨어 회사에서 소스를 꼭 공개하지 않더라도, 이러한 개발 방식을 도입한 사례를 종종 볼 수 있다. 자사가 사용한 오픈소스 솔루션에 대해 사용 경험(best practice)을 블로그나 컨퍼런스 등을 통해 공유하고 있다.

3. 누가하는가?

Facebook이나 Twitter와 같은 회사들이 아이디어를 잘 만들어 성공한 회사라고 생각하면 오산이다. 적어도 내가 아는 한 이 두 회사는 컴퓨터공학에 있어서, 구글과 어깨를 나란히 하는 세계 최고의 기술 회사이다. 많은 오픈 소스 프로젝트들의 스폰서이고, 그리고 이 이 회사들의 엔지니어들이 직접 오픈소스 프로젝트에 참여하고 있다. 그리고, 이 오픈 소스를 자사의 서비스에 이용하고 있다. 특히 최근의 대용량 서비스를 가능하게 해주는 솔루션인 Cassandra, Hadoop 등이 바로 그 예이다.  국내에서도 NHN, Daum, KTH와 같은 회사에서는 컨퍼런스나 블로그를 통해서 노하우를 공유하고, 이따금씩 자사의 솔루션을 오픈 소스화 하고 있다.

누구도 부인하지 못하는 점은, 이 회사들이 이렇게 자사의 엔지니어들이 만든 소스를 오픈하면서도 성공을 하고 있고, 또 그들의 서비스들이 유사한 서비스를 제치고 지속되고 있다는 점이다.

4. Why successful?

솔직히 아직도 잘 모르겠다. 그저 짧은 지식으로 나름 파악해본 바는 다음과 같다.

4.1 집단 지성이 발휘된다

오픈 소스들의 특징은 commitor라 불리는 소스를 직접 컨트롤 하는 사람들외에도 익명의 다수 사람들이 기여할 수 있다는 점이다. 물론 오픈 소스가 지향하는 큰 방향은 commitor들에 의해 결정이 되겠지만, 자잘한 버그들이나 성능 개선 등은 익명의 수많은 프로그래머들에 이루어 지는 듯 하다. 마치 Wikipedia가 수많은 사람들의 참여로 브리태니커(Britannica) 백과 사전보다 그 내용이 우수한 것과 같은 이유가 아닌가 생각 된다.

4.2 참여자의 자기 만족이 크다

오픈 소스 프로젝트들은 저마다 정의한 문제를 각각의 시각으로 풀어내고 있다. 때문에 비슷한 솔루션을 여기 저기서 만드는 것이 아니라, 각각 고유한 솔루션을 만들어 낸다. 프로그래머들 사이에서 많이 쓰이는 말 중에 ‘Don’t reinvent the wheel’이라는 말이 있다. 똑같은 작업을 다시 싫어하기 싫어하는 프로그래머들의 특성을 잘 보여주는 말이 있는데, 오픈 소스에서는 이럴 가능성이 적다. 이것이 참여자의 생산성을 높여주는 것이 아닌가 생각된다.

또, 오픈소스에 참여하는 개발자는 자신이 가치 있는 일에 기여하고 있고, 이것이 오픈 소스를 통해 알려지고 명예를 얻는 것에 만족감을 느끼는 것 같다.

개발자들이 오픈소스에 참여하는 이유에 대해서는 @sm_park님께서 잘 정리해주신 소프트웨어, 잉여와 공포를 참고하기를.

5. 기업 입장에서 Open이란?

그러면 개개의 기업들은 오픈 소스와 오픈 소스 개발 문화를 어떻게 보고 어떻게 접근해야 할까?

기업 입장에서 오픈 소스 솔루션 자체를 도입하는 것은 좋은 점, 나쁜 점 모두 있는 것 같다. 당연히 새로 개발을 안하고, 어느 정도 검증된 솔루션을 쓸 수 있다는 것은 장점이다.

하지만, 간과해서는 안되는 부분이, 기술 회사를 지향한다면 오픈 소스를 도입하는 것과 더불어 자사의 기술 역량을 높이는 것을 게을리 해서는 안되는 것 같다. 오픈 소스를 도입하는 것은 마치 어려운 수학 문제를 푸는 데에 있어서, 답안지를 펴놓고 하는 것과 비슷하다고 생각하기 때문이다. 한 문제의 답을 아는 것이 지금의 상황을 이겨나가기는 좋지만, 나중에 또 다른 어려움이 닥칠 것을 생각해보면 근본적으로 역량(capability)를 키워 놓는 것이 중요하지 않나 생각된다. 마치 숙제를 열심히 베끼다 보면 숙제는 빨리 할 수 있지만, 실력은 늘지 않는 것처럼.

이것을 좀 과장해 표현하자면, 오픈하는 쪽의 마수(?)에 걸리지 않도록 조심해야 한다. 그 방법 중에 하나는 오픈 소스를 도입함과 동시에 자신도 오픈하는 것이 아닌가 생각된다. 회사 입장에서 ‘오픈’은 그 의미가 여러가지 일 수 있는데, 넓은 의미로는 타사에 대한 오픈이고, 좁은 의미로는 개인과 팀의 성과물을 다른 팀에게 오픈하는 것이다. 그러면 이 두 가지 의미를 포괄해서, 회사 입장에서 ‘오픈’이 갖는 의미에 대해서 좀더 자세히 이야기해보겠다.

5.1 사내에서 갖는 의미

1) 품질이 올라간다.

누군가 내 코드를 보고 거기에 대해서 평가한다고 생각하면, 프로그래밍에 임하는 자세가 분명히 다를 것이다. 알면서도 무시했던 여러가지 프로그래밍 원칙들을 지키려고 노력할 것이다. 쪽팔리기 싫으니까.

많은 오픈 소스 코드들과 그동안 내가 회사에서 보았던 코드와 비교해보면, 품질에 있어서는 오픈 소스 코드들이 압도적이다. 프로그래밍의 기본 원칙부터, 그 구조에 있어서 디자인 패턴의 적용 등 모든 부분에 있어서 좋다. 나 스스로는 이런 오픈 소스의 소스를 보면서 많이 배우고 있다고 생각한다.

2) 장기적으로 도움이 된다.

예전에, 오픈 소스의 버그를 고치고, 이것을 오픈 소스 커뮤니티에 알려주지 않고 자기 회사에서만 쓰는 경우를 보았다. 단기적으로는, 이 오픈 소스를 사용하는 다른 제품에 비해 경쟁우위가 생겼을 지 몰라도, 장기적으로 보면 손해 보는 일이다. 오픈 소스 버전이 올라갈 때 마다 수동으로 이 버그의 패치를 따로 해줘야 하면서 생기는 관리 비용이 생기기 때문이다. 또, 결국 이런 버그들은 언젠가 패치가 될 텐데 그때 가서 이것을 반영(merge)하려면 별도의 수고가 들고, 이런 것들이 프로젝트의 위험요소(risk)가 될 수 있다.

5.2 사외적으로 갖는 의미

실력과 자신감을 바탕으로, 자사가 만든 소스를 오픈하거나 또는 자사의 경험을 공유하게 되면, 업계와 개발자 커뮤니티에서 주목을 받게 되고, 기술 리딩(leading)회사로서 입지를 다지게 되는 것 같다. 특히 국내의 경우에 이렇게 하는 회사가 많지 않아, 해외의 솔루션을 잘 이용한 경험을 공유 해도 단번에 주목 받는다.

이렇게 회사가 주목 받으면, 그 회사가 내놓는 서비스나 제품도 초기에 주목 받기가 쉽다. 또 이렇게 기술을 리딩하는 회사로 포지셔닝을 하면 훌륭한 인재를 모으기도 쉽다. 적어도 내 주변만 보아도, 여러 조건이 비슷하면 기술적으로 명망이 있는 회사로 지원하는 개발자들이 꽤 있었다.

5.3 도의적으로 갖는 의미

약간은 이상적인 측면에서도 조금 언급해보고 싶다. 간단히 말하면, 공짜로 받은 것이 있으면 공짜로 줄 줄도 알아야 하는 것이 아닌가 싶다. 매일 친구의 숙제를 베끼지 말고, 한번쯤은 나도 친구들에게 숙제의 소스(source)가 되어주자. 매번 친구들에게 신세만 지면 친구들이 하나 둘 없어질 것이 아닌가. 조금 고상하게 표현하자면, 이것이 회사의 사회적 역할인 것 같다.

마치며

이렇게 장황하게 open에 대해서 썼지만, open을 해야만 성공하는 것인 지에 대해서는 확신이 없다. 적어도 open을 하더라도 꼭 실패하는 것은 아니고,  성공을 할 수는 있다는 점은 이제 배운 것 같다.

아직 open에 대해 확신이 서지 않는 이유는, 여전히 오픈 소스 개발 문화와 정반대에 있으면서도 새롭게 성공하는 회사들이 많기 때문이다. 대표적으로 애플과 아마존이 있는데, 애플은 자사의 주요 프로젝트에 대해서는 사내 직원들도 모르게 진행하고 있고, 아마존도 자사의 소스를 오픈하는 경우는 드물다.

하지만, 적어도 내가 보기에 open을 하는 것이 성공 확률을 높일 수는 있는 것처럼 보인다. 무엇보다, 나는 오픈 소스와 오픈 소스 개발 문화가 더 멋지게 보인다. 그리고, 기업이 커지면 관료화 되고 회사가 재미없어지는, 조직 경영의 문제를 푸는 데에도 오픈 소스 개발 문화가 열쇠가 될 수 있지 않을까 생각하고 있다.

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 Test

자세한 결과보기

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]

Ping Test

자세한 결과보기

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]

Ping Test

자세한 결과보기

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를 이용하여 연결했더니, 성능이 꽤 좋아졌다. 다른 것에 비교해서 성능이 떨어지기는 하지만, 개발 생산성을 고려해보면 프로젝트의 요구사항에 따라서 선택해볼 여지가 있지 않나 생각된다.