如何讓伺服器從30臺縮減到2臺的:從Ruby遷移到Go語言

aqee發表於2013-03-26

  我們開發第一版的IronWorker已經是3年前的事了,是用Ruby寫的,API基於Rails開發。我們沒用多久就發展成了相當大的規模,很快我們就觸及到了Ruby程式的承載上限。長話短說,我們切換到了Go語言,請接著讀下去,下面是事情如何一步步發展的。

  最初的設計

  首先,做一點背景介紹:我們開發的第一版IronWorker,起初叫做SimpleWorker(很不錯的名稱,不是嗎?),用的是Ruby。我們過去是一個顧問公司,為其它公司開發應用,在當時有兩個東西被炒得非常火:亞馬遜的Web Services和Ruby on Rails。所以我們開發的應用都基於AWS的Ruby on Rails架構,並因此吸引了不少大客戶。我們開發IronWorker的初衷是來源我們自身的需求。我們有不少做硬體裝置的客戶,他們會7×24小時不停的給我們傳送資料,我需要收集這些資料,把它們整理成有用的資訊。典型的做法就是讓定時任務每天每小時的遍歷這些資料。我們想到應該開發一個東西,能夠處理所有使用者的資料,而不必做一大批的定時任務為每個客戶單獨處理。於是我們開發了一個服務類應用,並在內部使用了一段時間,但後來我們認為一定會有其他的人也需要這個應用,於是我們決定公佈它,這樣,IronWorker誕生了。

  我們的伺服器可承受的CPU使用率大概在50-60%。當超過這個額度,需要增加伺服器來保持它在50%左右。只要我們不介意大量的伺服器租用費(我們當然介意),這種模式會工作的很好。但最大的問題是出現在流量大量陡增時。當一個大型的流量高峰到來時,它會產生多米諾效應,會拖垮我們整個的伺服器叢集。當某些指標超過50%的閥值時,我們的Rails伺服器會吃掉100%的CPU使用率,變成無響應狀態。這會導致負載均衡裝置認為它已經宕了,把它移出分發池,於是這臺無響應的伺服器上的負載就會轉移到池中其他伺服器上。因為池中剩下的伺服器需要承載這失去的伺服器上的負載再加上流量高峰,必然會有第二臺伺服器倒下,負載均衡裝置又會把它移除,前赴後繼。很快池中所有的伺服器都會耗盡。這種現象也叫做colossal clusterf**k (ref: +Blake Mizerany)。

這裡是一個簡單描繪多米諾當機效應的繪圖

  這裡是一個簡單描繪多米諾當機效應的繪圖。

  在這種架構下避免這種事情發生的唯一辦法就是保持有大量的額外處理能力,讓我們的伺服器的負載遠低於它應該能承受的能力,但這意味著要多花一大筆錢。必須讓這種狀態有所改變。

  重寫應用

  我決定重寫這應用。這是一個很容易的決定,很顯然,我們的Ruby on Rails無法支撐我們業務規模的增長。我們都有多年的開發Java的經歷,曾經寫過很多東西只需要很少的資源就能處理大量負載,遠比Ruby on Rails的處理能力強的多,我知道我們可以做出很多改進。於是,接下來的問題變成了應該使用哪種語言?

  選擇一種語言

  我對任何新建議都持開放的態度,最不濟,我還可以重回到Java。Java是一個在很多方面(比如效能上)很棒的語言(是嗎?),但經過了多年的Ruby程式編寫後,我已經為它的開發效率所痴迷。Ruby很有趣,樸素,簡單。

  我們搜尋了一下比Ruby效能上要好的指令碼語言(Ruby並不是很差),比如Python和Javascript/Node,我們還研究了Java的衍生語言,如Scala和Clojure,和還有其它的語言例如Erlang(AWS使用了它)和Go語言(golang)。Go語言獲勝。事實上,它的作為基礎組成部分的併發特徵太強悍了;它的標準核心庫提供了我們開發API服務需要的所有東西;它簡潔;它編譯快;很像Ruby,Go語言很有趣;最後,數字是不會撒謊的。經過了一次原型製作和效能測試後,我們知道了通過它我們可以將負載能力做重大的提高。經過了徵詢團隊的意見(“這很好,它背後有Google支援”),我們打起了攻堅戰。

  起初決定押寶Go語言時,這是一個有風險的決策。Go語言的社群並沒大量的形成,沒有多少開源的Go語言工程專案,在正式產品上使用Go語言的成功案例並不多(有嗎?)。而且我們並不敢肯定在認定Go語言後能否招到這方面的頂級人才,但很快我們發現我們可以招到頂級人才——正是因為我們選擇了Go語言。我們是首個公司公開的宣稱在我們的產品中使用Go,首個公司在Go語言郵件列表裡貼出Go語言工作職位招聘。很多頂級程式設計師希望來我們這裡,就是因為這樣他們可以在每日的程式設計中使用Go語言。

  Go語言的表現

Go語言

  在我們推出了首個Go語言版本後,我們的伺服器數量從30個減少到了2個,並且只留了2個伺服器做冗餘儲備。它們就像是根本沒有被使用,完全就像沒有任何程式在上面執行。我們的CPU使用率低於5%,整個應用的執行啟動只消耗了幾百KB的記憶體(僅在啟動時),相比之下Rails應用要耗用50MB。這種比較甚至是包括了虛擬機器記憶體使用!這真是天與地的差別。從此我們再也沒有經歷過多米諾當機的事故。

  相比起之前,我們的業務增長了許多。我們有了更大的流量,我們增加了兩個新服務(IronMQIronCache),我們有數百個伺服器來支援客戶的需求。這全部是用Go做後臺馬達。回想起來,選擇Go語言是一個明智之舉,它讓我們開發出更好的產品,幫助公司成長,擴大企業規模,並且吸引了一流人才。我相信它會繼續在可預見的未來幫助我們進步。

  英文原文:How We Went from 30 Servers to 2: Go

相關文章