《程序員》2009 05期
Twitter將部分應用從Ruby遷移到了Scala。三位開發者詳談決策背后的因素、Scala在現實應用中遇到的困難以及Scala對編程風格的影響。
=■文,Bill Venners
Twitter是一個快速成長的微博客服務網站。它作為一個Ruby on Rails應用呱呱落地,現在依然用Ruby on Rails支撐著大部分面向用戶的網頁。但大約一年以前,他們開始將部分Ruby服務替換成用Scala編寫、在JVM上運行的程序;來自Twitter的三位開發者——系統工程師Steve Jenson、API主管Alex Payne.服務團隊成員Robey Pointer-與Bill Venners坐到一起討論Scala在Twitter的實際應用。他們詳述了運營中遇到的實際問題如何使他們開始考慮Scala.Scala在實踐中又產生哪些問題,還會探討Scala怎樣影響了他們的編程風格。
Twitter簡短回顧
Bill Venner:在Twitter的技術演變歷程里,是什么因素令你開始考慮Scala?
Alex Payne:Twitter最初只是從事播客業務的ODEO公司里面私下鼓搗的項目。當ODEO遇到經營困難,他們開始允許工程師折騰各種想法。其中一位工程師Jack Dorsey對狀態尤為感興趣。他總是在IM上看到有人說“我在遛狗”,“我在做這個”,“我在干那個”,于是開始思考有什么辦法能讓人們更方便地交流各自的狀態。他和另外幾位工程師搭建的原型后來成了Twitter。原型沿用了ODEO 慣用的Ruby on Rails。直到今天Twitter都主要是一個Rails
應用加若干Ruby守護進程在后臺完成異步處理。
后來我們發現雖然Rails做前臺Web開發非常出色,但對重量級的后臺處理來說.Rails在運行時有一些性能上的局限。我個人認為Ruby語言缺少一些有助于產生可靠的高性能代碼的因素.而當我們的業務越做越大,這樣的因素對我們來說非常重要。我們希望寫出來的代碼是正確的、可維護的。我們還希望維持低成本——和大多數企業對軟件平臺的期望沒什么兩樣。所以我們開始盯上Scala。
我們看中Scala還有一個原因。雖然我們用Ruby遇到了問題,但依舊熱愛Ruby語言的靈活性、喜歡它功能全面、也忘不了用Ruby編程的愉悅。很多Java開發者離開大公司之后都轉而用Ruby編程,原因和我們一樣,希望每天都過得愉快。我們不希望丟掉這些,投向萊種無趣的、一本正經的語言社群,比如C++。我們知道人們用C++寫出非常高性能的代碼,在座的Steve和Robey都有那方面的經驗。可是我們希望能用一種真正令我們傾心的語言,而Scala令我們感覺值得賭一把。可靠的高性能代碼
Bill Venners:我很好奇.Ruby粉絲也會希望你說清楚——能否詳細解釋對于編寫可靠的高性能代碼來說,你感覺Ruby缺少了什么?
Steve Jenson:在我的職業生涯中,一直覺得長生命期的進程是不能缺少的東西。而Ruby.像很多腳本語言一樣,作為長生命期進程的環境會遇到麻煩。相反JVM非常適合,因為過去十年JVM都-直在為這個方面優化。所以Scala具備了編寫長生命期服務的基礎,而這也是目前它在Twitter的主要用途。Scala還有一樣特質令我們愛不釋手,就是靜態類型,而且是無痛的靜態類型。有時候在Ruby里面會很希望能寫一些可選的類型標注,特別指
明在某個地方我們希望出現什么類型。Scala就能指定這樣的類型信息.我們感覺特別有用。
Robey Polnter:另外Ruby還沒有很好的線程支持。現在情況改善了,不過當初我們編寫這些服務的時候,綠色線程是唯一的選擇。綠色線程不用真正的操作系統內核線程,它們定期停下手上的工作,檢查一下有沒有別的“線程”要執行,用這樣的辦法去模擬。所以Ruby是在單核或者單處理器的范圍內模擬線程。我們用多核服務器,而且服務器上的內存是有限的。在欠缺很好的線程支持的時候,就只能依靠多進程了。但因為Ruby的垃圾收集不像
Java那么完善,每個進程都要用掉很多內存。沒有足夠大的內存我們就沒辦法在單臺機器上跑很多Ruby守護進程。當我們用JVM的時候,可以在堆里跑很多線程,還可以讓
單個JVM進程占據機器上的全部內存。
Alex Payne:我要特別強調Steve剛才提到的“類型”。隨著我們的系統越來越大.我們的Ruby代碼里面有很多邏輯可以說是在模仿一個類型系統,單元測試或者模型驗證的時候都容易出現那樣的邏輯。我想這種情況可能是動態語言編寫的大型系統與生俱來的——你最終不得不自己重寫一個類型系統,而且很可能寫不好。到處都要檢查null值,到處都調用Ruby的kind_of?方法。“kind of?”相當于問“這個是User對象嗎?不好意思,我們一定要那種的,不然程序會爆掉。”寫這樣的東西實在是太丟人了,在編程語言的世界里,分明幾十年前就已經有了解決方案。用Scala補足Ruby
Steve Jenson:我們發現Ruby和Scala非常互補。我們把Ruby.具體說是Rails.用在它特別擅長的地方。前端的東西Rails做得很好。
Bill Venners:你們把Scala用在什么地方?
Robey PoInter:我們有一個基于Ruby的隊列系統負責Rails前端和守護進程之間的通信,現在換成了用Scala重寫的隊列。在情況穩定的時候,原來的Ruby隊列其實表現得還不錯,只不過啟動時間和崩潰行為不符合我們的期望。它慢了一點,內存消耗多了一點。有時候遇到流量高峰就撐不住了,而當它崩潰之后,要很長時間才能恢復。這可不行,我們需要能對付極端情況和高負載的方案,即使不像對付一般負載那么輕松,至少要相對容易。
Bill Venners:守護進程做些什么?
Robey Polnter:我們的架構有一個重要的出發點.就是讓Rails做它所擅長的事.AJAX、Web前端、網站——總之就是用戶看得見的東西。任何能脫離請求,響應循環的工作,我們都會把它卸下來,放進消息系統里面排隊.讓后端的守護進程去處理。
Steve Jenson:例如當你修改社會關系圖的時候,也就是你在Twitter上“跟”或者“不跟”某個人的時候,這些工作以及相應的緩存更新都由守護進程異步完成。
Bill Venners:你們考慮過JRuby嗎?
Alex Payne:考慮過。只不過當時試驗的時候,沒辦法在JRuby上啟動我們的Rails應用。我們用了大量要求C擴展的Ruby Gems.而當中很多都還沒移植成JVM友好的版本。當時JRuby的性能還遠不能與MRI( Ruby的C實現)相提并論,更沒法與Scala這樣的語言相比了。我們不排除將來會再次嘗試JRuby.但目前只是希望給Ruby打些補丁能有幫助。Scala的權衡取舍
Bill Venners:你們已經有了Scala的實戰經驗,用它去解決實際的問題。你們認為它有什幺代價,有什么問題?好處在哪里,壞處在哪里?
Stwe Jenson:我認為Scala的效果很好。我們當中很多人都有過使用研究型語言編程的經驗,而一般來說,當把研究型語言投入實際生產會遇到很多問題。可是我們用Scala的時候沒有遇到太多這類困難.我知道在Actor和高可伸縮性方面遇到一點麻煩,不過已經解決了。總體來說,從我們的經驗看.Scala是一個非常高性能、非常穩定的系統。
Robelt Pohar:我也同意到現在為止遇到的問題非常少。其中一些是由于語言和編譯器都還很新。我們偶爾遇到一些令人困惑的編譯錯誤,要花一些時間才能找出真正的錯誤。Scala有—部分核心集合庫還不及格,當然現在他們正在改進;
Bill Venners:哪方面“不及格”?用不了?不夠快?
Robey Polnter:我沒有遇到用不了的情況,但有那么幾個方法寫得效率不高.API也存在一些缺口。有的時候我們干脆決定丟開它,直接在Scala里面用Java的集合庫。這倒是Scala的一項優點,它有Java做后備。
Alex Payne;我首先做的一件事是給我們的API準備Scala測試平臺。主要是包裝Apache Commons HTTP庫,還要提供代表系統中所有RESTNI資源的一組對象。最困難的地方是把Ruby思維換成Scala思維。要從更加函數式的角度去思考,還要更加從不變性的角度去思考,更何況我好幾年沒用過靜態類型的思考方式了。所以對于Java背景不那么強,更偏向動態語言背景的人來說,過渡期可能長一點,不過只要過了那個階段,結果是值得的。現在
我的默認思維已經用Scala取代了以前的Ruby。
Bill Venners:學習Scala如何改變你時編程的想法?
Robey Polnter:學習Scala之前,我沒有比Python更強的函數式語言背景。我很熟悉Python。越深入學習Scala.我就越從函數式的角度去思考。一開始的時候,我會像寫Python 一樣用for表達式,現在我發現自己經常會用map或者直接在迭代子上調用foreach。
Alex Payne:我感覺從Actor的角度去思考并發絕對是一次思維轉變。我有過一點用IO語言編程的經歷,不過我感覺Scala的Actor更接近Erlang的模型,與IO差別更大一些,我非常喜歡Scala的實現。這是好的轉變。
Stew Jenson:我來自Java背景,不過我也熟悉Common LISP和ML。能用自己熟悉的運行時,又能用函數式的組合子、閉包和高階函數,這是美妙的事情。它們在Scala里面的表現我很滿意。Scala的顧慮
Bill Venners:如果我打算在生產系統中使用Scala.有什么需要擔心的呢?哪些事情是我·玉緬先準備好的?有什么要害怕的嗎?
Alex Payne:目前Scala的IDE支持情況,應該說已經過了嬰兒期,但還處在別扭的青春期。IntelliJ 8.1的Scala支持感覺相當不錯。Scala自帶的Emacs模式,縮進有些怪毛病。Textmate的支持很差勁,不過Scala工具郵件列表上已經在討論怎么改進,IDE支持算是個門檻。
Robey Polnter:如果你不是從Java世界過來的,而是來自Ruby或者Python的世界,有可能受不了編譯一部署的流程。你要配置構建環境,還要用很長的腳本去部署jar文件,與Ruby或者Python相比,這個世界差別很大。
Alex Payne:JavaRebel對此有些幫助,把它配置好之后就比較接近以前的流程——寫代碼、保存、運行測試;情況有所改善,但還是免不了Java世界的拖泥帶水,每個項目都要先寫一堆配置。不過會得到一套好的慣例.增加新的庫很方便,還有很多部署相關的東西都已經內建在里面了。終究是個權衡問題。
Steve Jenson:要保證把可變性(mutability)用對了地方。先從不可變開始,當發現適合的時候再運用可變性。這就是我們得到的教訓。應當注重不可變,理由是當用到線程的時候,如果對象是不可變的,就無須擔心發生意外的變化。這個原則對我們來說是一大收獲,現在如果不是特別需要提高性能的地方,都盡可能不要可變性。
Robey PoInter:JIT編譯器還能對不可變對象做一些很重要的優化.大大提高性能。
Alex Payne:我們還遇到一種情況,肯定屬于很特殊的情況,大家不要因此被嚇倒了,我們的Hosebird服務是一個獨立的專用系統,它將全部的公開Tweet消息流通過互聯網近乎實時地發送給各家合作伙伴。最初系統里有很多Actor:-個負責從內部的消息隊列上抓消息,還有很多個Actor各自代表不同的客戶。隨著我們做的系統測試越來越多,我們發現Actor不一定是適合系統所有部分的最佳并發模型。現在系統里一部分保留了基于Actor的并發模型,其余部分干脆回到了傳統的Java線程模型。
負責的工程師John Kalucki認為這樣更容易測試,更好預測。最妙的是只要幾分鐘就能把基于Actor的代碼換成基于Java線程的代碼,幾次查找替換而已。所以萬一發現Actor不適用了,也不是什么大不了的事情。
Robey Pointer:我在隊列系統Kestrel也遇到同樣的情況。一開頭是每個隊列一個Actor.但發現任務的粒度太細了,在那么細微的層次上用Java的鎖實際效果更好。
Bill Venners:在現實世界中便用Scala還有什么地方要注意的嗎?
Alex Payne:如果一個程序員從來沒有用過支持模式匹配的語言,那要準備好改變自己對編程的認知。我和一群用Objective-C的Mac程序員談過,試圖說服他們,一旦你開始用模式匹配,就再也不想回到其他語言了。模式匹配是程序員每天都在傲的事情。給我一個集合,我讓從大海里面找出特定的那一根針來,根據類去找也好,根據內容去找也好,模式匹配就是那么強大的一個工具。
Robey Pofnter:我還想說說我們是怎么開始用Scala的。絕不是哪天晚上喝多了兩杯拍腦袋做的決定.而是掙扎了很長時間,也許算不上掙扎吧,但至少討論了很長時間。當你用過像Ruby這么高級的語言編程,再回到中級的語言,比如Java.會感覺不耐煩,因為要多寫很多代碼才能達到同樣的效果。Scala在這方面很吸引,因為可以繼續寫高層次的代碼,只不過是在JVM上運行。付諸行動
Bill Venners:不久前JavaPosse的人說過他們是怎么嘗試新事物的。他們建議應該在你關心的事情上嘗試,但是不要在關鍵的業務上嘗試。因為是你關心的事情,所以會一直保持進展:但要是在關鍵業務上嘗試,一旦失敗生意就完了。
Steve Jenson。Twitter也是這么做的。我們首先做小規模的試驗,用Scala實現“Public Timeline”服務。效果很好,我們也學到很多,知道了我們想要什么不想要什么。那個服務還在正常運行,已經運行了差不多一年。
Alex Payne:是的,唯一一次遇到問題是因為底層的數據庫出現復制延遲。除此之外它都運行得很順暢。因為太成功了,所以我們打算逐漸把更多架構遷移到Scala。我們的流量中API請求占大頭,我們希望把其中大部分都交給Scala去處理,不管是Edge緩存層還是Web應用層。希望到2009年底的時候大多數用戶與Twitter的交互背后都有Scala在辛勤勞動。■參考資料
Programming Scala,Alex Payne與Dean Wampler-9-aF:
http://oreilly.com/catalog/9780596157746/
Programming in Scala. Martin Odersky( Scala設計者)、
Lex Spoon與Bill Venners :
http://www.artima.com/sViop/programming_in_scala
視頻The Feel of Scala:
http://tinyurl.com/dcfm4c
Bill Venners.Artima Inc.總裁及網站的出版人。著有Inside the Java Virtual Machine-書。領導了Jini社區的ServiceUI項目,還主導面向Scala和Java開發者的開源測試工具ScalaTest項目的開發及設計。
2009 05 83