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

Nginx Высокая балансировка нагрузки трафика

Последние 3 недели мы тестировали Nginx в качестве баланса нагрузки. В настоящее время нам не удается обработать более 1000 активных запросов и 18 000 активных соединений. Когда мы добираемся до вышеуказанных чисел, Nginx начинает зависать и возвращает коды тайм-аута. Единственный способ получить ответ - резко сократить количество подключений.

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

Мы используем выделенный сервер со следующим HW:

  • INTEL XEON E5620 CPU
  • 16 ГБ ОЗУ
  • 2T SATA HDD
  • Соединение 1 Гбит/с
  • ОС: CentOS 5.8

Нам нужно сбалансировать 7 обратных серверов, работающих под управлением Tomcat6 и обрабатывающих более 2000 запросов в секунду в часы пиковой нагрузки, обрабатывающих запросы HTTP и HTTPS.

Во время работы процессора Nginx потребление составляет около 15%, а используемая оперативная память - около 100 МБ.

Мои вопросы:

  1. Кто-нибудь пытался сбалансировать нагрузку такого типа трафика с помощью nginx?
  2. Как вы думаете, nginx может обрабатывать такой трафик?
  3. Есть ли у вас какие-либо идеи, что может привести к зависанию?
  4. Я что-то упускаю в своих конфигурациях?

Ниже приведены мои конфигурационные файлы:

nginx.conf:

user  nginx;
worker_processes 10;

worker_rlimit_nofile 200000;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  10000;
    use epoll;
    multi_accept on;
}


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;
    access_log off;

    sendfile        on;
    tcp_nopush     on;

    keepalive_timeout  65;
    reset_timedout_connection on;

    gzip  on;
    gzip_comp_level 1;
    include /etc/nginx/conf.d/*.conf;
} 

servers.conf:

#Set the upstream (servers to load balance)
#HTTP stream
upstream adsbar {
  least_conn;
  server xx.xx.xx.34 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.36 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.37 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.39 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.40 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.42 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.43 max_fails=2 fail_timeout=15s;
}      

#HTTPS stream
upstream adsbar-ssl {
  least_conn;
  server xx.xx.xx.34:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.36:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.37:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.39:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.40:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.42:443 max_fails=2 fail_timeout=15s;
  server xx.xx.xx.43:443 max_fails=2 fail_timeout=15s;
}

#HTTP
server {
  listen xxx.xxx.xxx.xxx:8080;
  server_name www.mycompany.com;
  location / {
      proxy_set_header Host $host;
      # So the original HTTP Host header is preserved
      proxy_set_header X-Real-IP $remote_addr;
      # The IP address of the client (which might be a proxy itself)
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://adsbar;
  }
}

#HTTPS
server {
  listen xxx.xxx.xxx.xxx:8443;
  server_name www.mycompany.com;
  ssl on;
  ssl_certificate /etc/pki/tls/certs/mycompany.crt;
  # Path to an SSL certificate;
  ssl_certificate_key /etc/pki/tls/private/mycompany.key;
  # Path to the key for the SSL certificate;
  location / {
      proxy_set_header Host $host;
      # So the original HTTP Host header is preserved
      proxy_set_header X-Real-IP $remote_addr;
      # The IP address of the client (which might be a proxy itself)
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass https://adsbar-ssl;
  }
}

server {
    listen xxx.xxx.xxx.xxx:61709;
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
} 

sysctl.conf:

# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 

0 is disabled, 1 is enabled.  See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 1

# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65536

# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296

fs.file-max = 120000
net.ipv4.ip_conntrack_max = 131072
net.ipv4.tcp_max_syn_backlog = 8196
net.ipv4.tcp_fin_timeout = 25
net.ipv4.tcp_keepalive_time = 3600
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_rmem = 4096 25165824 25165824
net.core.rmem_max = 25165824
net.core.rmem_default = 25165824
net.ipv4.tcp_wmem = 4096 65536 25165824
net.core.wmem_max = 25165824
net.core.wmem_default = 65536
net.core.optmem_max = 25165824
net.core.netdev_max_backlog = 2500
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

Любая помощь, руководство, идеи будут высоко оценены.

4b9b3361

Ответ 1

Вот несколько хороших ссылок:

http://dak1n1.com/blog/12-nginx-performance-tuning

Ошибка сервера: https://serverfault.com/questions/221292/tips-for-maximizing-nginx-requests-sec

Очень хорошо документированная конфигурация из ссылки dak1n1:

# This number should be, at maximum, the number of CPU cores on your system. 
# (since nginx doesn't benefit from more than one worker per CPU.)
worker_processes 24;

# Number of file descriptors used for Nginx. This is set in the OS with 'ulimit -n 200000'
# or using /etc/security/limits.conf
worker_rlimit_nofile 200000;


# only log critical errors
error_log /var/log/nginx/error.log crit


# Determines how many clients will be served by each worker process.
# (Max clients = worker_connections * worker_processes)
# "Max clients" is also limited by the number of socket connections available on the system (~64k)
worker_connections 4000;


# essential for linux, optmized to serve many clients with each thread
use epoll;


# Accept as many connections as possible, after nginx gets notification about a new connection.
# May flood worker_connections, if that option is set too low.
multi_accept on;


# Caches information about open FDs, freqently accessed files.
# Changing this setting, in my environment, brought performance up from 560k req/sec, to 904k req/sec.
# I recommend using some varient of these options, though not the specific values listed below.
open_file_cache max=200000 inactive=20s; 
open_file_cache_valid 30s; 
open_file_cache_min_uses 2;
open_file_cache_errors on;


# Buffer log writes to speed up IO, or disable them altogether
#access_log /var/log/nginx/access.log main buffer=16k;
access_log off;


# Sendfile copies data between one FD and other from within the kernel. 
# More efficient than read() + write(), since the requires transferring data to and from the user space.
sendfile on; 


# Tcp_nopush causes nginx to attempt to send its HTTP response head in one packet, 
# instead of using partial frames. This is useful for prepending headers before calling sendfile, 
# or for throughput optimization.
tcp_nopush on;


# don't buffer data-sends (disable Nagle algorithm). Good for sending frequent small bursts of data in real time.
tcp_nodelay on; 


# Timeout for keep-alive connections. Server will close connections after this time.
keepalive_timeout 30;


# Number of requests a client can make over the keep-alive connection. This is set high for testing.
keepalive_requests 100000;


# allow the server to close the connection after a client stops responding. Frees up socket-associated memory.
reset_timedout_connection on;


# send the client a "request timed out" if the body is not loaded by this time. Default 60.
client_body_timeout 10;


# If the client stops reading data, free up the stale client connection after this much time. Default 60.
send_timeout 2;


# Compression. Reduces the amount of data that needs to be transferred over the network
gzip on;
gzip_min_length 10240;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
gzip_disable "MSIE [1-6]\.";

Также более подробная информация о настройке системы Linux для sysctl.conf:

# Increase system IP port limits to allow for more connections

net.ipv4.ip_local_port_range = 2000 65000


net.ipv4.tcp_window_scaling = 1


# number of packets to keep in backlog before the kernel starts dropping them 
net.ipv4.tcp_max_syn_backlog = 3240000


# increase socket listen backlog
net.core.somaxconn = 3240000
net.ipv4.tcp_max_tw_buckets = 1440000


# Increase TCP buffer sizes
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_congestion_control = cubic

Ответ 2

nginx должен иметь возможность обрабатывать более 1000 req/s (я получаю около 2800 req/s в nginx при игре на моем дешевом ноутбуке с jmeter, используя один и половину двух ядер).

Вы используете epoll, который является оптимальным вариантом в текущем ядре Linux, насколько я его понимаю.

Вы отключили acces_log, поэтому ваш IO-диск не должен быть узким местом (обратите внимание: вы также можете установить режим access_log в буферный режим с большим буфером, где он записывает только после каждого x kb, что позволяет избежать диск io постоянно забивается, но сохраняет журналы для анализа)

Я понимаю, что для максимизации производительности nginx вы обычно устанавливаете количество рабочих_процессов, равное числу ядер/процессоров, а затем увеличивайте количество рабочих_соединений, чтобы разрешать больше параллельных подключений (вместе с количеством открытых файлов os предел). Тем не менее в данных, которые вы указали выше, у вас есть процессор quadcore с 10 рабочими процессами с 10-килограммовыми соединениями, разрешенными каждый. Следовательно, на стороне nginx я бы попробовал что-то вроде:

worker_processes 4;
worker_rlimit_nofile 999999;
events {
  worker_connections 32768;
  use epoll;
  multi_accept on;
}

На стороне ядра я бы настроил tcp для чтения и записи буферов по-разному, вам нужен небольшой минимум, малый размер по умолчанию и большой макс.

Вы уже подняли эфемерный диапазон портов.

Я бы увеличил число открытых файлов, потому что у вас будет много открытых сокетов.

Что дает следующие строки для добавления/изменения в /etc/sysctl.conf

net.ipv4.tcp_rmem = 4096 4096 25165824                                
net.ipv4.tcp_wmem = 4096 4096 25165824
fs.file-max=999999

Надеюсь, что это поможет.

Ответ 3

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

hash $remote_addr consistent;

и нашел услугу намного быстрее.