Sequel + ADO + Puma 不是线程查询

Sequel + ADO + Puma is not threading queries

我们在 Windows Server 2008 + SQLServer 2008 + Ruby + Sinatra + Sequel/Puma

中有一个网站 运行

我们为我们的网站开发了 API。 当许多客户端同时请求访问点时,客户端开始出现 RequestTimeout 异常。

我进行了一些调查,发现 Puma 可以很好地管理多线程。 但是 Sequel(或 Sequel 下面的任何层)一次处理一个查询,即使它们来自不同的客户端。

事实上,如果我启动许多 Web 服务器,每个服务器侦听一个不同的端口,并且我为每个客户端分配一个不同的端口,则不会发生 RequestTimeout 异常。

我还不知道问题是 Sequel、ADO、ODBC、Windows、SQLServer 还是什么。 事实是我无法切换到任何其他技术(如 TinyTDS)

Bellow 是一小段带有屏幕截图的代码,您可以使用它来复制错误:

require 'sinatra'
require 'sequel'
CONNECTION_STRING =
 "Driver={SQL Server};Server=.\SQLEXPRESS;" +
 "Trusted_Connection=no;" +
 "Database=pulqui;Uid=;Pwd=;"

DB = Sequel.ado(:conn_string=>CONNECTION_STRING)
enable :sessions
configure { set :server, :puma }
set :public_folder, './public/'
set :bind, '0.0.0.0'
get '/delaybyquery.json' do
 tid = params[:tid].to_s
 begin
 puts "(track-id=#{tid}).starting access point"
 q = "select p1.* from liprofile p1, liprofile p2, liprofile p3, liprofile p4, liprofile p5"
 DB[q].each { |row| # this query should takes a lot of time
 puts row[:id]
 }
 puts "(track-id=#{tid}).done!"
 rescue=>e
 puts "(track-id=#{tid}).error:#{e.to_s}"
 end
end
get '/delaybycode.json' do
 tid = params[:tid].to_s
 begin
 puts "(track-id=#{tid}).starting access point"
 sleep(30)
 puts "(track-id=#{tid}).done!"
 rescue=>e
 puts "(track-id=#{tid}).error:#{e.to_s}"
 end
end 

以上代码中有2个接入点:

  1. delaybyquery.json,加入相同的 table 5 会产生延迟 次。请注意,table 必须大约 1000 行才能获得 查询工作真的很慢;和

  2. delaybycode.json,通过调用 ruby 睡眠产生延迟 功能。

两个接入点都收到一个 tid (tracking-id) 参数,并且都写入 在 CMD 中输出,因此您可以在同一过程中遵循两个过程的 activity window 并检查哪个接入点阻止了来自其他接入点的传入请求 浏览器。

为了测试,我在同一个 chrome 浏览器中打开了 2 个选项卡。 以下是我正在执行的 2 个测试。

第 1 步:运行 网络服务器

c:\source\pulqui>ruby example.app.rb -p 81 我得到下面的输出

步骤 #2:通过代码测试延迟

我打电话给这个 URL: 127.0.0.1:81/delaybycode.json?tid=123 5 秒后,我将其称为另一个 URL 127.0.0.1:81/delaybycode.json?tid=456 下面是输出,您可以在其中看到两个调用并行工作

click here to see the screenshot

步骤 #3:通过查询测试延迟

我打电话给这个 URL: 127.0.0.1:81/delaybyquery.json?tid=123 5 秒后,我将其称为另一个 URL 127.0.0.1:81/delaybyquery.json?tid=456 下面是输出,您可以在其中看到调用一次有效 1。 对访问点的每次调用都以查询超时异常结束。

click here to see the screenshot

这几乎可以肯定是因为 win32ole(Sequel 的 ado 适配器使用的驱动程序)。它可能不会在查询期间释放 GVL,这会导致您看到的问题。

如果您不能切换到 TinyTDS 或切换到 JRuby,那么如果您想要并发查询,您唯一的选择是 运行 单独的网络服务器进程,并让反向代理服务器向它们发送请求。