這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
故事的起因在這裡。
之前發了一篇文章,講了暴漫用golang重構了worker系統,有好多朋友問到語言選擇的問題。
其實在用Golang重寫我們的worker系統之前是做過很多調研的。
真正讓我們下定決心的是 Parse的一篇文章:How We Moved Our API From Ruby to Go and Saved Our Sanity。 文中講了Facebook的Parse團隊為什麼選擇Golang代替Ruby。
我翻譯下關鍵幾點:
Parse面臨的問題
Parse跟暴漫的技術棧比較相似: 伺服器Unicorn,部署使用Capistrano。在高流量面前很多問題都被指數級放大,在每次部署的時候 app server重啟都要很長時間。並且Unicorn的重啟並不是真正的‘graceful’(這個我們也有同感,重啟之後服務會中斷10秒左右,另外Parse在用Golang重構之後還寫了一個庫‘Grace’ 專門解決重啟中斷服務的問題)。 這樣造成的服務中斷帶來的影響非常不好。
另外像Unicorn這樣 每個進程同時只能處理一個請求(one process per request),不僅僅是極度的浪費,而且如果某一個action突然變慢 將會佔滿整個 worker poll。 導致整個服務都不可用。
方案選擇
Parse在EventMachine,JRuby,c++, c#, golang 之前做了對比,並最終選擇了go。
EventMachine
Parse使用了EventMachine實現他們的push服務,在使用過程中,由於相關的gem成熟度等級不夠,總是碰到一些奇怪的bug。還是生態的問題,導致實現某些功能的時候無輪子可用。
JRuby
Parse現在是Ruby實現,所以JRuby就是正確的選擇? JRuby基於rvm可以並發處理大量請求,看起來非常不錯。 不是的!JRuby缺乏各種非同步庫的支援。Parse擔心為了應對業務的增長,還要第二次重構:從JRuby到JAVA。 並且Parse的工程師團隊是在不想在JVM中部署並調節各種參數。
文中還提到了 Twitter團隊在遷移到Scala之前對JRuby的調查:Twitter對MRuby做了很多工作,包括自己寫了一個GC工具。本來在MRuby上工作很好,效率很高的庫,到了JRuby上 就不好使了(說白了就是各種庫不成熟,生態系統太重要!)遷移過去之後雖然JRuby本身快了2倍,但是其他東西都面臨各種問題,有點得不償失
That's not a fault of JRuby; it's just that at the moment the surrounding ecosystem is still kind of immature. CRuby's was too; we put a lot of investment into it, which we can now take advantage of, and we would have to do the same for JRuby.
暴漫團隊說實話沒人用過JRuby,而且經過這麼長時間的發展,生態應該會好很多,但是儘管這樣,遷移之後 仍然有很多工作要做吧?
C++
Parse團隊有很多c++的開發經驗, 不過c++代碼難以debug和維護。 就我個人而言 嚴重覺得c++肯定不是web項目的選擇。 另外缺乏 web相關各種庫支援。
C
c#有非常好的並行存取模型支援。不過在Linux上。。。還是看下一條吧
Golang
Golang語言效率高,語言層面支援並發,文法非常簡單 易於上手,並行存取模型容易理解。(我們重構之前只給團隊講了一個小時的文法,然後給了一些些好的worker作為參考,然後大家都可以順利的重構2-3個worker,在兩周的時間內)。 應該是worker系統的最佳選擇。
最後回到暴走漫畫的問題
大家的疑問更多是 既然都是io消耗,為什麼golang會快這麼多。我試著解釋下(水平有限): golang靜態語言 不需要類型推斷 拋棄了各種文法糖,在語言效率層面上快上不少,另外在資料庫io方面 gorm 沒有 ActiveRecord的黑魔法,自然會快很多。
暴漫的worker系統瓶頸在高並發峰值,一旦抗不過去後面就會持續累積。 而golang在單個任務上雖然只有5倍快,但是良好的並發機制,使job的執行速度飛快。 而在原系統中 每台機器150並發跑慢之後,有些100ms的任務都等到23s之久。
單個任務執行速度快5倍, 並發再快5倍,所以從10台減到1台 而 golang機器還遊刃有餘是合理的。
Parse在重構的時候考慮的是能容納當前業務峰值的10倍的方案。我覺得我們在挑選方案的時候 也要有這種意識。雖然有些方案確實也可以解決目前的困境,但是對以後的架構調整是否有益,或者說相容