部署 有关 ruby 进程的内存性能优化

magic · 2013年06月06日 · 最后由 robbin 回复于 2013年06月17日 · 12652 次阅读

大家好,最近部署了服务在 Linode 上(1G RAM,8 CPU (1x priority)),前端是 Android,后端是 Rails+Grape 做 API 服务器,基本服务器架构是 Nginx+Passenger+ROR+Memcache+MySQL。

启了 4 个 Nginx,6 个 ruby 进程;从 newrelic 监控的数据来看,CPU 占用率不到 1%, IO 也不到 1%,内存占用 70% 左右


Processes
User    Count   CPU Memory
ruby    magic   6   0.5%     572 MB
mysqld  mysql   1   0.0%     36.7 MB
nginx   nobody  4   0.0%     12 MB
memcached   magic   1   0.0%     10.2 MB

从上面的数据来看,主要是 ruby 进程占用了大部分内存;目前应用特点是 PV 比较高,业务比较简单;由于之前没太多处理高并发的部署经验,如何在有限的内存的情况下处理更多的并发量?大家有什么好的建议和意见?急求 ing~ @lgn21st @Rei @hooopo @poshboytl @fredwu @yedingding @robbin

把内存升级到 4G,然后继续观察,等 4G 内存不够,继续升级内存到 8G,等 8G 不够的时候在考虑进一步优化代码,缓存和架构。这里有个 RailsCast-China 的视频,关于暴走漫画的性能调优方面的,可以借鉴 http://railscasts-china.com/episodes/baozoumanhua-jiagou

要优化首先要测量现在的水平,然后找瓶颈。楼主的应用一部署就有很大量的访问?

现在 ruby 的程序基本上都是内存不够,cpu 绝大多数情况下都是 5% 一下。

楼主的应用都用了哪些 gem 呢?空跑 rails 单进程项目都要将近 50m 6 个就是 300m 或者楼主把 6 个 ruby 进程各自是什么贴出来?现在这样子不好识别...

真心觉得没有必要一开始就跟 1G 内存死磕,Linode 上升级一下内存真的很贵吗?感觉可能升级了内存后都没有必要优化了,或者过几个月再优化都来得及。

6 个 ruby 而且还用了 Rails 的进程才 572 MB,这真的算很省了 ...

同样的逻辑用其他 Ruby 框架实现,估计内存能省大约一半 再改用 PHP 实现,内存还能再省至少 3/4。

所以,还是改用最最先进的 PHP 语言吧。

升级到 ruby2.0 可以节省 20% 左右内存。

#8 楼 @linjunhalida 升级到 PHP 还能节省 80% 左右内存呢 ...

#9 楼 @bhuztez golang 省更多

这个内存还可以吧,相对 rails 来说,@lgn21st 说的对啊,加内存,有时间去想怎么把 1g 内存用的再少点儿,不如加点内存实在啊

#5 楼 @lgn21st 我是想在 1G 的配置下尽量能挖掘出优化的空间,等实在不行了,我们再升级内存。我们这个应用是免费服务,也没广告;目前都是自己的投入,所以尽可能节省些。

#7 楼 @reus 谢谢,我研究下。

#8 楼 @linjunhalida 正准备从 1.9.3 升级到 2.0。

#2 楼 @Rei 这个应用服务器端之前是朋友自己用 PHP 弄的,他擅长的是 Android 端,没多少经历维护服务器;所以最近我用 ROR 重写了服务器端的代码,整个应用每天的 PV 大概会有 100W,目前只有部分用户升级到新版本,Linode 内存就告急了,所以要想办法先解决这个内存问题才行。

为什么是 6 个 ruby?不是 4 个

1G 内存实在太小了,稍微复杂一点的 rails 应用,一个进程很容易就跑到 200M,还是升级一下内存吧,4G 是标配了。

#16 楼 @jimrokliu 当时是想,有 8 个核,启 6 个应该没问题。没想那么多 呵呵

6 个会占用比较多的内存,如果你的问题是内存颠簸引起的性能下降,还是减少些实例,可以换成基于事件并发模型的服务器,例如 rainbow.

#18 楼 @Magic 其实 API 类的应用 可以考虑用 Cramp 或者 Sinatra 重写 本身 rails 的几个 gem 就很吃内存 而你大部分时候是针对接口格式用不到 就比较悲剧

1G 内存实在太小了,就算升级到 4G,每月的差价也抵不过程序员 1 天的工资。 话说你一天的时间肯定完成不了 4G 缩减为 1G 的程序优化。

#9 楼 @bhuztez 升级到 ruby2.0 只需要检查 gem 支持,测试一遍。

额,换到 Digital Ocean 然后你就发现同样的价格内存翻番,CPU 只剩双核,正好适合楼主的情况。 2GB 内存不够了就砸 40 刀每月,内存再翻番。 4GB 内存还是不够,就找个比较便宜的 Dedicated Server , 60 刀左右能租到 24GB - 32GB 的,自己注意一下备份和 failover ...

先简单用 ab 工具测试一下现在能撑多少并发。

要减少内存可以去掉 rails,纯 api 服务 rails 的作用不大。

#23 楼 @blacktulip 一分钱一分货,DigitalOcean 的网络抽风频率很高。 当然楼主要的是内存,DigitalOcean 满足需求。

#26 楼 @blacktulip 我们每小时一次,从国内和国外各个点监控,2 台 DigitalOcean 的 VPS,每周至少抽风 5 次以上。 我是说相比 20 美元均价的主流 VPS。如果跟其他 5-7 美元的低价 VPS 相比,他家的抽风算平均水平。

#27 楼 @kgen 竟然会这样,等我也监控一段时间看看,你的抽风是什么意思,是完全不通么?

我说的抽风是:国内一线城市的电信联通过去 500ms,或者美国当地的节点 MTR 过去有 10% 以上的丢包。 考虑到机房网络平均情况,海外对海外有 10% 以上的丢包是很高很高了。 上上周我们给 DogitalOcean 反应了 sfo1 机房严重丢包的问题(20-30%),他们说已经知晓并在处理了,但之后断断续续好几个小时差几个小时,大概 5 天后才完全恢复。

#28 楼 @blacktulip 楼上忘记 AT 你了

100w PV? 我觉得你可以找投资了吧

如果部署再 paas 平台上会不会就很好解决了呢?

#32 楼 @mobiwolf 账单会哗哗上涨

恩,可以设定一个大约的阀值。可能只是这几天量高,需要加内存,或者其他的。等一段之后,就不需要了呢。paas 可以弹性的调整。heroku 如果不翻墙的话,也许很好把

#31 楼 @ShiningRay CPU 1% 支持 100W 日 PV,本身的技术就值得获得投资,可以授权给 Intel 改进指令预测,授权给微软和 Redhat 改进操作系统。

#35 楼 @kgen 1% 是指负载还没切过来,楼主奇怪空载情况下内存占用高。Ruby 的部署一般就是持久占用内存的。

#36 楼 @Rei 纯粹跟楼主开个玩笑,并无恶意

#37 楼 @kgen 我太死板了……

加内存或者优化,如果要优化,首先明确资源消耗在哪里,其它就容易了 内存分析我一般也就是 ObjectSpace 一下

昨天升级 Linode 配置到 2G 内存,通过 newrelic 数据看到,内存在 30% 左右(600M),现在访问是平均 200rpm,请求相应平均 150ms;按照这个计算,每秒可以处理 6(1000ms/150ms)* 6(ruby 进程数) = 36 个请求,每天 100W 请求应该没问题。

按照上面的计算,暂时没压力;但是我们计划之后在这机器要部署几个其他项目,所以内存优化及性能调优还会继续研究(没办法,总共就这台机器,屌丝程序员一枚)

#36 楼 @Rei 应该是的,每个 100M,总共 6 个,占用 600M 左右。从现象来看没有因为访问减少而释放多余的内存。

#42 楼 @Magic 没有访问也是占那么多的,如果错误使用内存,比如载入一个文件,或者有内存泄露,内存占用就会升高。浮动不大就是正常。

#3 楼 @iamroody 我用 rails 做了一个项目,现在是 cpu 是瓶颈,2,3 百 reqs/s 的访问后,cpu 基本是 80% 左右了。(ngnix +passenger+redis+mysql(ssd))

2,3 百 reqs/s 持续多长时间?几核的 CPU?访问过后,是哪些个进程 CPU 占用比较大?

有个专门 for api 的 rails 不知道楼主用没有 rails-api

#46 楼 @steven_yue 上 api 讲究性能就不如直接上 goliath。

你的问题不在于单个 ruby 进程占用多少内存,而在于应该尽量少开进程的情况下,尽可能多的提高系统并发性能。

在 8 CPU (1x priority) 的服务器上,你开太多进程对提高并发性能没有多少帮助,建议如下:

1、nginx 开 1 个 worker 就行了,开 4 个没必要 2、既然是 API Server,就扔掉 Rails,直接用 Passenger/Unicorn/Rainbows 跑 grape,进程内存会节省很多,我估计能从 100MB 下降到 60MB 左右。 3、少开点进程,最多开 4 个 ruby 进程,观察一下请求的 IO 并发状况,如果并发不高,用 unicron 即可,如果并发高,可以改用 rainbows 跑多线程 4、如果你需要更高的 IO 并发,可以改用 goliath 跑 grape,内存不会更节省,但是并发性能会进一步提高 5、如果你不怕麻烦,可以把操作系统换成 32bit 的,能很大程度上节省内存 (缺点就是内存不能超过 4G)

#48 楼 @robbin 谢谢你的建议。我调整下进程数量,再观察下;另外我打算把 rails 换成 sinatra 试试。

#49 楼 @Magic 上面有人建议升级 ruby1.9.3 到 ruby2.0,这个建议也很靠谱。我刚刚测试过了,ruby2.0 的向下兼容 1.9.3 非常好,可无痛升级,而且 2.0 默认打开了 copy-on-write,多进程情况下可共享框架加载的内存,大约能节省 30% 的物理内存占用。

#50 楼 @robbin 这个端午前已升级。但是内存占用量好像没有下降。我理解是 ruby 进程开启就占用 100M,不管是否已使用完,所以没看到内存占用下降。不知道理解是否对?

#51 楼 @Magic COW 是使用 Passenger/Unicorn 的时候,子进程会共享父进程的共享内存区 (主要是加载 Rails 框架那部分内存)。你在单纯的 ruby 进程上看不到减少,但服务器总物理内存会节省。

你可以用 gc-cow.rb 这个脚本测试一下就知道了,使用 Ruby2.0 的时候,fork 出来的子进程的 Private 内存占用明显下降。

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