2017-01-17 2 views
0

Nous avons un site Web en cours d'exécution dans Windows Server 2008 + SQLServer 2008 + Ruby + Sinatra + Sequel/PumaSequel + ADO + Puma n'est pas de filetage des requêtes

Nous avons développé une API pour notre site Web. Lorsque les points d'accès sont demandés par plusieurs clients, en même temps, les clients commencent à recevoir des exceptions RequestTimeout. J'ai étudié un peu, et j'ai noté que Puma gère très bien le multi-threading. Mais Sequel (ou n'importe quelle couche sous Sequel) traite une requête à la fois, même si elles proviennent de clients différents. En fait, les exceptions RequestTimeout ne se produisent pas si je lance de nombreux serveurs Web, chacun écoute un port différent et j'affecte un port différent à chaque client.

Je ne sais pas encore si le problème est Sequel, ADO, ODBC, Windows, SQL Server ou quoi. La vérité est que je ne peux pas passer à toute autre technologie (comme TinyTDS)

Bellow est un petit morceau de code avec des captures d'écran que vous pouvez utiliser pour reproduire le bug:

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 

Il y a 2 points d'accès dans le code ci-dessus:

  1. delaybyquery.json, qui génère un retard en se joignant à la même table 5 fois. Notez que la table doit contenir environ 1000 lignes pour que la requête fonctionne très lentement; et

  2. delaybycode.json, qui génère un retard en appelant simplement la fonction sommeil rubis .

Les deux points d'accès reçoit un paramètre tid (suivi-id), et les deux écrivent le outout dans le CMD, afin que vous puissiez suivre l'activité des deux processus dans la même fenêtre et vérifiez le point d'accès est bloquer les demandes entrantes provenant d'autres navigateurs .

Pour tester, j'ouvre 2 onglets dans le même navigateur chrome. Voici les 2 tests que j'effectue.

Étape 1: Lancez le serveur Web

c: \ source de \ Pulqui> Ruby example.app.rb -p 81 Je reçois la sortie ci-dessous

Étape # 2: Retard d'essai par le code

J'ai appelé à l'adresse suivante: 127.0.0.1:81/delaybycode.json?tid=123 et 5 secondes plus tard, j'appelle cette autre URL 127.0.0.1:81/delaybycode.json?tid = 456 Ci-dessous la sortie, où vous pouvez voir que les deux appels travaillent en parallèle

click here to see the screenshot

Étape # 3: Retard d'essai par Query

J'ai appelé à l'adresse suivante: 127.0.0.1:81/delaybyquery.json?tid=123 et 5 secondes plus tard, j'ai appelé cette autre URL 127.0.0.1:81/delaybyquery.json?tid=456 Ci-dessous est la sortie, où vous pouvez voir que les appels sont travaillant 1 à l'heure. Chaque appel à un point d'accès se termine par une exception de délai d'attente de requête.

click here to see the screenshot

+0

S'il vous plaît, cliquez sur les liens pour voir les captures d'écran. Toutes mes excuses, mais StackOverflow ne me permet pas encore de publier des images. –

Répondre

0

Ceci est presque certainement en raison de win32ole (le pilote que l'adaptateur de bruit Sequel utilise). Il ne libère probablement pas le GVL pendant les requêtes, ce qui causerait les problèmes que vous voyez.

Si vous ne pouvez pas basculer vers TinyTDS ou passer à JRuby, votre seule option si vous souhaitez que les requêtes simultanées soient exécutées est de traiter des serveurs Web distincts et d'envoyer un serveur proxy inverse à ces demandes.

+0

Merci Jeremy. –