Iron.io从Ruby迁移到Go:减少了28台服务器并避免了连锁故障
过去几个月,我在用Go语言编写系统,所以一直密切关注能够证实我的选择是正确的”的那些消息。当Iron.io记录下 使用Go重写IronWorker的经验时,机会出现了。Iron.io中非常忙碌的作业执行系统最初是用Ruby编写的。
重写的结果是:
- 服务器数量从30台减少到2台,而且第2台仅用于实现冗余。
- CPU利用率下降至5%以下。
- 所用内存也下降了很多。Rails应用在启动时需要接近50MB内存,而Go版本在启动时只需要几百KB内存。
- 连锁故障成为历史。
- 运行于成百上千台服务器上的新服务完全用Go编写。
- 他们认为,Go的使用使他们得以“构建伟大的产品,得以成长和扩展,同时还能吸引一流人才”。他们的博客中写道:“我们认为,在可预见的未来,它将继续帮助我们成长。”一般建议根据人才库的规模来选择编程语言,他们发现Go语言的选择帮助他们吸引了顶级人才。
- 容易部署,因为Go程序会编译为一个单一静态映像。
- Go存在的小问题:需要学习一种新语言,库还有限。
- 如果服务器流量很高,或者你想应对突发的增长,Go是很好的选择。
当然,如果没有第二系统效应(Second System Effect)的影响,重写会快得多,不过你可能会回想起LinkedIn的类似经验: LinkedIn从Rails迁移到Node:服务器减少27台,速度提升多达20倍。
下面说明一下Go解决的问题:
- 在使用Ruby时,服务器的CPU利用率维持在50%到60%之间。为将CPU利用率保持在50%左右,可以增加服务器,这样就可以优雅地处理流量峰值。但这种方式有个缺点:需要昂贵的服务器来进行水平扩展。
- 他们有一个非常有趣的故障模式。当流量出现峰值时,Rails服务器的CPU利用率将达到100%。这就致使该服务器看上去是失效了,进而引发负载均衡器把流量路由到其余服务器上,这样更多服务器的CPU利用率会飙升到100%。最终导致连锁故障。
使用Ruby有助于产品快速上市,这个理由十分在理。虽说性能并非一切,但这里我们看到了性能的价值,尤其是在Web层之外,性能更为重要。表现良好的服务在健壮性和成本方面都有巨大优势。
以往,系统的弱点被服务器的量所掩盖,但大量服务器要花很多钱,而且未必总能解决问题。
性能起到了缓冲作用,使系统既能承载流量而不至崩溃,又能容忍一次次的突发冲击。即时(Just-in-time)分配和启动新实例都需要时间,而长时间的流量峰值可能引发连锁故障。针对性能编码,而不是针对产品上市时间编码,即可防患于未然。
Go 并不完美
如果看一下Go的Google网上论坛,你会发现Go并不是没有 性能问题。不过这些问题往往可以编码绕过。比如用bufio.ReadSlice代替bufio.ReadString,能够去掉一次数据复制,代码魔法般地快了若干倍。
学习这些技巧是需要时间的,尤其对这样一种新语言而言。
让Go真正处于不利地位的是,JVM和V8 JavaScript引擎在垃圾回收优化和代码生成方面已经有了许多年的经验积累。Go要赶上尚需时日。
性能永远不会是免费的。你必须巧妙地编码,将状态共享最小化,不要老翻腾内存,要尽力剖析,理解自己的语言并且能够用这种语言来做正确的事。
查看英文原文: Iron.io Moved From Ruby to Go: 28 Servers Cut and Colossal Clusterf**ks Prevented
感谢 杨赛对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至 [email protected]。也欢迎大家通过新浪微博( @InfoQ)或者腾讯微博( @InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。