Go 博客
使用 Go 构建 StatHat
引言
我的名字是 Patrick Crosby,我是 Numerotron 公司(StatHat 的开发者)的创始人。我们最近发布了 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 模板的性能和功能非常满意。
试错
在我以前的一份工作中,我曾参与开发一款名为《Throne of Darkness》的视频游戏,该游戏是用 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 测试包的基准性能测试功能。
应用程序级并发
在我过去的职业生涯中,我是 OkCupid 的 CTO。我在那里使用 OKWS 的经验让我认识到异步编程的重要性,尤其是在动态 Web 应用程序方面。您永远不应该同步执行类似以下的操作:从数据库加载用户,然后查找他们的统计数据,然后查找他们的警报。这些都应该并发执行,但令人惊讶的是,许多流行的框架没有异步支持。Go 在语言级别支持这一点,而不会出现任何回调地狱。StatHat 大量使用 goroutines 来并发运行多个函数,并使用 channels 在 goroutines 之间共享数据。
托管和部署
StatHat 运行在 Amazon 的 EC2 服务器上。我们的服务器分为几种类型
-
API
-
Web
-
应用程序服务器
-
数据库
每种类型的服务器至少有两个,并且它们位于不同的区域,以实现高可用性。添加一台新服务器只需几分钟。
为了部署,我们首先将整个系统构建到一个带时间戳的目录中。我们的打包脚本构建 Go 应用程序,压缩 CSS 和 JS 文件,并复制所有脚本和配置文件。然后,该目录分发到所有服务器,使它们拥有完全相同的发行版。每台服务器上的一个脚本会查询其 EC2 标签,确定它负责运行什么,并启动/停止/重启任何服务。我们经常只部署到一部分服务器。
更多
有关 StatHat 的更多信息,请访问 stathat.com。我们正在发布一些我们编写的 Go 代码。前往 www.stathat.com/src 获取所有开源的 StatHat 项目。
要了解更多关于 Go 的信息,请访问 golang.org。
下一篇文章: 了解 Go 社区
上一篇文章: 从零到 Go:24 小时内在 Google 主页上线
博客索引