Charity Majors是移动后端支持平台Parse的工程师。近日,他 撰文 介绍了他们将API从Ruby迁移到Go的过程。
2011年, Parse 借助Ruby on Rails快速推出了第一个版本。他们用 Unicorn 作为HTTP服务器,用 Capistrano 部署代码,用 RVM 管理环境,并用许多开源gems处理 YAML 解析、oAuth、JSON解析、MongoDB及MySQL等方面的工作。此外,他们还用Chef管理他们的基础设施。
起初,平台运行良好。但随着代码库的增长,部署时间越来越长,Unicorn服务器无法很平稳地重启。到2012年底,他们有200个API服务器运行在 m1.xlarge 类型的实例上,每个实例24个Unicorn工作进程。该平台每秒需要为来自60000个移动应用的3000个请求提供服务。一次完整部署或回滚需要20分钟。另外,在通常的Ruby on Rails设置中,工作进程池大小固定,每个工作进程一次只能处理一个请求。随着API流量和应用数量的增加,“一个请求一个进程”的Rails模型开始无法满足平台的扩展需求,而增加数据库和工作进程也增加了故障点和性能退化的可能。
于是,他们认为,他们需要迁移到一个完全不同于Rails的异步工作模型。他们对比了如下选项:
最终,他们选择了Go,用它重写了EventMachine推送后端、核心API服务器,实现了Rails中间件的处理功能,结果:Parse平台的可靠性提高了一个数量级;API不再因为数据库和后端服务的增加而日益变得脆弱;由于去掉了大量的gems和隐含假设,代码库变得更干净;Ops团队不用每周处理多次Ruby API故障了;预分配的API服务器池缩减了约90%;移除了孤立的Rails API服务器筒仓,简化了架构;完整集成测试的时间由25分钟缩减至2分钟;完整API服务器部署(包含滚动重启)的时间由30分钟缩减至3分钟;Go API服务器启动更平稳。
虽然Parse成功地实现了迁移,但是许多网友都认为Majors给出的选择理由并不充分。网友pron指出,JVM易于监控、控制、调试和性能分析。在大多数情况下,JVM调优只需要设置GC方式、最大堆大小和新生代比率三个值。对此,Majors的答复是,“我们讨厌有关Java和JVM的一切”。网友headius则为Parse团队没有试用JRuby感到可惜,因为单个JRuby实例就可以处理成百上千的并发请求,而且不需要采用异步方式。他认为,JRuby团队不需要重写就可以解决Parse的问题。网友Zazi Bazuka则这样评论道:
我讨厌这篇博文,攻击Ruby成了现在的一种趋势。但攻击总是来自不了解Ruby生态系统的人。为什么不使用 Puma 或其它多线程服务器?!为什么使用EventMachine?互联网上到处都是不应该使用它的文章,你们应该使用 celluloid.io 代替它。
Majors的文章 在Hacker News上也引发了激烈的讨论 ,其中许多网友同样对Parse的选择过程存在疑问。网友aikah就表示:
当了解业务域和性能问题时,Go是一个不错的迁移目标。但是,我不推荐初学者用它构建安全的Web应用程序,因为……Go确实不适合用于传统Web站点的快速开发。让我吃惊的是,Parse用Rails编码,我原以为他们以Node.js为基础构建,因为Cloud Code用了JS。
对此,lacker答复说:
我们考虑过它。那时,一个很大的Node代码库看上去很难维护。不过,工具比那时好了。如果我们现在重新讨论,我认为,采用Node的理由会更令人信服,如果我们等到ES6成为标准后再讨论,理由还会更充分。
感谢郭蕾对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群 )。