Go 部落格
使用 Go 建立 StatHat
簡介
我叫 Patrick Crosby,並創立了一家名為 Numerotron 的公司。我們最近發布了 StatHat。這篇文章說明我們選擇使用 Go 開發 StatHat 的原因,其中包含我們使用 Go 的詳細資訊。
StatHat 是一款工具,可用於追蹤程式碼中的統計資料和事件。每個人,從 HTML 設計師到後端工程師,都可以輕鬆使用 StatHat,它支援 從 HTML、JavaScript、Go 和其他十二種程式語言發送統計資料。
將數字傳送至 StatHat,由此產生美觀又全嵌入式資料圖表。當特定觸發器發生時,StatHat 會提醒您,並會傳送每日電子郵件報告,還有更多功能。如此一來,不必再花時間為應用程式撰寫追蹤或回報工具,您可以專注在程式碼上。當您專注於真正的區塊時,StatHat 會像山巔雄鷹或服用甲基安非他命保姆一般,維持高度警覺。
以下是紐約市、芝加哥、舊金山的溫度 StatHat 圖表範例

架構概觀
StatHat 包括兩種主要服務:輸入統計量/事件 API 呼叫與檢視和分析統計資料的網路應用程式。我們希望盡量將兩者分開,以將資料收集與資料互動隔離。我們出於許多理由這麼做,但其中一個主要理由是,我們預期會處理大量的自動輸入 API HTTP 要求,因此必須針對 API 服務採用與與人類互動的網路應用程式不同的最佳化策略。

網路應用程式服務是多層的。網路伺服器會處理所有要求並將其傳送至互動層。對於簡單的任務,互動層會處理產生所有必要的資料。對於複雜的任務,互動層仰賴於多個應用程式伺服器來處理:例如產生圖表或分析資料集。互動層完成後,網路伺服器會將結果傳送至簡報。簡報會以 HTML 或 JSON 回應 HTTP 要求。隨著服務的需求增加並隨著時間而改變,我們可以橫向擴展網路、API、應用程式伺服器和資料庫。由於每個應用程式伺服器都有多個執行中的複本,因此沒有單一故障點。互動層允許我們擁有不同的系統介面:http、命令列、自動化測試、行動裝置 API。StatHat 使用 MySQL 進行資料儲存。
選擇 Go
在我們設計 StatHat 時,針對開發工具制定以下檢查清單
-
後端和前端系統採用相同的程式語言
-
良好且快速的 HTML 樣本製作系統
-
快速啟動、重新編譯、應付大量修改的測試
-
同一台機器上的大量連線
-
處理應用程式層級並行處理的語言工具
-
良好的效能
-
在層級之間傳遞的可靠 RPC 層
-
大量函式庫
-
開放原始碼
我們評估許多著名的和不著名的網路技術,最後選擇使用 Go 來進行開發。
當 Go在 2009 年 11 月發布時,我立即安裝了它,並喜歡它快速的編譯時間、 goroutine、通道、垃圾回收以及所有可用的封裝。我對我的應用程式使用很少的程式碼列感到特別高興。我很快便嘗試建立一個名為Langalot的網頁應用程式,讓你輸入查詢時同時搜尋五種外語詞典。它的速度快得驚人。我把它上傳到網路上,並從 2010 年 2 月起一直運行著。
以下各節詳細說明 Go如何符合StatHat的需求,以及我們使用Go來解決我們問題的經驗。
執行環境
我們對我們的 API 和網頁應用程式伺服器使用標準 Go HTTP 封裝。所有要求首先透過 Nginx,任何非檔案要求都會委派給使用 Go的 HTTP 伺服器。後端伺服器全部使用 Go 編寫,並使用RPC 套件與前端溝通。
範本
我們使用標準template 封裝建置了一個範本系統。我們的系統增加了版面配置、一些常見格式設定函式,以及在開發期間動態重新編譯範本的能力。我們對 Go 範本的效能和功能感到非常滿意。
改裝
在我之前的工作中,我曾參與開發一款使用 C++編寫的電子遊戲《黑暗王座》。我們有一些標頭檔案,在修改後需要完全重新建置整個系統,耗時 20-30 分鐘。如果有人變更了Character.h
,他會成為所有其他程式設計師的眼中釘。除了這種煎熬之外,它還大幅拖慢了開發時間。
從那時起,我一直嘗試選擇允許快速、頻繁改裝的技術。有了 Go,編譯時間不再是問題。我們可以在幾秒內重新編譯整個系統,而不是幾分鐘。開發網頁伺服器立即啟動,測試幾秒內完成。正如前面提到的,範本會在變更時重新編譯。結果是 StatHat 系統非常容易使用,編譯器並未形成瓶頸。
RPC
由於 StatHat 是多層式系統,我們想要一個 RPC 層,讓所有通訊都可以標準化。有了 Go,我們使用rpc 封裝和gob 封裝來編碼 Go 物件。在 Go 中,RPC 伺服器會取用任何 Go 物件並註冊其已匯出的方法。不需要透過中間介面描述語言。我們發現它非常容易使用,我們的許多核心應用程式伺服器都不到 300 行程式碼。
函式庫
我們不想花時間為 SSL、資料庫驅動程式、JSON/XML 解析器等事物重新撰寫函式庫。儘管 Go 是一種年輕的語言,但它有許多系統封裝和越來越多使用者貢獻的封裝。除了少數例外,我們已經為我們需要的所有事物找到了 Go 封裝。
開源
依我們的經驗,使用開放原始碼工具極具價值。如果某事出錯,能夠逐層檢視來源且無任何黑盒子,將會非常有助益。擁有語言、網路伺服器、套件和工具的程式碼讓我們得以瞭解系統中每個元件的運作方式。Go 中的所有內容都是開放原始碼。在 Go 程式碼庫中,我們經常閱讀測試,因為它們通常提供如何使用套件和語言功能的絕佳範例。
效能
人們仰賴 StatHat 來取得其資料的最新分析,我們需要系統盡可能地回應迅速。在我們的測試中,Go 的效能勝過大部分的競爭對手。我們對上 Rails、Sinatra、OpenResty 和 Node 進行測試。StatHat 一直透過追蹤各種類型的效能指標(例如,關於請求、特定任務的持續時間、記憶體使用量)來監控自身。因此,我們能夠輕鬆地評估不同的技術。我們也利用了 Go 測試套件的基準效能測試功能。
應用程式層級並行處理
前生前,我在 OkCupid 擔任 CTO。我在那裡使用 OKWS 的經驗讓我體悟到非同步編程的重要性,尤其是在處理動態網頁應用程式時。完全沒有理由要同步執行以下工作:從資料庫載入使用者、接著找到他們的統計資料、接著找到他們的警示。這些工作全都應該並行的執行,但令人驚訝的是,許多熱門架構並不支援非同步。Go 在語言層級支援這個功能,無需任何回呼介面「義大利麵」。StatHat 廣泛使用 goroutines 來並行執行多個函式,並透過通道在 goroutines 之間分享資料。
主機和部署
StatHat 在 Amazon 的 EC2 伺服器上執行。我們的伺服器分為下列幾種類型
-
API
-
網頁
-
應用程式伺服器
-
資料庫
每種類型的伺服器至少配備兩台,且分屬不同的區域,以提供高可用性。要新增一台新的伺服器到配置中,僅需幾分鐘的時間。
要進行部署,我們會先將整個系統建置到一個加註時間戳記的目錄中。我們的封裝腳本會建置 Go 應用程式、壓縮 CSS 和 JS 檔案,以及複製所有腳本和組態檔。然後將此目錄分發到所有伺服器,讓所有的伺服器都擁有相同的發行套件。每個伺服器上的腳本會查詢其 EC2 標籤,並判斷它負責哪部分的執行,以及啟動/停止/重新啟動任何服務。我們經常只部署到伺服器的子集。
更多
如需有關 StatHat 的更多資訊,請前往 stathat.com。我們正在釋出一些我們撰寫的 Go 程式碼。前往 www.stathat.com/src 取得所有 StatHat 開放原始碼專案。
如需進一步瞭解 Go,請前往 golang.org。
下一篇文章:了解 Go 社群
上一篇文章:從零開始使用 Go:在 24 小時內於 Google 首頁上架
部落格索引