Мы только что перешли с пассажира на единорога, чтобы разместить несколько приложений для рельсов. Все работает отлично, но через New Relic мы заметили, что запросы стоят в очереди от 100 до 300 мс.
Вот график:
Я понятия не имею, откуда это взялось, вот наша конфа единорога:
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
наш 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;
}
и наше конкретное приложение 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;
}
У нас нет большой нагрузки, поэтому я не понимаю, почему запросы зависают в очереди. Как указано в конфиге единорога, у нас есть 6 рабочих-единорогов.
Любая идея, откуда это может исходить?
Ваше здоровье
ИЗМЕНИТЬ:
Среднее количество запросов в минуту: около 15 в большинстве случаев, более 300 при просмотре, но после миграции мы не получили ни одного запроса.
Средняя загрузка ЦП: 0,2–0,3
Пробовал с 8 рабочими, ничего не изменилось.
Я также использовал капли дождя, чтобы посмотреть, чем заняты рабочие-единороги.
Вот рубиновый скрипт:
#!/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)
Как я его запускал:
./linux-tcp-listener-stats.rb -d 0.1 /var/run/engineyard/unicorn_actor.sock
Таким образом, он в основном проверяет каждую 1/10 с, есть ли запросы в очереди и есть ли они на выходе:
сокет | количество обрабатываемых запросов | количество запросов в очереди
Вот суть результата:
https://gist.github.com/f9c9e5209fbbfc611cb1
EDIT2:
Вчера вечером я попытался уменьшить количество рабочих nginx до одного, но это ничего не изменило.
Для справки: мы размещены на Engine Yard и имеем экземпляр Medium с высокой производительностью ЦП, 1,7 ГБ памяти, 5 вычислительных блоков EC2 (2 виртуальных ядра с 2,5 вычислительными блоками EC2 в каждом)
Мы размещаем 4 приложения rails, у этого есть 6 рабочих, у нас есть один с 4, один с 2 и еще один с одним. Все они столкнулись с очередями запросов с тех пор, как мы перешли на unicorn. Я не знаю, обманывал ли Passenger, но New Relic не регистрировал очереди запросов, когда мы его использовали. У нас также есть приложение node.js, обрабатывающее загрузку файлов, база данных mysql и 2 redis.
ИЗМЕНИТЬ 3:
Мы используем ruby 1.9.2p290, nginx 1.0.10, unicorn 4.2.1 и newrelic_rpm 3.3.3. Завтра я попробую без newrelic и сообщу вам о результатах здесь, но для информации мы использовали пассажира с новой реликвией, ту же версию ruby и nginx, и у нас не было никаких проблем.
ИЗМЕНИТЬ 4:
Я попытался увеличить client_body_buffer_size
и proxy_buffers
с помощью
client_body_buffer_size 256k;
proxy_buffers 8 256k;
Но это не помогло.
ИЗМЕНИТЬ 5:
Наконец-то мы разобрались… барабанная дробь… Победителем стал наш SSL-шифр. Когда мы изменили его на RC4, мы увидели, что очередь запросов сократилась со 100-300 мс до 30-100 мс.
If your application responses are larger than the socket buffer or if you’re handling large requests (uploads), worker processes will also be bottlenecked by the speed of the client connection. You should not allow unicorn to serve clients outside of your local network.
Насколько я понимаю, это значительно повлияет на ваши тесты производительности. Если это полезная информация, я перепишу это как ответ. - person MrGomez   schedule 03.04.2012