Go 博客

用 Go 构建 StatHat

帕特里克·克罗斯比
2011 年 12 月 19 日

介绍

我叫帕特里克·克罗斯比,是一家名为 Numerotron 的公司的创始人。我们最近发布了 StatHat。这篇文章主要介绍了我们为什么选择用 Go 开发 StatHat,包括我们如何使用 Go 的详细信息。

StatHat 是一款用于跟踪代码中的统计数据和事件的工具。从 HTML 设计师到后端工程师,每个人都可以轻松使用 StatHat,因为它支持从 HTML、JavaScript、Go 和其他 12 种语言发送统计数据。

您将数字发送到 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 开发它。

2009 年 11 月 Go 发布后,我立即安装了它,并喜欢上了快速的编译时间、goroutine、通道、垃圾回收以及所有可用的包。我尤其高兴的是我的应用程序使用了很少的代码行。我很快就尝试制作了一个名为 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 测试包的基准性能测试功能。

应用程序级并发

在以前,我是 OkCupid 的 CTO。我在那里使用 OKWS 的经验让我了解了异步编程的重要性,尤其是在动态 Web 应用程序方面。没有理由您应该同步执行以下操作:从数据库加载用户,然后查找其统计数据,然后查找其警报。所有这些都应该同时进行,但令人惊讶的是,许多流行的框架都不支持异步。Go 在语言级别支持这一点,无需任何回调意大利面。StatHat 广泛使用 goroutine 并发运行多个函数,并使用通道在 goroutine 之间共享数据。

托管和部署

StatHat 运行在亚马逊的 EC2 服务器上。我们的服务器分为几种类型

  • API

  • Web

  • 应用程序服务器

  • 数据库

每种类型的服务器至少有两个,并且它们位于不同的区域以实现高可用性。添加新服务器只需几分钟。

要进行部署,我们首先将整个系统构建到一个带时间戳的目录中。我们的打包脚本构建 Go 应用程序、压缩 CSS 和 JS 文件,并复制所有脚本和配置文件。然后将此目录分发到所有服务器,以便它们都具有相同的分布。每个服务器上的脚本查询其 EC2 标签并确定它负责运行什么,并启动/停止/重新启动任何服务。我们经常只部署到服务器的一个子集。

更多

有关 StatHat 的更多信息,请访问 stathat.com。我们正在发布我们编写的一些 Go 代码。访问 www.stathat.com/src 以获取所有开源 StatHat 项目。

要了解有关 Go 的更多信息,请访问 golang.org

下一篇文章:了解 Go 社区
上一篇文章:从零到 Go:在 24 小时内在 Google 首页上发布
博客索引