2013-03-11 35 views
1

我正在使用Ruby Grape创建一个API,并面临以下问题。 当有新的GET请求时,请求大量数据,这需要很长时间,同时反应器被阻塞,并且在请求完成之前不能处理新的请求。 代码很直截了当:红宝石葡萄反应器被阻止

class API < Grape::API 
    resource :users do 
    get do 
     get_users() 
    end 
    end 
end 

get_users连接到另一个系统通过TCP,并得到大量转换成JSON数据。这是使用第三方宝石完成的。 什么是处理这种情况的最佳选择?

回答

0

我觉得两个选项:

  1. 设置乘客/麒麟等具有足够的工人来处理并发请求。
  2. 如果这还不够:重新制作API逻辑,以便长时间操作将分解为两个调用:第一个 - 请求,第二个 - 检查完成/检索结果。

而且,如果是适合的 - 你可以缓存get_users的结果()

+0

谢谢Yuriy。 1.我正在使用Thin。我正在考虑像NginX + HAProxy + Thin这样的体系结构,其中有几个实例。我也会检查乘客和独角兽。 2.我试图用EM.defer做类似的事情。你认为这是好方法吗?缓存是我没有想过的。我也会检查。 但我认为我更喜欢你的第二点。 – antiziclon 2013-03-11 21:18:55

+0

其实我的意思是另一回事。这里是一个例子: 1.客户端调用获取用户 2.应用程序保存此请求,并将生成的请求密钥返回给客户端 3.应用程序通过delayed_job或类似的方式生成get_users() 4.应用程序保存get_users()与请求密钥关联 5.客户端调用通过密钥获取用户 6.应用返回与密钥关联的结果。 当get_users()尚未完成时,应用程序应返回not_ready。 应用程序应该过期键和结果。 缺点是客户必须改变它的逻辑。所以这只适用于报表生成等非常长的操作。 – 2013-03-12 03:30:33

+0

我现在明白了。我不太喜欢这种方法,因为它需要客户改变其逻辑,如你所说。我会测试你的观点1,看看我能做些什么。 – antiziclon 2013-03-12 08:56:49

0

你的应用程序执行长时间运行的阻塞I/O操作。要很好地处理这些类型的工作负载,您的系统需要支持较高的I/O并发性。

传统的单线程多进程系统,如Phusion Passenger开源和Unicorn不适合这些类型的工作负载。它们可以处理的并发量受限于进程的数量。这个问题记录在独角兽的philosophy page,“在某些情况下更糟糕”一节或最近关于tuning Phusion Passenger's concurrency的Phusion文章中。

虽然由于其I/O模型均匀,Thin理论上能够处理高I/O并发性,但必须明确编写应用程序和框架才能充分利用此优势。很少有框架可以做到这一点。 Rails和Sinatra都不支持I/O。 Cramp支持它,并且还有另一个新的Evented框架,我忘记了它的名字。但看起来葡萄不支持偶数的I/O。

解决方案是切换到支持多线程的应用程序服务器,它也能够支持高I/O并发性。一个这样的应用服务器是Phusion Passenger 4 Enterprise,它支持混合多线程/多进程模型。多线程是并发的,而多进程是为了稳定性和利用多个CPU核心的能力。 Phusion博客describes optimal concurrency settings for different workloads.