Подтвердить что ты не робот

Очередь запросов единорога

Мы просто перешли от пассажира к единорогу, чтобы разместить несколько рельсовых приложений. Все работает отлично, но мы замечаем через 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 мс.

4b9b3361

Ответ 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 мс, но я не знаком со всей вашей системой, поэтому стоит взглянуть на это направление. Кажется, что ваша очередь не вызвана конкуренцией процессора, а какой-то блокировкой ввода-вывода.