http://www.infoq.com/articles/twitter-java-use;jsessionid=BCBAEA4F386A677C22155A1AC63BAEE1

Twitter Shifting More Code to JVM, Citing Performance and Encapsulation As Primary Drivers

위의 infoQ 글을 약간 요약해서 정리합니다. 일목정연한 느낌의 글은 아니니. 그냥 편하게 보시면 좋을 것 같습니다.

<주 내용>
트위터는 Ruby on Rails와 Mysql로 시작하였습니다. 비용과 성능, 확장성, 아직 성숙하지 못한 library의 한계로 JVM 기반으로 코드를 바꾸고 있습니다.
InfoQ에서는 트위터 엔지니어인 Evan Weaver에게 이런 변화에 대한 배경을 더 알아보기 위해서인터뷰를 하였습니다. 

<트위터 아키텍처 Overview>
트위터는 2010년 봄에 검색 스토리지를 Mysql에서 Lucene의 리얼 타임 버전으로 변경했습니다. 그리고, 최근에는 검색 쪽 Front end를 Ruby on Rails 에서 Blender라고 하는 자바 서버로 바뀌었습니다. 이를 통해서 3배 정도로 성능을 좋게 할 수 있었습니다.
http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html

저희가 Cassandra를 사용하는데, Cassandra는 훨씬 flexible한 데이터인 신상품, 시간정보 데이터, 아주 빠른 속도로 저장해야 하는것들, Hadoop을 이용하여 나오는 결과물에 대해서 처리하는데 아주 유용한 것 같습니다.
한편, Front-End와 Back-End간의 통신은 Facebook에서 사용하는 Thrift를 사용합니다.
 
트위터 내부에서는 Finagle(http://twitter.github.com/finagle/)이라는 Java, Scala로 된 Async RPC 클라/서버를 투자해서 만들기도 했습니다. 

<언어>
트위터 서비스를 처음 할 때, Javascript, Ruby, Scala, Java언어를 사용해서 개발했습니다. Ruby 기반 개발자는 Scala를 선호했으며, C/C++ 기반 개발자들은 Java를 선호했습니다. C를 다 지원하는 언어라서 C언어로 만든 것들을 적용하기도 했습니다.

검색팀에서는 Java 기반의 Lucene을 많이 작업했기 때문에 Scala 언어보다는 Java가 훨씬 편했습니다. 트위터의 서비스가 점점 복잡해지면서 Backend로는  JVM과 Front-end에 back-end 코드가 들어가기 시작했습니다. 
또한 Javascript가 무거워지면서 Ruby 컴포넌트는 점차 사라지기 시작했습니다. 이로 인해서 성능과 encapsulation이 매우 중요한 요소가 되었습니다. 

Ruby runtime은 JVM보다 느렸습니다. 성능 최적화 작업을 하기 위해서 GC 쪽을 힘들게 작업 했어야 했습니다. 그리고, Ruby 의 LAMP 모델과 수직 encapsultation 모델은 트위터와 같은 대용량서비스에는 맞지 않았습다. 새로운 서비스를 만들 때는 좀 더 성능과 encapsulation과 서비스 중심 프로젝트를 빨리 하기 위해서는 Rails 대신 Java 로 가야 했습니다. Front-end쪽의 렌더링은 Rails의 템플릿 모델 대신 브라우져 기반의 javascript로 사용했습니다. 
결국 성능과 개발 생산성을 위해서는 Backend/Frontend에서 Ruby/Rails를 빼고 java 기반으로 가게 되었습니다.

<검색쪽 이야기>
검색쪽을 Ruby에서 java로 바꾸니 2가지가 좋아졌습니다. 첫번째는 Lucene에서 만든 real time reverse index가 Mysql을 대체할 수 있었습니다. 저희는 이 Lucene을 Earlybird라 불렀는데, Earlybird는 메모리 효율을 2배로 높일 수 있었고, 검색 필터링에 대한 연관 확장성을 높였습니다. 마지막으로는 검색 서비스에 대한 요구들을 빨리 처리할 수 있었습니다. 실제 성능결과는 mysql 은 20TPS/200QPS에서 Earlybird는 1000TPS/12000QPS로 높였습니다. 
Blender 는 Thrift 이고, Netty 기반의 HTTP 서비스입니다. Netty는 Fully Async를 지원하며.. 하여튼 완전 좋습니다. Blender를 적용하면서 800ms였던 latency를 250m로 줄였으며 cpu도 반으로 줄어들었습니다.

JVM 기반 언어의 장점이 성능과 확장성이라면, 트위터는 적어도 backend 서비스에서만큼은 static typing 이라는 장점이 있겠다고 말씀드릴 수 있습니다. (static typing은 프로그래밍 언어개념이며, 컴파일시 문제점을 발견 가능하고, 실행이 빠르며 가독성이 좋아지는 특징이 있습니다. Ruby 언어가 Dynamic한 언어의 특성을 가지다 보니 개런티에 대한 모호함이 있을 수 있었던 단점을 java에서 최대한 명확하게 해주는 편의성을 주요하게 봤던 것으로 생각됩니다. 그래서 Scala 언어가 static 하기 때문에 이런 부분에 대해서 얘기가 나왔습니다.)

한편, 여전히 Ruby가 어떤 서비스에서는 최고의 선택이 됩니다. 트위터는 여전히 GC로직을 수정한 Ruby MRI(CRuby) 1.8 을 사용하고 있으며, Ruby 1.9 에 기어하려고 하고 있습니다. 
JVM 언어인 JRuby로 옮길라고 하는데, 성능이슈가 있습니다. CRuby의 memcached의 경우는 엄청 빠른데, JRuby 클라언트로는 성능이 안나옵니다. JRuby 자체를 2배로 빠르게 한다 하더라도 느린 memcached client가 성능의 이점을 다 날릴 수 있을 것입니다. JRuby 잘못은 안라고 생각은 듭니다. 아직 immature한 환경이라고 생각이 듭니다. CRuby 도 마찬가지이지요. 여전히 우리는 얻을 수 있 이익이 많기 때문에 계속 JRuby에 투자를 할 것입니다. 
 
한편, 이익이 있다면, JRuby Twitter는 Thrift 기반으로 재작성하여 평가할 수 있을 것입니다. 

(블로그 주인이 추가합니다.)
LAPM는  (Linux-Apache-mysql-PHP/Perl/Python)의 약자이고,
APM은 (Apache-mysql-PHP/Perl/Python)의 약자입니다. 

 Java7에서 invokeDynamic이 추가되었습니다. JRuby 성능은 추후 달라질 것으로 예상됩니다.
Posted by 김용환 '김용환'