前情提要: https://ruby-china.org/topics/26785
其实在用 Golang 重写我们的 worker 系统之前是做过很多调研的。 而真正让我们下定决心的是 Parse 的一篇文章。How We Moved Our API From Ruby to Go and Saved Our Sanity。文中讲了 Facebook 的 Parse 团队为什么选择 Golang 代替 Ruby。我翻译下关键几点:
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。
Parse 使用了 EventMachine 实现他们的 push 服务,在使用过程中,由于相关的 gem 成熟度不够,总是碰到一些奇怪的 bug。还是生态的问题,导致实现某些功能的时候无轮子可用。
Parse 现在是 Ruby 实现,所以 JRuby 就是正确的选择?JRuby 基于 JVM 可以并发处理大量请求,看起来非常不错。不是的!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,而且经过这么长时间的发展,生态应该会好很多,但是尽管这样,迁移之后 仍然有很多工作要做吧?
Parse 团队有很多 c++ 的开发经验,不过 c++ 代码难以 debug 和维护。就我个人而言 严重觉得 c++ 肯定不是 web 项目的选择。另外缺乏 web 相关各种库支持。
c#有非常好的并发模型支持。不过在Linux上。。。还是看下一条吧
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 倍的方案。我觉得我们在挑选方案的时候 也要有这种意识。虽然有些方案确实也可以解决目前的困境,但是对以后的架构调整是否有益,或者说兼容。