Go 部落格
奇虎360與Go
這篇客座部落格文章由奇虎360的軟體工程師楊舟撰寫。
奇虎360是中國領先的網際網路和移動安全產品及服務提供商,並運營著一個主要的Android移動分發平臺。截至2014年6月底,奇虎擁有約5億月活躍PC網際網路使用者和超過6.4億移動使用者。奇虎還運營著中國最受歡迎的網際網路瀏覽器和PC搜尋引擎之一。
我的團隊——推送服務團隊,為公司(PC和移動端)的50多個產品提供基礎的訊息服務,包括我們開放平臺上的數千款應用。
我們與Go的“戀情”始於2012年,當時我們首次嘗試為奇虎的一個產品提供推送服務。最初的版本是使用nginx + lua + redis構建的,但由於負載過高,未能滿足我們對即時效能的要求。在這種情況下,新發布的Go 1.0.3引起了我們的注意。多虧了它提供的goroutine和channel功能,我們在幾周內就完成了原型開發。
最初,我們的Go系統執行在20臺伺服器上,總共支援2000萬即時連線。該系統每天傳送200萬條訊息。現在,該系統執行在400臺伺服器上,支援超過2億即時連線。目前每天傳送超過100億條訊息。
隨著業務的快速擴充套件和對我們推送服務的應用需求不斷增加,最初的Go系統很快達到了瓶頸:堆大小高達69G,最大垃圾回收(GC)暫停時間達到3-6秒。更糟糕的是,我們每週都必須重啟系統以釋放記憶體。如果說我們沒有考慮放棄Go,轉而用C重寫整個核心元件,那就不誠實了。然而,事情並沒有完全按計劃進行,我們在遷移業務邏輯層的程式碼時遇到了麻煩。因此,當時唯一的人員(我)不可能在保證邏輯遷移到C服務框架的同時,還要維護Go系統。
因此,我做出了堅持使用Go系統的決定(這可能是必須做出的最明智的決定),並且很快取得了重大進展。
以下是我們做的一些調整和關鍵收穫:
- 用持久連線(使用連線池)替換短連線,以減少通訊過程中緩衝區的建立和物件的生成。
- 恰當使用物件和記憶體池,以減輕GC的負擔。

-
使用任務池,一種由一組長期存在的goroutine消費全域性任務或訊息佇列(由連線goroutine傳送)的機制,以替換短暫存在的goroutine。
-
監控和控制程式中的goroutine數量。由於不加限制地接受外部請求可能導致goroutine激增,而傳送給內部伺服器的RPC呼叫可能會阻塞新建立的goroutine,因此缺乏控制可能會給GC帶來無法承受的負擔。
-
在行動網路下,請記住為連線新增讀寫截止時間;否則,可能會導致goroutine阻塞。在區域網下,請謹慎並正確地應用它,否則會損害RPC通訊效率。
-
使用管道(TCP的全雙工特性)來提高RPC框架的通訊效率。
結果是,儘管人力資源有限,我們還是成功地對架構進行了三次迭代,並對RPC框架進行了兩次迭代。這一切都歸功於Go的開發便利性。下面是當前的系統架構。

持續改進的過程可以用下表來說明。

此外,在這些最佳化之後,不再需要臨時釋放記憶體或重啟系統。
更令人興奮的是,我們開發了一個線上的即時視覺化平臺,用於分析Go程式的效能。現在我們可以輕鬆訪問和診斷系統狀態,鎖定任何潛在的風險。以下是該系統執行時的截圖。


該平臺最大的優點是,我們可以透過應用分散式壓力測試工具(也用Go構建)來模擬數百萬線上使用者的連線和行為,並觀察所有即時視覺化資料。這使我們能夠評估任何最佳化的有效性,並透過識別系統瓶頸來規避問題。
到目前為止,我們已經實踐了幾乎所有可能的系統最佳化。我們期待GC團隊能帶來更多好訊息,以便我們能從繁重的工作中進一步解脫出來。我猜想,隨著Go的不斷發展,我們的經驗有一天也會過時。
因此,我希望透過感謝有機會參加Gopher China來結束我的分享。這是一個讓我們學習、分享的盛會,也為展示Go在中國日益增長的普及度和繁榮景象提供了一個視窗。奇虎內部的許多其他團隊已經瞭解或嘗試使用Go。
我相信,將有更多中國網際網路公司加入我們,用Go重塑他們的系統,並且Go團隊的努力將在可預見的未來惠及更多的開發者和企業。
下一篇文章:Go、開源、社群
上一篇文章:GopherChina之行報告
部落格索引