stop start rails ruby-on-rails nginx passenger unicorn

ruby-on-rails - start - phusion passenger rails



cola de solicitud de unicornio (3)

Acabamos de migrar de pasajero a unicornio para alojar algunas aplicaciones de rieles. Todo funciona bien, pero notamos a través de New Relic que la solicitud está en cola entre 100 y 300 ms.

Aquí está el gráfico:

No tengo idea de dónde viene esto de aquí está nuestra confesión de unicornio:

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

nuestro 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; }

y nuestra aplicación específica 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; }

No estamos bajo mucha carga, por lo que no entiendo por qué las solicitudes están atrapadas en la cola. Como se especifica en la confesión de unicornio, tenemos 6 trabajadores de unicornio.

¿Alguna idea de dónde podría venir esto?

Aclamaciones

EDITAR:

Promedio de solicitudes por minuto: alrededor de 15 la mayoría de las veces, más de 300 en peeks pero no experimentamos uno desde la migración.
Promedio de carga de CPU: 0.2-0.3

Intenté con 8 trabajadores, no cambió nada.

También usé raindrops de raindrops para ver qué hacían los trabajadores del unicornio.

Aquí está el script de 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)

Cómo lo lancé:

./linux-tcp-listener-stats.rb -d 0.1 /var/run/engineyard/unicorn_actor.sock

Por lo tanto, básicamente comprueba cada 1 / 10s si hay solicitudes en la cola y si hay salidas:

el zócalo | la cantidad de solicitudes que se procesan | el número de solicitudes en la cola

Aquí hay una esencia del resultado:

https://gist.github.com/f9c9e5209fbbfc611cb1

EDIT2:

Traté de reducir el número de trabajadores de nginx a uno anoche, pero no cambió nada.

Para obtener información, estamos alojados en Engine Yard y tenemos una instancia media de alta CPU de 1,7 GB de memoria, 5 unidades informáticas EC2 (2 núcleos virtuales con 2,5 unidades informáticas EC2)

Tenemos 4 aplicaciones de rieles, esta tiene 6 trabajadores, tenemos uno con 4, uno con 2 y otro con uno. Todos están experimentando colas de solicitudes desde que migramos al unicornio. No sé si Passenger estaba engañando, pero New Relic no registró ninguna cola de solicitud cuando la estábamos usando. También tenemos una aplicación node.js que maneja cargas de archivos, una base de datos mysql y 2 redis.

EDIT 3:

Estamos usando ruby ​​1.9.2p290, nginx 1.0.10, unicorn 4.2.1 y newrelic_rpm 3.3.3. Intentaré sin newrelic mañana y le dejaré saber los resultados aquí, pero para la información que usamos pasajeros con nueva reliquia, la misma versión de ruby ​​y nginx y no tuve ningún problema.

EDIT 4:

Traté de aumentar el client_body_buffer_size y proxy_buffers con

client_body_buffer_size 256k;
proxy_buffers 8 256k;

Pero no funcionó.

EDIT 5:

Finalmente lo descubrimos ... drumroll ... El ganador fue nuestro cifrado SSL. Cuando lo cambiamos a RC4, vimos que la cola de peticiones caía de 100 a 300 ms a 30 a 100 ms.


¿Está seguro de que está almacenando en búfer las solicitudes de los clientes en nginx y luego almacenando en búfer las respuestas de los unicornios antes de enviarlos de vuelta a los clientes? Desde su configuración parece que lo hace (porque esto es por defecto), pero le sugiero que lo compruebe dos veces.

La configuración para mirar es:

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

Esto es para amortiguar la respuesta de los unicornios. Definitivamente lo necesita porque no quiere mantener ocupados a los unicornios enviando datos a un cliente lento.

Para el almacenamiento en búfer de la solicitud del cliente, creo que debe observar:

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

Creo que todo esto no puede explicar una demora de 100 ms, pero no estoy familiarizado con toda la configuración del sistema, por lo que vale la pena echarle un vistazo a esta dirección. Parece que tus colas no son causadas por una contención de CPU, sino por algún tipo de bloqueo de IO.


¿Qué versión de ruby, unicornio, nginx (no debería importar mucho pero vale la pena mencionar) y newrelic_rpm estás usando?

Además, intentaría ejecutar una prueba de perf de línea base sin newrelic. NewRelic analiza la respuesta y hay casos en que esto puede ser lento debido al problema con ''rindex'' en ruby ​​pre-1.9.3. Esto generalmente solo se nota cuando su respuesta es muy grande y no contiene etiquetas de "cuerpo" (por ejemplo, AJAX, JSON, etc.). Vi un ejemplo de esto donde una respuesta AJAX de 1MB tardaba 30 segundos en analizar NewRelic.


Acabo de diagnosticar un nuevo gráfico reliquia similar al que es totalmente culpa de SSL. Intenta apagarlo. Estamos viendo un tiempo de espera de solicitud de 400 ms, que se reduce a 20 ms sin SSL.

Algunos puntos interesantes sobre por qué algunos proveedores de SSL pueden ser lentos: http://blog.cloudflare.com/how-cloudflare-is-making-ssl-fast