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 主页上线
博客索引