故事的起因在这里。
之前发了一篇帖子,讲了暴漫用golang重构了worker系统,有好多朋友问到语言选择的问题。
其实在用Golang重写我们的worker系统之前是做过很多调研的。
真正让我们下定决心的是 Parse的一篇文章:How We Moved Our API From Ruby to Go and Saved Our Sanity。 文中讲了Facebook的Parse团队为什么选择Golang代替Ruby。
我翻译下关键几点:
Parse面临的问题
Parse跟暴漫的技术栈比较相似: 服务器Unicorn,部署使用Capistrano。在高流量面前很多问题都被指数级放大,在每次部署的时候 app server重启都要很长时间。并且Unicorn的重启并不是真正的‘graceful’(这个我们也有同感,重启之后服务会中断10秒左右,另外Parse在用Golang重构之后还写了一个库‘Grace’ 专门解决重启中断服务的问题)。 这样造成的服务中断带来的影响非常不好。
另外像Unicorn这样 每个进程同时只能处理一个请求(one process per request),不仅仅是极度的浪费,而且如果某一个action突然变慢 将会占满整个 worker poll。 导致整个服务都不可用。
方案选择
Parse在EventMachine,JRuby,c++, c#, golang 之前做了对比,并最终选择了go。
EventMachine
Parse使用了EventMachine实现他们的push服务,在使用过程中,由于相关的gem成熟度不够,总是碰到一些奇怪的bug。还是生态的问题,导致实现某些功能的时候无轮子可用。
JRuby
Parse现在是Ruby实现,所以JRuby就是正确的选择? JRuby基于rvm可以并发处理大量请求,看起来非常不错。 不是的!JRuby缺乏各种异步库的支持。Parse担心为了应对业务的增长,还要第二次重构:从JRuby到JAVA。 并且Parse的工程师团队是在不想在JVM中部署并调节各种参数。
文中还提到了 Twitter团队在迁移到Scala之前对JRuby的调查:Twitter对MRuby做了很多工作,包括自己写了一个GC工具。本来在MRuby上工作很好,效率很高的库,到了JRuby上 就不好使了(说白了就是各种库不成熟,生态系统太重要!)迁移过去之后虽然JRuby本身快了2倍,但是其他东西都面临各种问题,有点得不偿失
That's not a fault of JRuby; it's just that at the moment the surrounding ecosystem is still kind of immature. CRuby's was too; we put a lot of investment into it, which we can now take advantage of, and we would have to do the same for JRuby.
暴漫团队说实话没人用过JRuby,而且经过这么长时间的发展,生态应该会好很多,但是尽管这样,迁移之后 仍然有很多工作要做吧?
C++
Parse团队有很多c++的开发经验, 不过c++代码难以debug和维护。 就我个人而言 严重觉得c++肯定不是web项目的选择。 另外缺乏 web相关各种库支持。
C
c#有非常好的并发模型支持。不过在Linux上。。。还是看下一条吧
Golang
Golang语言效率高,语言层面支持并发,语法非常简单 易于上手,并发模型容易理解。(我们重构之前只给团队讲了一个小时的语法,然后给了一些些好的worker作为参考,然后大家都可以顺利的重构2-3个worker,在两周的时间内)。 应该是worker系统的最佳选择。
最后回到暴走漫画的问题
大家的疑问更多是 既然都是io消耗,为什么golang会快这么多。 我试着解释下(水平有限): golang静态语言 不需要类型推断 抛弃了各种语法糖,在语言效率层面上快上不少,另外在数据库io方面 gorm 没有 ActiveRecord的黑魔法,自然会快很多。
暴漫的worker系统瓶颈在高并发峰值,一旦抗不过去后面就会持续累积。 而golang在单个任务上虽然只有5倍快,但是良好的并发机制,使job的执行速度飞快。 而在原系统中 每台机器150并发跑慢之后,有些100ms的任务都等到23s之久。
单个任务执行速度快5倍, 并发再快5倍,所以从10台减到1台 而 golang机器还游刃有余是合理的。
Parse在重构的时候考虑的是能容纳当前业务峰值的10倍的方案。我觉得我们在挑选方案的时候 也要有这种意识。虽然有些方案确实也可以解决目前的困境,但是对以后的架构调整是否有益,或者说兼容
有疑问加站长微信联系(非本文作者)