我们是如何让服务器从30台缩减到2台的:从Ruby迁移到Go语言

我们开发第一版的IronWorker已经是3年前的事了,是用Ruby写的,API基于Rails开发。我们没用多久就发展成了相当大的规模,很快我们就触及到了Ruby程序的承载上限。长话短说,我们切换到了Go语言,请接着读下去,下面是事情如何一步步发展的。

最初的设计

首先,做一点背景介绍:我们开发的第一版IronWorker,起初叫做SimpleWorker(很不错的名称,不是吗?),用的是Ruby。我们过去是一个顾问公司,为其它公司开发应用,在当时有两个东西被炒得非常火:亚马逊的Web Services和Ruby on Rails。所以我们开发的应用都基于AWS的Ruby on Rails架构,并因此吸引了不少大客户。我们开发IronWorker的初衷是来源我们自身的需求。我们有不少做硬件设备的客户,他们会7×24小时不停的给我们发送数据,我需要收集这些数据,把它们整理成有用的信息。典型的做法就是让定时任务每天每小时的遍历这些数据。我们想到应该开发一个东西,能够处理所有用户的数据,而不必做一大批的定时任务为每个客户单独处理。于是我们开发了一个服务类应用,并在内部使用了一段时间,但后来我们认为一定会有其他的人也需要这个应用,于是我们决定公布它,这样,IronWorker诞生了。

我们的服务器可承受的CPU使用率大概在50-60%。当超过这个额度,需要增加服务器来保持它在50%左右。只要我们不介意大量的服务器租用费(我们当然介意),这种模式会工作的很好。但最大的问题是出现在流量大量陡增时。当一个大型的流量高峰到来时,它会产生多米诺效应,会拖垮我们整个的服务器集群。当某些指标超过50%的阀值时,我们的Rails服务器会吃掉100%的CPU使用率,变成无响应状态。这会导致负载均衡设备认为它已经宕了,把它移出分发池,于是这台无响应的服务器上的负载就会转移到池中其他服务器上。因为池中剩下的服务器需要承载这失去的服务器上的负载再加上流量高峰,必然会有第二台服务器倒下,负载均衡设备又会把它移除,前赴后继。很快池中所有的服务器都会耗尽。这种现象也叫做colossal clusterf**k (ref: +Blake Mizerany)。

这里是一个简单描绘多米诺宕机效应的绘图

这里是一个简单描绘多米诺宕机效应的绘图。

在这种架构下避免这种事情发生的唯一办法就是保持有大量的额外处理能力,让我们的服务器的负载远低于它应该能承受的能力,但这意味着要多花一大笔钱。必须让这种状态有所改变。

重写应用

我决定重写这应用。这是一个很容易的决定,很显然,我们的Ruby on Rails无法支撑我们业务规模的增长。我们都有多年的开发Java的经历,曾经写过很多东西只需要很少的资源就能处理大量负载,远比Ruby on Rails的处理能力强的多,我知道我们可以做出很多改进。于是,接下来的问题变成了应该使用哪种语言?

选择一种语言

我对任何新建议都持开放的态度,最不济,我还可以重回到Java。Java是一个在很多方面(比如性能上)很棒的语言(是吗?),但经过了多年的Ruby程序编写后,我已经为它的开发效率所痴迷。Ruby很有趣,朴素,简单。

我们搜索了一下比Ruby性能上要好的脚本语言(Ruby并不是很差),比如Python和Javascript/Node,我们还研究了Java的衍生语言,如Scala和Clojure,和还有其它的语言例如Erlang(AWS使用了它)和Go语言(golang)。Go语言获胜。事实上,它的作为基础组成部分的并发特征太强悍了;它的标准核心库提供了我们开发API服务需要的所有东西;它简洁;它编译快;很像Ruby,Go语言很有趣;最后,数字是不会撒谎的。经过了一次原型制作和性能测试后,我们知道了通过它我们可以将负载能力做重大的提高。经过了征询团队的意见(“这很好,它背后有Google支持”),我们打起了攻坚战。

起初决定押宝Go语言时,这是一个有风险的决策。Go语言的社区并没大量的形成,没有多少开源的Go语言工程项目,在正式产品上使用Go语言的成功案例并不多(有吗?)。而且我们并不敢肯定在认定Go语言后能否招到这方面的顶级人才,但很快我们发现我们可以招到顶级人才——正是因为我们选择了Go语言。我们是首个公司公开的宣称在我们的产品中使用Go,首个公司在Go语言邮件列表里贴出Go语言工作职位招聘。很多顶级程序员希望来我们这里,就是因为这样他们可以在每日的编程中使用Go语言。

Go语言的表现

Go语言

在我们推出了首个Go语言版本后,我们的服务器数量从30个减少到了2个,并且只留了2个服务器做冗余储备。它们就像是根本没有被使用,完全就像没有任何程序在上面运行。我们的CPU使用率低于5%,整个应用的运行启动只消耗了几百KB的内存(仅在启动时),相比之下Rails应用要耗用50MB。这种比较甚至是包括了虚拟机内存使用!这真是天与地的差别。从此我们再也没有经历过多米诺宕机的事故。

相比起之前,我们的业务增长了许多。我们有了更大的流量,我们增加了两个新服务(IronMQIronCache),我们有数百个服务器来支持客户的需求。这全部是用Go做后台马达。回想起来,选择Go语言是一个明智之举,它让我们开发出更好的产品,帮助公司成长,扩大企业规模,并且吸引了一流人才。我相信它会继续在可预见的未来帮助我们进步。

[英文原文:How We Went from 30 Servers to 2: Go ]
分享这篇文章:

13 Responses to 我们是如何让服务器从30台缩减到2台的:从Ruby迁移到Go语言

  1. Null says:

    有点眼熟

  2. lemboyz says:

    怎么有点像推广GO的枪手文。

  3. zhy says:

    这太扯了,我不得不浮出水面来发表一下感想

  4. halfelf says:

    通篇就没见说到底是什么问题,只是说Rails有问题,难道不是你自己架构的问题?

  5. dsfsdf says:

    同上,明显是自己的架构有问题,说一大堆没用的东西。

  6. 独行猫儿 says:

    感觉其实是因为ruby版本的代码增生了太多变得臃肿了,于是决定重构,重构时更换了代码语言为Go。实际上本文和Ruby和Go的性能问题没啥关系。

  7. 唐官小杰 says:

    这篇祸害文又跑到这来了,小编转载前先google下好吗,最近外刊评论的文章和别处太多重复了,质量下降严重啊

  8. Adam says:

    真有那么夸张?
    30-》2
    100% -》5%
    50M -》x00K

  9. 寻觅 says:

    文章细节方面太笼统了,如果Ruby的性能真的如此之差,怎么还会有如此多人在使用? 这应该是他们公司内部使用Ruby时的架构问题,然后在使用了go语言后,将架构梳理清理,去掉冗余的逻辑所以才达到的效果吧。

  10. 孙俊文 对这篇文章的反应是

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据