Go 博客

奇虎 360 与 Go

周洋
2015 年 7 月 6 日

这篇客座博客文章由奇虎 360 软件工程师周洋撰写。

奇虎 360 是中国主要的互联网和移动安全产品及服务提供商,并运营着一个大型的基于 Android 的移动分发平台。截至 2014 年 6 月底,奇虎拥有约 5 亿月活跃 PC 互联网用户和超过 6.4 亿移动用户。奇虎还运营着中国最受欢迎的互联网浏览器和 PC 搜索引擎之一。

我的团队,推送服务团队,为公司内部 50 多个产品(包括 PC 和移动端)提供了基础消息服务,其中包括我们开放平台上的数千个应用。

我们与 Go 的“情缘”可以追溯到 2012 年,当时我们首次尝试为奇虎的一款产品提供推送服务。最初的版本是使用 nginx + lua + redis 构建的,由于负载过高,未能满足我们对实时性能的要求。在这种情况下,新发布的 Go 1.0.3 版本引起了我们的注意。我们仅用了几周时间就完成了一个原型,这主要得益于它提供的 goroutine 和 channel 特性。

最初,我们基于 Go 的系统运行在 20 台服务器上,总共有 2000 万个实时连接。系统每天发送 200 万条消息。现在,该系统运行在 400 台服务器上,支持超过 2 亿个实时连接。它现在每天发送超过 100 亿条消息。

随着业务的快速扩张和对推送服务日益增长的应用需求,最初的 Go 系统很快达到了瓶颈:堆大小上升到 69G,最大垃圾回收 (GC) 暂停时间达到 3-6 秒。更糟糕的是,我们不得不每周重启系统以释放内存。如果我们不考虑放弃 Go 并用 C 重写整个核心组件,那是不诚实的。然而,事情并没有完全按照我们的计划进行,我们在迁移业务逻辑层的代码时遇到了麻烦。结果是,当时唯一的维护人员(我自己)不可能在维护 Go 系统的同时,确保逻辑转移到 C 服务框架。

因此,我决定继续使用 Go 系统(这可能是我必须做出的最明智的决定),并且很快取得了很大的进展。

以下是我们进行的一些调整和一些关键的收获:

  • 使用持久连接(使用连接池)替换短连接,以减少通信过程中缓冲和对象的创建。
  • 适当使用对象池和内存池,以减轻 GC 的负载。
  • 使用任务池,这是一种由一组长期运行的 goroutine 消费连接 goroutine 发送的全局任务或消息队列的机制,以替代短期运行的 goroutine。

  • 监控和控制程序中的 goroutine 数量。缺乏控制可能导致 GC 承受难以承受的负担,这是由于无限制地接受外部请求导致的 goroutine 激增造成的,因为发送到内部服务器的 RPC 调用可能会阻塞最近创建的 goroutine。

  • 在移动网络下,记得给连接添加读写截止时间;否则,可能会导致 goroutine 阻塞。在局域网下,应谨慎且适当地应用此设置,否则会影响 RPC 通信效率。

  • 使用管道 (Pipeline)(利用 TCP 的全双工特性)来提高 RPC 框架的通信效率。

结果,尽管人力资源有限,我们成功推出了三次架构迭代和两次 RPC 框架迭代。这一切都归功于 Go 的开发便利性。下面是最新的系统架构图:

持续改进的过程可以用下表说明:

此外,经过这些优化后,不再需要临时释放内存或重启系统。

更令人兴奋的是,我们开发了一个在线实时 Go 程序性能剖析的可视化平台。现在我们可以轻松访问和诊断系统状态,找出任何潜在的风险。这是一个系统运行中的屏幕截图:

这个平台最棒的地方在于,我们可以通过使用分布式压力测试工具(也是用 Go 构建的)来模拟数百万在线用户的连接和行为,并观察所有实时可视化数据。这使我们能够评估任何优化的有效性,并通过识别系统瓶颈来排除问题。

到目前为止,几乎所有可能的系统优化都已实践过。我们期待着 GC 团队带来更多好消息,以便进一步减轻繁重的开发工作。我想我们的经验总有一天会过时,因为 Go 还在不断发展。

这就是为什么我想以诚挚感谢能够参加Gopher China 来结束我的分享。这对我们来说是一场盛会,可以学习、分享,并提供了一个窗口,展示 Go 在中国的普及和繁荣。奇虎内部的许多其他团队都已经了解或尝试使用 Go。

我相信,未来将有更多中国互联网公司加入我们,用 Go 重建他们的系统,Go 团队的努力将使更多开发者和企业受益。

下一篇文章:Go、开源、社区
上一篇文章:GopherChina 之行报告
博客索引