Rails Ruby-China.org 选择用 Thin 还是 Unicorn?

lgn21st · 发布于 2011年11月06日 · 最后由 realwol 回复于 2016年12月09日 · 17118 次阅读
3

问题的起因是这样的:Ruby-China.org部署在一个Linode 512的Instance上,系统只有512M内存,跑一个Nginx带两个Thin的instance,外加MongoDB,Redis,还有一些后台任务等等。前几天 @huacnlee 跟我说内存不够用了,两个Thin和MongoDB一上去内存就捉襟见肘了,需要考虑升级VPS的内存了,否则极有可能随时把其他的Services如MongoDB或者Redis搞挂掉。 [img]//ruby-china-files.b0.upaiyun.com/photo/a73f2b074d7e848ade1bf9bce8987abe.png[/img]

我当时建议用Unicorn试试看,Github和37Singles都全部迁移到了默认使用Unicorn作为Rails的server。昨天找了个时间测试了一下,开启2个Unicorn的worker_processes,发现每个worker的内存占用跟Thin基本上一致,也就是说使用Unicorn并没有内存使用上的优势。 [img]//ruby-china-files.b0.upaiyun.com/photo/cd1d5bdd4a4e2a71a7603f8a4bb207fd.png[/img]

我的理解是不管是thin,mongrel,webrick,还是unicorn,都需要载入一份完整的Rails instance,Rails instance的内存消耗是无法通过替换Server消减的。另外还有一个Memory Bloat的问题,当Rails server运行时间越长,占用的内存就越多,罪魁祸首是大量的ActiveRecord对象被hold在内存中,无法高效及时的释放掉,所以通常的作法是设定一个阈值,当Rails Server使用内存超过一个具体的数值一段时间后,就Restart这个Rails Server,这个方法在Production环境下已经被充分验证过是一个行之有效的解决方 案。

Unicorn的这种Master process + worker processes的工作方式,在总体内存消耗上比Thin要略微大一点点,不过Unicorn相对于Thin的优势在于他的Load balance机制是通过OS Kernel来实现的,以及进程管理非常的Unix风格,有利于简化部署和系统管理: http://sirupsen.com/setting-up-unicorn-with-nginx/

Load balancing between worker processes is done by the OS kernel. All workers share a common set of listener sockets and does non-blocking accept() on them. The kernel will decide which worker process to give a socket to and workers will sleep if there is nothing to accept().

Thin需要通过Nginx来做Load balancing,或者在多个Thin instance前面架设一个HAproxy来实现高效的Load-balancing,不过就系统组成复杂度,部署难易程度,以及Load balancing效能方面考虑,优选采用Unicorn的方案。

话说回来,我们仍然需尝试在其他地方压榨一些内存出来,或者考虑换回使用32bit的Linux?

共收到 44 条回复
3

这里有一篇关于Twitter使用Unicorn的文章,他们使用Unicorn替换掉了Mongrel后,处理request的时候降低了30%的CPU消耗,并使用一个定制的脚本自动监控并重启Unicorn workers。 http://engineering.twitter.com/2010/03/unicorn-power.html

3

在Github上有一篇Blog,讲的是Github是如何使用God来监控Unicorn的,包括根据CPU的占用或者内存消耗自动启动/重启Unicorn。 https://github.com/blog/519-unicorn-god

1

现在一个 server 占了多少内存呢?我一个类似网站,功能可能少点,passenger 一个 ruby 进程40M。如果太高的话可能要检查下代码。

39

unicorn 的一个 worker processes 占用内存40~44M,开两个worker processes连带master进程unicorn占用内存不过120~130M左右吧?还剩下380M内存难道不够?会否问题出现在MongoDB上?之前试用过一下MongoDB,似乎它会将剩下的内存全部占光。

3

#3楼 @Rei #4楼 @Los 有截图为证,不过现在显示图片有点问题,呼唤 @huacnlee 帮助修复。 Thin 或者 Unicorn 的一个proces启动后,立即占用90MB左右的内存,随着时间推移,可能会占用到140MB左右,甚至更多,我们可以开一个新帖分析一下内存消耗情况。这里我贴个skitch的截图: https://skitch.com/lgn21st/ggmmk/root-li387-252-ssh 从截图可以看到,两个Thin和resque是内存使用大户。resque貌似也载入了一个完整的rails环境,内存消耗接近90MB。

De6df3

#5楼 @lgn21st 图片绑定那个 l.ruby-china.org 的域名,DNS 貌似不对啊

De6df3

#4楼 @Los 和 MongoDB 没有关系,Rails 跑起来,一个 Thin 进程就有 90M 左右,目前 Mongodb 的进程才 15M

8

@lgn21st 的描述上看不管换Thin还是unicorn都无法解决问题。用切腹的方式也只是暂时缓解问题。 我觉得主要原因是用了太多的gems(https://github.com/huacnlee/ruby-china/blob/master/Gemfile.lock ),有些功能重复的,比如Mongoid和ActiveRecord。 至于Memory Bloat问题是完全可以人为控制的。 还有以目前的规模和需求来看,像resque这样的吃内存大户也不需要用,发邮件时fork一下也ok。

96

我的linode 512上,32bit Arch Linux,nginx,unicorn两个worker,postgres,redis,resque两个worker,resque-scheduler 内存在400左右,内存压力不大

之前在aws上用的passenger,每个worker的内存消耗和unicorn差不多。 resque的worker也占这么多内存,所以应该是rails环境占的。

之前在aws上的时候经常内存爆。但是我看linode有swap吗,内存不够的时候是不是会用到swap?是不是虽然性能慢点但不会因为无法分配内存而出错?

1

#8楼 @hooopo activerecord 有依赖,但是没载入。

96

就我个人而言,Unicorn相比于Thin并没有太大的优势。当项目大了之后,更需要细粒度的部署,我会倾向于Nginx + HA + Thin。这个内存的问题目前的解决方案最好是resque先去掉

De6df3

暂时还是将 Resque 关了,反正目前邮件提醒仍然有 Bug

96

#12楼 @huacnlee 邮件提醒功能很重要吗? 可以统计一下有多少人需要回复的邮件提醒

39

#11楼 @nowazhu Unicorn 的热部署优势很明显啊

41

邮件提醒不需要吧, 那样人们就会等着邮件提醒,不会上来再看了,对论坛发展不好

41

我有国内的独立服务器可以贡献出来 需要的话可以联系我 dave@liageren.com

De6df3

#16楼 @dave 靠谱么?

41

#17楼 @huacnlee 服务器? 算是靠谱吧,我自己的, 现在在跑我的网站,如果能为社区做点事也不错

3

#18楼 @dave 我找个时间跟你通个电话,了解一下,你有我的号码么?在Twitter上DM我一下吧

41

#19楼 @lgn21st skype上发给你了

3

#17楼 @huacnlee 我刚刚跟 @dave 通了个电话,@dave 是我的前同事,我了解了下情况,考虑到他的服务器目前用于他们自己的商业项目,虽然有大量的系统资源空闲,但是却无法完全开放权限给我们。所以我建议他们的服务器资源作为我们的backup。我们的社区发展下去,如果需要的话我就去升级Linode到1024或者购买位于日本的EC2,这个论坛的方向靠谱,不管是小额捐赠,或者大公司支持,我都有把握解决硬件资源问题。

132

apache + mongrel apache + fastcgi nginx+ passenger nginx + Haproxy + thin apache + passenger apache + unicorn

以上组合我都用过, 最后我还是选择了 nginx + passenger , 只因为 重启 忒方便

touch tmp/restart.txt

呵呵~!!!

96

#22楼 @wxianfeng unicorn 也不麻烦,kill -USR2 pid。好处是用户不会被中断。之前用passenger重启之后第一次访问要花点时间

De6df3

为了用 Http Streaming,现在改成了 unicorn 不过无缝重启还没有搞定

De6df3

无缝重启已经解决了,原来是这样的:

用这个命令就能通知 unicorn 进程重启

kill -USR2 `cat /rails/app/path/tmp/pids/unicorn.pid`

但是之前一直没成的原因是 unicorn.rb 里面有项 preload_app 开启了,将它去掉就可以用上面的命令重启

preload_app true

http://stackoverflow.com/questions/5794176/restart-unicorn-with-a-usr2-quitting-old-master

96

#6楼 @huacnlee 我这儿看不到图片,404

De6df3

#26楼 @blankyao 暂时有问题,正在想办法解决

142

#23楼 @cqpx Nginx + Passenger 重启我一般使用 Nginx 的 reload 功能,完全是无缝重启,也不怕服务器会中断服务 nginx -s reload

另外,上面大家都提到什么占用多少内存之类的,用什么监控的啊?直接用 top 么?

De6df3

top 就可以看到了

1

#28楼 @yzhrain 最好还是

touch tmp/restart.txt
96

不是说passenger + ree 可以减少30%内存占用么.. 我看他原理就是共享了一部分framework占用的内存空间 ,貌似是先加载框架,然后再fork , 我测试下来也是, 跑的实例越多 , ree在内存占用上的优势越明显

个人觉得unicorn最大的优势还是在于处理长动态请求, 因为他是基于事件驱动模型, 而且看了很多测试, 单个请求的速度 unicorn可能还比 thin 或者 passenger略微要慢一点

3

#30楼 @Rei 我觉得吧,用

touch tmp/restart.txt

其实也能实现优雅的重启 Unicorn 进程。不过我在想的是服务器上跑的不仅仅只有 Rails server, 还有数据库,redis,以及 resque 等等后台进程,跑一个 monitor 来监控这些所有的后台 Services,并自动完成 deploy 后重启。

Passenger 和 Thin 以及 Unicorn 背后的 Philosophy 和 Architecture 不同,就单机VPS,小网站而言,Passenger没有什么不好,不过我更认可 Unicorn 用 Unix Domain Socket 来完成进程间通讯,Loading balance 基于OS内核调度来实现,fork 一个 worker processor 出奇的快,配合 god 或者 monit 监控并发送 singal 来管理/切换服务器进程非常平顺,然后一切都尽在 Capistrano 掌控之下。

8

@lgn21st 管理一组应用进程用foreman比较不错:http://blog.daviddollar.org/2011/05/06/introducing-foreman.html

Heroku用的就是foreman,deploy以后所有进程一起重启。 在开发环境用起来也很方便。

196

http://ruby-taiwan.org 跑在 nginx + passenger 上....

78

32位下MongoDB有2G的限制。

数据量大了后,MongoDB内存要求会上去,它的设计哲学是尽量把index等放内存。不足时自动用系统调度swap(nmap)。这个时候就等着otm然后被系统干掉。在512的VPS上,插十万条数据然后做几个mapreduce就能搞出这问题来。另外楼上有朋友说的没错,它是有多少内存用多少的。

resque可以用hirefire这样的库来即使fork,省的大部分时间空占内存。

关键在于可能的话还是多加些内存:)

De6df3

现在资源已不再是问题,有盛大支持

96

打开 copy-on-write friendly gc 以后, 很多 gem 占用的内存其实只有一份

540

#1楼 @lgn21st 发现linode的部署这个,巨慢无比~~ 本地还挺快的~~

558

@huacnlee 刚看到 ruby-china server 又从unicorn 改到 thin了,能说下原因吗?

De6df3

#39楼 @camel 为了用 EventMachine

2220

nginx+Passenger和ExtJS实在是合不来,本来意图就是用哪里加载哪里,结果nginx给全绑一块儿了,研究了半天也不会取消,速度慢且不说,还有一堆重复加载的问题,实在是怕了它了 还是用了Thin,世界清静了……效率什么的再说吧=_=

2614

#3楼 @Rei 想请问下,内存不断上涨的话,检查代码,要检查哪些地方,比如你在写代码的时候,有哪些考虑

8087

进程内存达到一定阈值后,重启进程,如果这个时候进程正在处理请求,会出现问题吗

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册