Go 博客
奇虎360与Go
这篇客座博客文章由奇虎360的软件工程师杨舟撰写。
奇虎360是中国领先的互联网和移动安全产品及服务提供商,并运营着一个主要的Android移动分发平台。截至2014年6月底,奇虎拥有约5亿月活跃PC互联网用户和超过6.4亿移动用户。奇虎还运营着中国最受欢迎的互联网浏览器和PC搜索引擎之一。
我的团队——推送服务团队,为公司(PC和移动端)的50多个产品提供基础的消息服务,包括我们开放平台上的数千款应用。
我们与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重写整个核心组件,那就不诚实了。然而,事情并没有完全按计划进行,我们在迁移业务逻辑层的代码时遇到了麻烦。因此,当时唯一的人员(我)不可能在保证逻辑迁移到C服务框架的同时,还要维护Go系统。
因此,我做出了坚持使用Go系统的决定(这可能是必须做出的最明智的决定),并且很快取得了重大进展。
以下是我们做的一些调整和关键收获:
- 用持久连接(使用连接池)替换短连接,以减少通信过程中缓冲区的创建和对象的生成。
- 恰当使用对象和内存池,以减轻GC的负担。

-
使用任务池,一种由一组长期存在的goroutine消费全局任务或消息队列(由连接goroutine发送)的机制,以替换短暂存在的goroutine。
-
监控和控制程序中的goroutine数量。由于不加限制地接受外部请求可能导致goroutine激增,而发送给内部服务器的RPC调用可能会阻塞新创建的goroutine,因此缺乏控制可能会给GC带来无法承受的负担。
-
在移动网络下,请记住为连接添加读写截止时间;否则,可能会导致goroutine阻塞。在局域网下,请谨慎并正确地应用它,否则会损害RPC通信效率。
-
使用管道(TCP的全双工特性)来提高RPC框架的通信效率。
结果是,尽管人力资源有限,我们还是成功地对架构进行了三次迭代,并对RPC框架进行了两次迭代。这一切都归功于Go的开发便利性。下面是当前的系统架构。

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

此外,在这些优化之后,不再需要临时释放内存或重启系统。
更令人兴奋的是,我们开发了一个在线的实时可视化平台,用于分析Go程序的性能。现在我们可以轻松访问和诊断系统状态,锁定任何潜在的风险。以下是该系统运行时的截图。


该平台最大的优点是,我们可以通过应用分布式压力测试工具(也用Go构建)来模拟数百万在线用户的连接和行为,并观察所有实时可视化数据。这使我们能够评估任何优化的有效性,并通过识别系统瓶颈来规避问题。
到目前为止,我们已经实践了几乎所有可能的系统优化。我们期待GC团队能带来更多好消息,以便我们能从繁重的工作中进一步解脱出来。我猜想,随着Go的不断发展,我们的经验有一天也会过时。
因此,我希望通过感谢有机会参加Gopher China来结束我的分享。这是一个让我们学习、分享的盛会,也为展示Go在中国日益增长的普及度和繁荣景象提供了一个窗口。奇虎内部的许多其他团队已经了解或尝试使用Go。
我相信,将有更多中国互联网公司加入我们,用Go重塑他们的系统,并且Go团队的努力将在可预见的未来惠及更多的开发者和企业。
下一篇文章:Go、开源、社区
上一篇文章:GopherChina之行报告
博客索引