очередь запросов на единорога - PullRequest
23 голосов
/ 31 марта 2012

Мы только что перешли с пассажира на единорога, чтобы разместить несколько приложений на рельсах.Все отлично работает, но через New Relic мы замечаем, что запрос находится в очереди между 100 и 300 мс.

Вот график:

enter image description here

Я понятия не имею, где этоотсюда наш единорог конф:

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

Iпопробовал с 8 работниками, это ничего не изменило.

Я также использовал дождевые капли , чтобы посмотреть, что за рабочие единорога были.

Вот скрипт 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)

Как я его запустил:

./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 и имеем средне-инстанс с высоким процессором 1,7 ГБпамяти, 5 вычислительных блоков EC2 (2 виртуальных ядра с 2,5 вычислительными блоками EC2 каждое)

Мы размещаем 4 рельсовых приложения, у этого есть 6 рабочих, у нас одно с 4, одно с 2 и другое с одним.Все они испытывают очереди запросов, так как мы перешли на единорога.Я не знаю, обманывал ли Пассажир, но New Relic не регистрировал очереди запросов, когда мы его использовали.У нас также есть приложение node.js для загрузки файлов, база данных mysql и 2 redis.

EDIT 3:

Мы используем ruby ​​1.9.2p290, nginx1.0.10, единорог 4.2.1 и newrelic_rpm 3.3.3.Завтра я попробую без newrelic и сообщу вам результаты здесь, но для информации, которую мы использовали пассажиром с новой реликвией, той же версией ruby ​​и nginx и не было никаких проблем.

EDIT4:

Я пытался увеличить client_body_buffer_size и proxy_buffers с

client_body_buffer_size 256k;<br> proxy_buffers 8 256k;
Но это не сработало.

РЕДАКТИРОВАТЬ 5:

Мы наконец выяснили ... барабанная дробь ... Победителем стал наш шифр SSL.Когда мы изменили его на RC4, мы увидели, что очередь запросов упала со 100-300 мс до 30-100 мс.

Ответы [ 3 ]

12 голосов
/ 21 марта 2013

Я только что диагностировал похожий новый реликтовый граф как полностью недостаток SSL. Попробуйте выключить его. Мы видим время ожидания очереди 400 мс, которое без SSL сокращается до 20 мс.

Некоторые интересные моменты о том, почему некоторые провайдеры SSL могут работать медленно: http://blog.cloudflare.com/how-cloudflare-is-making-ssl-fast

1 голос
/ 05 апреля 2012

Какую версию ruby, unicorn, nginx (не имеет большого значения, но стоит упомянуть) и newrelic_rpm вы используете?

Кроме того, я бы попробовал запустить базовый перф тест без newrelic. NewRelic анализирует ответ, и в некоторых случаях это может быть медленным из-за проблемы с 'rindex' в ruby ​​pre-1.9.3. Обычно это заметно только тогда, когда ваш ответ очень большой и не содержит тегов body (например, AJAX, JSON и т. Д.). Я видел пример этого, когда 1-мегабайтный ответ AJAX занимал 30 секунд для анализа NewRelic.

0 голосов
/ 15 ноября 2012

Вы уверены, что буферизуете запросы от клиентов в nginx, а затем буферизуете ответы от единорогов перед отправкой их обратно клиентам.Из вашей настройки кажется, что вы делаете (потому что это по умолчанию), но я предлагаю вам дважды проверить это.

Конфигурация для просмотра:

http://wiki.nginx.org/HttpProxyModule#proxy_buffering

Это для буферизации ответа от единорогов.Вам определенно это нужно, потому что вы не хотите, чтобы единороги были заняты отправкой данных медленному клиенту.

Для буферизации запроса от клиента, я думаю, вам нужно посмотреть:

http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size

Я думаю, что все это не может объяснить задержку в 100 мс, но я не знаком со всеми настройками вашей системы, поэтому стоит взглянуть на это направление.Кажется, что ваша очередь вызвана не конфликтом процессора, а какой-то блокировкой ввода-вывода.

...