Abbiamo appena migrato da passeggero a unicorno per ospitare alcune app di rotaie. Tutto funziona alla grande ma notiamo tramite New Relic che le richieste sono in coda tra 100 e 300ms.unicorno richiesta di accodamento
Ecco il grafico:
Non ho idea di dove questo viene da ecco la nostra conf unicorno:
current_path = '/data/actor/current'
shared_path = '/data/actor/shared'
shared_bundler_gems_path = "/data/actor/shared/bundled_gems"
working_directory '/data/actor/current/'
worker_processes 6
listen '/var/run/engineyard/unicorn_actor.sock', :backlog => 1024
timeout 60
pid "/var/run/engineyard/unicorn_actor.pid"
logger Logger.new("log/unicorn.log")
stderr_path "log/unicorn.stderr.log"
stdout_path "log/unicorn.stdout.log"
preload_app true
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
end
before_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :TERM : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
sleep 1
end
if defined?(Bundler.settings)
before_exec do |server|
paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
paths.unshift "#{shared_bundler_gems_path}/bin"
ENV["PATH"] = paths.uniq.join(File::PATH_SEPARATOR)
ENV['GEM_HOME'] = ENV['GEM_PATH'] = shared_bundler_gems_path
ENV['BUNDLE_GEMFILE'] = "#{current_path}/Gemfile"
end
end
after_fork do |server, worker|
worker_pid = File.join(File.dirname(server.config[:pid]), "unicorn_worker_actor_#{worker.nr$
File.open(worker_pid, "w") { |f| f.puts Process.pid }
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
nostro nginx.conf:
user deploy deploy;
worker_processes 6;
worker_rlimit_nofile 10240;
pid /var/run/nginx.pid;
events {
worker_connections 8192;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nopush on;
server_names_hash_bucket_size 128;
if_modified_since before;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_buffers 16 8k;
gzip_types application/json text/plain text/html text/css application/x-javascript t$
# gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Allow custom settings to be added to the http block
include /etc/nginx/http-custom.conf;
include /etc/nginx/stack.conf;
include /etc/nginx/servers/*.conf;
}
e la nostra app specifica nginx conf:
upstream upstream_actor_ssl {
server unix:/var/run/engineyard/unicorn_actor.sock fail_timeout=0;
}
server {
listen 443;
server_name letitcast.com;
ssl on;
ssl_certificate /etc/nginx/ssl/letitcast.crt;
ssl_certificate_key /etc/nginx/ssl/letitcast.key;
ssl_session_cache shared:SSL:10m;
client_max_body_size 100M;
root /data/actor/current/public;
access_log /var/log/engineyard/nginx/actor.access.log main;
error_log /var/log/engineyard/nginx/actor.error.log notice;
location @app_actor {
include /etc/nginx/common/proxy.conf;
proxy_pass http://upstream_actor_ssl;
}
include /etc/nginx/servers/actor/custom.conf;
include /etc/nginx/servers/actor/custom.ssl.conf;
if ($request_filename ~* \.(css|jpg|gif|png)$) {
break;
}
location ~ ^/(images|javascripts|stylesheets)/ {
expires 10y;
}
error_page 404 /404.html;
error_page 500 502 504 /500.html;
error_page 503 /system/maintenance.html;
location = /system/maintenance.html { }
location/{
if (-f $document_root/system/maintenance.html) { return 503; }
try_files $uri $uri/index.html $uri.html @app_actor;
}
include /etc/nginx/servers/actor/custom.locations.conf;
}
Non siamo sotto carico pesante, quindi non capisco perché le richieste siano bloccate in coda. Come specificato nel conf unicorno, abbiamo 6 lavoratori unicorno.
Qualche idea da dove potrebbe provenire?
Acclamazioni
EDIT:
richieste medio al minuto: circa il 15 per la maggior parte del tempo, più di 300 in fa capolino, ma non abbiamo vissuto uno dalla migrazione.
CPU Media carico: 0,2-0,3
Ho provato con 8 lavoratori, non ha cambiato nulla.
Ho anche usato raindrops per vedere cosa stavano facendo gli unicorni.
Ecco lo script ruby:
#!/usr/bin/ruby
# this is used to show or watch the number of active and queued
# connections on any listener socket from the command line
require 'raindrops'
require 'optparse'
require 'ipaddr'
usage = "Usage: #$0 [-d delay] ADDR..."
ARGV.size > 0 or abort usage
delay = false
# "normal" exits when driven on the command-line
trap(:INT) { exit 130 }
trap(:PIPE) { exit 0 }
opts = OptionParser.new('', 24, ' ') do |opts|
opts.banner = usage
opts.on('-d', '--delay=delay') { |nr| delay = nr.to_i }
opts.parse! ARGV
end
socks = []
ARGV.each do |f|
if !File.exists?(f)
puts "#{f} not found"
next
end
if !File.socket?(f)
puts "#{f} ain't a socket"
next
end
socks << f
end
fmt = "% -50s % 10u % 10u\n"
printf fmt.tr('u','s'), *%w(address active queued)
begin
stats = Raindrops::Linux.unix_listener_stats(socks)
stats.each do |addr,stats|
if stats.queued.to_i > 0
printf fmt, addr, stats.active, stats.queued
end
end
end while delay && sleep(delay)
Come ho lanciato:
./linux-tcp-listener-stats.rb -d 0.1 /var/run/engineyard/unicorn_actor.sock
Così è fondamentalmente controlla ogni 1/10s se ci sono richieste nella coda e se ci sono si uscite:
la presa | numero di richieste in elaborazione | il numero di richieste nella coda
Ecco un succo del risultato:
https://gist.github.com/f9c9e5209fbbfc611cb1
EDIT2:
ho cercato di ridurre il numero di lavoratori nginx per una notte scorsa ma non ha cambiato nulla.
Per informazioni, siamo ospitati su Engine Yard e dispongono di un'istanza media con CPU alta 1,7 GB di memoria, 5 unità di calcolo EC2 (2 core virtuali con 2.5 unità di calcolo EC2 ciascuna)
Ospitiamo 4 applicazioni di rotaie, questa ha 6 lavoratori, ne abbiamo una con 4, una con 2 e un'altra con uno. Stanno tutti sperimentando l'accodamento delle richieste da quando siamo migrati verso l'unicorno. Non so se il Passeggero stava barando, ma New Relic non ha registrato alcuna richiesta di accodamento quando lo stavamo usando. Abbiamo anche un'app node.js che gestisce i caricamenti di file, un database mysql e 2 redis.
EDIT 3:
Stiamo usando rubino 1.9.2p290, nginx 1.0.10, 4.2.1 unicorno e newrelic_rpm 3.3.3. Domani proverò senza novità e ti farò sapere i risultati qui, ma per le informazioni che stavamo usando passeggero con una nuova reliquia, la stessa versione di rubino e nginx e non ha avuto alcun problema.
EDIT 4:
ho cercato di aumentare la client_body_buffer_size
e proxy_buffers
con
client_body_buffer_size 256k;
proxy_buffers 8 256k;
Ma non ha fatto il trucco.
EDIT 5:
Abbiamo finalmente capito tutto ... rullo di tamburi ... Il vincitore è stata la nostra cifra SSL. Quando lo abbiamo cambiato in RC4 abbiamo visto la richiesta di accodamento in coda da 100-300 ms a 30-100 ms.
è il tuo tempo di risposta effettivo aumentato nel corso quando si sta utilizzando per passeggeri, o è solo la ripartizione di New Relic di ciò che è responsabile per i tempi di risposta che è allarmante? –
Quando stavamo usando il passeggero, stavamo servendo le richieste in circa 120 ms, quindi sì, è il tempo medio di richiesta allarmante. La mia domanda principale è: perché le richieste sono bloccate in coda quando abbiamo poche richieste al minuto con 6 lavoratori unicorni? – Mike
Qual è il carico? Quanti RPM? Hai fatto i conti (i tuoi 6 lavoratori possono tenere il passo con il carico)? Hai provato a generare altri lavoratori unicorni? –