最近很长一段时间,一直在查性能问题,几个月过去了,ab 并发量从原来的 4 台机器 20 多并发,到现在 100 多,还是非常低。
服务器的环境从原来的 Nginx + Unicorn + Padrino + Mongoid
改成了Nginx + Rainbows(EventMachine) + Padrino + Moped + Sinatra::Synchrony
性能提升的也一般
业务逻辑上,主要是论坛的那种逻辑,分为 客户端 - 群组 - 讨论 - 回复等几个层次,主要使用 reference 进行查询,用于测试并发的接口的逻辑主要就是查询一个客户端下所有的群组信息,以及某一个用户在这些群组的权限,查询的次数已经尽量减少了。
执行 perf 输出,发现 garbage_collector 占比很高,不知道什么原因
大家都帮忙想想办法吧
mongo 的数据设计上还是尽量查什么就存什么吧。
页面还是尽量做成容易缓存的 (例如一个帖子页面带了用户信息的话,就很有点难缓存,但如果用户信息用 ajax 加载的话,帖子和回复就可以缓存了).
升 2.1 估计可以减少 40% GC 时间。
要做详细分析啊,看看瓶颈是在 rails 还是在数据库 i/o 上,rails 本身可以加缓存,数据库操作也是可以缓存的,不要直接读写数据库,先在内存操作,然后定时同步到数据库中。
其实问题不在 Padrino,不在 Mongodb,也不在 Unicorn,,,在于如何使用。
好像 Rails 网站的单机用 ab 测试,100 并发都很容易呀,API 应该更快才是.........
#4 楼 @cassiuschen
大姨妈的毛病具体是什么?知道症状可能可以找出线索...
如果用 puma 开多线程部署呢?sinatra::synchrony
貌似问题也不少,而且依赖的 em::synchrony
已经不维护了...
另外 ab 是本地测试么?最好用网络测试。本地测如果要减少 ab 本身的各种问题的影响,用 wrk 测会更准一些。
#10 楼 @cassiuschen 是用所有的部署方式都会 down 几分钟?前面加不加 nginx 都会?GC 早就变成增量式的,不会停掉全世界的了... 如果万一真是什么地方产生了海量对象,就只好 dtrace 找了...
GC 有压力,可以试下减少对象的分配 参考:https://github.com/blog/1489-hey-judy-don-t-make-it-bad
不止一次看到些“优雅”的代码,不仅执行效率低,对对象的分配也毫无节制。仅仅因为看起来比较魔法或者短小,就被看成优雅,实在不可取。
这可以通过设计缓存的粒度来解决,我们的应用在 api 上也有类似你说的权限判断问题,比如用户访问一个地点,需要返回该用户是否收藏过这个地点以及该地点的其他信息,可以将这部分拆封开来,我们用的是 rabl 做模板输出,代码类似如下:
object @attraction
node :current_user_favorited do |a|
user_signed_in? && PoiFavorite.where(:poi_type => 'Attraction', :poi_id => a.id, :user_id => current_user.id).present?
end
extends "api/attractions/show_cache"
然后在 show_cache 这个文件里面,再可以用 Preload 减少 N+1 的查询:
object @attraction
ActiveRecord::Associations::Preloader.new(@attraction, :xxx => xxx).run
attributes :id, :name, :description, :lat, :lng
...
供参考
EM 是采用 select 的 IO 模式,如果不阻塞,理论上单机 C10k,检测下你的一个页面不配置页面缓存时,需要阻塞多少 ms,瓶颈在那里,就优化那里,@zangcw,总觉得数据是这样出来的: 100 并发=20 个默认的 rack(如 thin) 服务器的线程数(每个都阻塞执行)*4 台单机