瞎扯淡 我们为什么会选择 Golang

shawnyu · 2015年08月09日 · 最后由 rasefon 回复于 2015年08月11日 · 9986 次阅读

前情提要: 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 面临的问题

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 基于 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,而且经过这么长时间的发展,生态应该会好很多,但是尽管这样,迁移之后 仍然有很多工作要做吧?

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 倍的方案。我觉得我们在挑选方案的时候 也要有这种意识。虽然有些方案确实也可以解决目前的困境,但是对以后的架构调整是否有益,或者说兼容。

另外像 Unicorn 这样 每个进程同时只能处理一个请求(one process per request),不仅仅是极度的浪费,而且如果某一个 action 突然变慢 将会占满整个 worker poll。导致整个服务都不可用。

为什么不考虑换线程服务器比如 puma。

em 常年不更新也变成一个坑了。

#1 楼 @rubyu2 暂时我们 api 服务状态非常好 还没有重构的必要。

#2 楼 @shawnyu 能说说为什么选择用 gorm ? 有没有对比其他的 ORM ?

#2 楼 @shawnyu 还有,应该是有很多以前 model 里面的逻辑需要用 golang 再写一遍,那么就是要维护两份不同语言的相同业务逻辑,这个事情有什么可以分享的经验?

C# 在 Linux 上面运行得相当好相当稳定,很多年前就是这样了。参考 http://www.mono-project.com/

#4 楼 @ch3n 我们现在是根据业务需要重写,没有保持一致。另外我觉得最佳实践应该是 有统一数据层,然后不同的地方在不同的引用出做修改,比如说某一个服务引用了一个 model 并且需要新加一个字断之类的 应该在这个服务自己的数据库新建表做记录。

gorm 是因为 star 比较多吧?

@shawnyu 从软件角度来看,换语言,换环境,的确能够提升不少的性能。 如果换种出发点,从硬件角度,既然 IO 消耗如此严重,是否评估过升级硬盘为 SSD 硬盘呢 😄 这样,软硬的提升,会再次带动整个系统的效率提升。

#8 楼 @luolinae86 硬件提升却是是一方面,这次主要是硬件性能不能被充分利用,另外,ucloud 给我们的机器全部都是 ssd 的。

JRuby 基于 rvm ?

JRuby 基于 JVM

使用 Go 解决了问题,说明暴走漫画做了正确的事情,且能很好的 handle 新语言,应该点赞

关于 EventMachine,如果记得没错的话,虽然是 Reactor Pattern,但是 EventMachine 是基于线程池实现的,且默认 thread pool 大小是 20

https://github.com/eventmachine/eventmachine/blob/master/lib/eventmachine.rb#L1091

其他关于 EventMachine 的文档,以及使用,debug 吐槽也都是对的,我想 Ruby 跟 Go 实现的效率比较,除了语言效率的差别,区别更大的是 EventMachine 跟 Go 的并发处理能力的差别么?

nodejs 呢?

@shawnyu

由于 markdown 标题可以这么写 ## ... ##

所以 C# 中的 # 漏掉了,像下面这么写就不会漏了:

## C\#

#14 楼 @luikore 囧 改过之后就是 "c \" 了 我用了全角符号改了下

#13 楼 @kikyous 没研究过,对 node 无感啊。逃)

#15 楼 @shawnyu 啊... 应该是

#### C\# ####

C#

:)

@ch3n 撇开 gorm 功能应该是最多的不说。。。他有个强大的插件系统,你可以基于他写各种插件,例如我们基于它写的类似 rails admin/active admin 类似的后台管理软件 http://getqor.com/ ;)

为什么不是选择 scala?貌似 scala 非常接近 ruby。

#18 楼 @zhangjinzhu 谢谢 jinzhu 老师亲自回复

Parse 的 Video 放出来了 http://blog.parse.com/learn/moving-our-api-from-ruby-to-go-the-video/

P.S. 看这个视频,对英语听力有特殊要求,我还在适应中。

我前面一个项目在遇到性能问题的时候,也是用 golang 来解决的 中间尝试 puma/thin/rainbow 等等,大小坑无数 em 在纯 http 相关的性能不错,一但有数据库连接,就坑无数了 最近的高并发语言里,我就会点 golang...所以就选 golang,效果相当不错

#19 楼 @jimrokliu 如果用了 scala 很可能所有 worker 都要你自己重构了!

我想知道如果用 erlang/otp 会不会效率更高。

gingerhot 如何使用 Rails 集成开发 Go API 提及了此话题。 01月29日 05:14
需要 登录 后方可回复, 如果你还没有账号请 注册新账号