2013-03-18 19 views
7

Mam aplikację Rails (3.2), która działa na platformie nginx i jednorożec na platformie chmurowej. "Skrzynka" działa na Ubuntu 12.04.Błędy błędnej bramy przy obciążeniu nginx + Unicorn (aplikacja Rails 3)

Gdy obciążenie systemu jest na poziomie około 70% lub powyżej, nginx nagle (i pozornie przypadkowo) rozpoczyna rzucanie 502 Bad błędy bramy; gdy ładunek jest mniejszy, nie ma nic podobnego. Eksperymentowałem z różnymi rdzeniami (4, 6, 10 - mogę "zmieniać sprzęt" na platformie chmurowej), a sytuacja jest zawsze taka sama. (Obciążenie procesora jest podobne do obciążenia systemu, użytkownik ma 55%, reszta jest systemowa i skradziona, z dużą ilością wolnej pamięci, bez zamiany).

502 zwykle występują w partiach, ale nie zawsze.

(biegnę jeden jednorożec pracownika na jeden rdzeń, oraz jeden lub dwa nginx pracowników. Zobacz odpowiednich częściach configs poniżej podczas jazdy na 10 rdzeni).

ja naprawdę nie wiem, jak śledzić przyczyny tych błędów. Podejrzewam, że może to mieć coś wspólnego z robotami jednorożca, którzy nie są w stanie służyć (z czasem?), Ale wygląda to dziwnie, ponieważ nie wydają się nasycać procesora i nie widzę powodu, dla którego mieliby poczekać na IO (ale ja don nie wiem, jak się tego upewnić).

Czy możesz mi pomóc, jak znaleźć przyczynę?


Unicorn config (unicorn.rb):

worker_processes 10 
working_directory "/var/www/app/current" 
listen "/var/www/app/current/tmp/sockets/unicorn.sock", :backlog => 64 
listen 2007, :tcp_nopush => true 
timeout 90 
pid "/var/www/app/current/tmp/pids/unicorn.pid" 
stderr_path "/var/www/app/shared/log/unicorn.stderr.log" 
stdout_path "/var/www/app/shared/log/unicorn.stdout.log" 
preload_app true 
GC.respond_to?(:copy_on_write_friendly=) and 
    GC.copy_on_write_friendly = true 
check_client_connection false 

before_fork do |server, worker| 
    ... I believe the stuff here is irrelevant ... 
end 
after_fork do |server, worker| 
    ... I believe the stuff here is irrelevant ... 
end 

A ngnix config:

/etc/nginx/nginx.conf:

worker_processes 2; 
worker_rlimit_nofile 2048; 
user www-data www-admin; 
pid /var/run/nginx.pid; 
error_log /var/log/nginx/nginx.error.log info; 

events { 
    worker_connections 2048; 
    accept_mutex on; # "on" if nginx worker_processes > 1 
    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"'; 
    access_log /var/log/nginx/access.log main; 
    # optimialization efforts 
    client_max_body_size  2m; 
    client_body_buffer_size  128k; 
    client_header_buffer_size 4k; 
    large_client_header_buffers 10 4k; # one for each core or one for each unicorn worker? 
    client_body_temp_path  /tmp/nginx/client_body_temp; 

    include /etc/nginx/conf.d/*.conf; 
} 

/etc/nginx/conf.d/app.conf:

sendfile on; 
tcp_nopush on; 
tcp_nodelay off; 
gzip on; 
gzip_http_version 1.0; 
gzip_proxied any; 
gzip_min_length 500; 
gzip_disable "MSIE [1-6]\."; 
gzip_types text/plain text/css text/javascript application/x-javascript; 

upstream app_server { 
    # fail_timeout=0 means we always retry an upstream even if it failed 
    # to return a good HTTP response (in case the Unicorn master nukes a 
    # single worker for timing out). 
    server unix:/var/www/app/current/tmp/sockets/unicorn.sock fail_timeout=0; 
} 

server { 
    listen 80 default deferred; 
    server_name _; 
    client_max_body_size 1G; 
    keepalive_timeout 5; 
    root /var/www/app/current/public; 

    location ~ "^/assets/.*" { 
     ... 
    } 

    # Prefer to serve static files directly from nginx to avoid unnecessary 
    # data copies from the application server. 
    try_files $uri/index.html $uri.html $uri @app; 

    location @app { 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Host $http_host; 
    proxy_redirect off; 

    proxy_pass http://app_server; 

    proxy_connect_timeout  90; 
    proxy_send_timeout   90; 
    proxy_read_timeout   90; 

    proxy_buffer_size   128k; 
    proxy_buffers    10 256k; # one per core or one per unicorn worker? 
    proxy_busy_buffers_size 256k; 
    proxy_temp_file_write_size 256k; 
    proxy_max_temp_file_size 512k; 
    proxy_temp_path   /mnt/data/tmp/nginx/proxy_temp; 

    open_file_cache max=1000 inactive=20s; 
    open_file_cache_valid 30s; 
    open_file_cache_min_uses 2; 
    open_file_cache_errors on; 
    } 
} 

Odpowiedz

21

Po wyszukiwaniu wyrażeń w dzienniku błędów nginx okazało się, że jest to znany problem, który nie ma nic wspólnego z nginxem, niewiele wspólnego z jednorożcem i jest zakorzeniony w ustawieniach systemu operacyjnego (Linux).

Głównym problemem jest to, że zaległości w gniazdach są za krótkie. Istnieją różne rozważania, jak dużo to powinno być (czy chcesz wykryć awarię elementu klastra JAK NAJSZYBCIEJ, czy też aplikacja powinna nadal przekraczać limity obciążenia). Ale w każdym razie listen:backlog potrzebuje ulepszenia.

Znalazłem, że w moim przypadku wystarczyło listen ... :backlog => 2048. (Nie eksperymentowałem zbyt wiele, chociaż jest dobry hack do zrobienia tego, jeśli chcesz, mając dwa gniazda do komunikacji między nginxem i jednorożcem z różnymi zaległościami i dłuższym tworzeniem kopii zapasowych, następnie zobacz w dzienniku nginx, jak często nieudana kolejka nie działa .) Należy pamiętać, że nie jest to wynik naukowej kalkulacji i YMMV.

Zauważ jednak, że wiele systemów operacyjnych (większość dystrybucji Linuksa, w tym Ubuntu 12.04) ma znacznie niższe domyślne limity na poziomie gniazd na backlogach (nawet 128).

można zmienić limity OS następująco (jako root):

sysctl -w net.core.somaxconn=2048 
sysctl -w net.core.netdev_max_backlog=2048 

Dodaj je do /etc/sysctl.conf dokonać zmiany na stałe. (/etc/sysctl.conf mogą być przeładowane bez restartu z sysctl -p.)

Istnieje wspomina, że ​​być może trzeba będzie zwiększyć maksymalną liczbę plików, które mogą być otwierane za pomocą procesu (także użyć ulimit -n i /etc/security/limits.conf dla trwałości). Zrobiłem to już z innych powodów, więc nie wiem, czy to robi różnicę czy nie.

+0

Doskonale! Dzięki. –

+0

Dziękuję fastcatch! Zastosowano tę poprawkę. Nie zweryfikowałem jeszcze, czy poprawiono przejściowe błędy nieprawidłowej bramy. – amolk

Powiązane problemy