Go 部落格

使用 Go 構建 StatHat

Patrick Crosby
2011 年 12 月 19 日

引言

我叫 Patrick Crosby,是 Numerotron 公司的創始人。我們最近釋出了 StatHat。本文介紹了我們為何選擇使用 Go 開發 StatHat,並詳細闡述了我們如何使用 Go。

StatHat 是一款用於跟蹤程式碼中的統計資料和事件的工具。從 HTML 設計師到後端工程師,任何人都可以輕鬆使用 StatHat,因為它支援從 HTML、JavaScript、Go 和其他十二種語言傳送統計資料。

您將資料傳送到 StatHat;它會生成精美、完全可嵌入的資料圖表。StatHat 會在指定的觸發器發生時提醒您,每天傳送電子郵件報告,等等。因此,您無需花費時間為應用程式編寫跟蹤或報告工具,可以專注於程式碼。當您進行真正的工作時,StatHat 會保持高度警惕,就像巢穴中的老鷹,或者吃了興奮劑的保姆一樣。

這是 StatHat 生成的紐約、芝加哥和舊金山氣溫圖表示例

架構概覽

StatHat 由兩個主要服務組成:接收統計/事件 API 呼叫和用於檢視和分析統計資料的 Web 應用程式。我們希望將它們儘可能分開,以便將資料收集與資料互動隔離。我們這樣做有很多原因,但一個主要原因是,我們預計需要處理大量自動化的傳入 API HTTP 請求,因此 API 服務將採用與處理人類互動的 Web 應用程式不同的最佳化策略。

Web 應用程式服務是多層級的。Web 伺服器處理所有請求並將它們傳送到互動層。對於簡單任務,互動層會處理生成任何必要的資料。對於複雜任務,互動層依賴多個應用伺服器來處理生成圖表或分析資料集等任務。互動層完成後,Web 伺服器會將結果傳送給表示層。表示層使用 HTML 或 JSON 響應 HTTP 請求。隨著服務需求隨時間增長和變化,我們可以水平擴充套件 Web、API、應用伺服器和資料庫。沒有單點故障,因為每個應用伺服器都有多個副本執行。互動層使我們能夠擁有不同的系統介面:http、命令列、自動化測試、移動 API。StatHat 使用 MySQL 進行資料儲存。

選擇 Go

在設計 StatHat 時,我們對開發工具有一個清單,其中包括以下幾點:

  • 後端和前端系統使用同一種程式語言

  • 優秀、快速的 HTML 模板系統

  • 快速啟動、重新編譯和測試,便於大量除錯

  • 一臺機器支援大量連線

  • 用於處理應用級併發的語言工具

  • 出色的效能

  • 強大的 RPC 層用於層間通訊

  • 豐富的庫

  • 開源

我們評估了許多流行和不太流行的 Web 技術,最終選擇了使用 Go 進行開發。

Go 於 2009 年 11 月釋出後,我立即安裝了它,並且非常喜歡它快速的編譯時間、goroutines、channels、垃圾回收以及所有可用的包。我尤其高興的是,我的應用程式程式碼行數非常少。我很快就嘗試製作了一個名為 Langalot 的 Web 應用程式,它可以在您輸入查詢時併發搜尋五個外語詞典。它速度快得驚人。我把它放到了網上,從 2010 年 2 月開始一直執行至今。

以下部分詳細介紹了 Go 如何滿足 StatHat 的需求以及我們使用 Go 解決問題的經驗。

執行時

我們使用標準的 Go http 包 作為我們的 API 和 Web 應用程式伺服器。所有請求首先透過 Nginx,任何非檔案請求都被代理到 Go 驅動的 http 伺服器。後端伺服器全部用 Go 編寫,並使用 rpc 包 與前端通訊。

模板

我們使用標準的 template 包 構建了一個模板系統。我們的系統增加了佈局、一些常用格式化函式以及在開發過程中動態重新編譯模板的能力。我們對 Go 模板的效能和功能非常滿意。

除錯/修改

在之前的工作中,我曾參與開發一款名為《黑暗王座》的影片遊戲,它使用 C++ 編寫。我們有一些標頭檔案,一旦修改,就需要對整個系統進行完全重建,耗時 20-30 分鐘。如果有人改動了 Character.h,他就會招致其他所有程式設計師的憤怒。除了這種痛苦之外,這也顯著減慢了開發時間。

從那時起,我一直努力選擇能夠快速、頻繁修改的技術。使用 Go,編譯時間根本不是問題。我們可以在幾秒鐘內,而不是幾分鐘內重新編譯整個系統。開發 Web 伺服器瞬間啟動,測試在幾秒鐘內完成。正如前面提到的,模板在更改時會重新編譯。結果是 StatHat 系統非常易於使用,並且編譯器不是瓶頸。

RPC

由於 StatHat 是一個多層系統,我們想要一個 RPC 層,以便所有通訊都標準化。使用 Go,我們使用 rpc 包gob 包 來編碼 Go 物件。在 Go 中,RPC 伺服器只需接受任何 Go 物件並註冊其匯出的方法。不需要中間介面描述語言。我們發現它非常易於使用,並且我們許多核心應用伺服器的程式碼都不到 300 行。

我們不想花時間重寫 SSL、資料庫驅動程式、JSON/XML 解析器等庫。雖然 Go 是一門年輕的語言,但它擁有大量的系統包和越來越多的使用者貢獻包。除了少數例外,我們已經找到了我們需要的一切 Go 包。

開源

根據我們的經驗,使用開源工具的價值是巨大的。如果出現問題,能夠檢視每一層的原始碼,而不是遇到任何黑箱,將非常有幫助。擁有語言、Web 伺服器、包和工具的程式碼,使我們能夠理解系統每個部分的工作原理。Go 中的一切都是開源的。在 Go 程式碼庫中,我們經常閱讀測試,因為它們通常提供了使用包和語言功能的絕佳示例。

效能

人們依賴 StatHat 來獲取資料的即時分析,我們需要系統儘可能地響應迅速。在我們的測試中,Go 的效能遠遠超過了大多數競爭對手。我們將其與 Rails、Sinatra、OpenResty 和 Node 進行了測試。StatHat 一直透過跟蹤請求、特定任務持續時間、記憶體使用量等各種效能指標來監控自身。因此,我們能夠輕鬆評估不同的技術。我們還利用了 Go testing 包中的基準效能測試功能。

應用級併發

在之前的工作中,我曾擔任 OkCupid 的 CTO。我在那裡使用 OKWS 的經驗教會了我非同步程式設計的重要性,尤其是在處理動態 Web 應用程式時。您完全沒有理由同步執行這樣的操作:從資料庫載入使用者,然後查詢他們的統計資料,然後查詢他們的提醒。這些都應該併發執行,然而令人驚訝的是,許多流行的框架都沒有非同步支援。Go 在語言層面支援這一點,不會產生回撥地獄。StatHat 廣泛使用 goroutines 來併發執行多個函式,並使用 channels 在 goroutines 之間共享資料。

託管與部署

StatHat 執行在亞馬遜的 EC2 伺服器上。我們的伺服器分為以下幾種型別:

  • API

  • Web

  • 應用伺服器

  • 資料庫

每種型別的伺服器至少有兩臺,並且位於不同的區域以實現高可用性。向叢集中新增新伺服器只需幾分鐘。

為了部署,我們首先將整個系統構建到一個帶時間戳的目錄中。我們的打包指令碼構建 Go 應用程式,壓縮 CSS 和 JS 檔案,並複製所有指令碼和配置檔案。然後將此目錄分發到所有伺服器,以便它們都有相同的分發內容。每個伺服器上的指令碼查詢其 EC2 標籤,確定它負責執行哪些服務,並啟動/停止/重新啟動任何服務。我們經常只部署到部分伺服器。

更多

有關 StatHat 的更多資訊,請訪問 stathat.com。我們正在釋出一些我們編寫的 Go 程式碼。訪問 www.stathat.com/src 獲取所有開源的 StatHat 專案。

要了解更多關於 Go 的資訊,請訪問 golang.org

下一篇文章: 瞭解 Go 社群
上一篇文章: 從零到 Go:24 小時內在 Google 主頁上線
部落格索引