Очередь запросов единорога
Мы просто перешли от пассажира к единорогу, чтобы разместить несколько рельсовых приложений.
Все работает отлично, но мы замечаем через New Relic, что запрос находится в очереди между 100 и 300 мс.
Здесь график:
![enter image description here]()
Я понятия не имею, откуда это происходит от нашего единорога conf:
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;
}
Мы не находимся под большой нагрузкой, поэтому я не понимаю, почему запросы застревают в очереди.
Как указано в unicorn conf, у нас есть 6 рабочих-единорогов.
Любая идея, откуда это может произойти?
Приветствия
EDIT:
Средние запросы в минуту: около 15 в большинстве случаев, более 300 в заглядываниях, но мы не переживали один с момента миграции.
Средняя загрузка процессора: 0.2-0.3
Я попробовал с 8 рабочими, ничего не изменил.
Я также использовал raindrops, чтобы посмотреть, что делали единороги.
Здесь ruby script:
#!/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/10s, если есть запросы в очереди, и если есть выходы:
сокет | количество обрабатываемых запросов | количество запросов в очереди
Вот суть результата:
https://gist.github.com/f9c9e5209fbbfc611cb1
EDIT2:
Я попытался сократить число рабочих nginx до последней ночи, но ничего не изменил.
Для информации мы размещаемся на Engine Yard и имеем среднюю память с высоким процессором 1,7 ГБ памяти, 5 вычислительных модулей EC2 (2 виртуальных ядра с 2,5 вычислительными единицами EC2 каждый)
У нас есть 4 приложения для рельсов, у этого есть 6 рабочих, у нас есть один с 4, один с 2, а другой с одним. Они все испытывают очередь запросов, так как мы перешли к единорогу.
Я не знаю, обманывал ли Пассажир, но 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 мс.
Ответы
Ответ 1
Я только что диагностировал аналогичный новый новый реликтовый граф как полностью вину SSL. Попробуйте отключить его. Мы наблюдаем время ожидания запросов 400 мс, которое падает до 20 мс без SSL.
Некоторые интересные моменты о том, почему некоторые поставщики SSL могут быть медленными: http://blog.cloudflare.com/how-cloudflare-is-making-ssl-fast
Ответ 2
Какая версия ruby, unicorn, nginx (не имеет значения, но стоит упомянуть) и newrelic_rpm вы используете?
Кроме того, я бы попробовал запустить базовый перфекционный тест без newrelic. NewRelic анализирует ответ, и есть случаи, когда это может быть медленным из-за проблемы с rindex в рубине до 1.9.3. Это обычно заметно только тогда, когда вы ответ очень велик и не содержит тегов тела (например, AJAX, JSON и т.д.). Я видел пример этого, когда 1MB AJAX ответ занимал 30 секунд для анализа NewRelic.
Ответ 3
Вы уверены, что буферизируете запросы от клиентов в nginx и затем буферизуете ответы от единорогов, прежде чем отправлять их обратно клиентам. Из вашей настройки кажется, что вы это делаете (потому что это по умолчанию), но я предлагаю вам дважды проверить это.
Конфигурация для просмотра:
http://wiki.nginx.org/HttpProxyModule#proxy_buffering
Это для буферизации ответа единорогов. Вам определенно нужно это, потому что вы не хотите, чтобы единороги занимались отправкой данных медленному клиенту.
Для буферизации запроса от клиента я думаю, что вам нужно посмотреть:
http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size
Я думаю, что все это не может объяснить задержку в 100 мс, но я не знаком со всей вашей системой, поэтому стоит взглянуть на это направление. Кажется, что ваша очередь не вызвана конкуренцией процессора, а какой-то блокировкой ввода-вывода.