Обратный прокси-сервер nginx значительно увеличивает задержку в худшем случае

(редактировать: частично понял и обойти, см. комментарий)

У меня есть установка с nginx, действующим в качестве обратного прокси-сервера перед сервером приложений CherryPy. Я использую ab для сравнения производительности, проходящей через nginx, и нет, и отмечаю, что в первом случае производительность намного хуже:

$ ab -n 200 -c 10 'http://localhost/noop'
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests


Server Software:        nginx
Server Hostname:        localhost
Server Port:            80

Document Path:          /noop
Document Length:        0 bytes

Concurrency Level:      10
Time taken for tests:   3.145 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      29600 bytes
HTML transferred:       0 bytes
Requests per second:    63.60 [#/sec] (mean)
Time per request:       157.243 [ms] (mean)
Time per request:       15.724 [ms] (mean, across all concurrent requests)
Transfer rate:          9.19 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     5   48 211.7     31    3007
Waiting:        5   48 211.7     31    3007
Total:          5   48 211.7     31    3007

Percentage of the requests served within a certain time (ms)
  50%     31
  66%     36
  75%     39
  80%     41
  90%     46
  95%     51
  98%     77
  99%    252
 100%   3007 (longest request)
$ ab -n 200 -c 10 'http://localhost:8080/noop'
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests


Server Software:        CherryPy/3.2.0
Server Hostname:        localhost
Server Port:            8080

Document Path:          /noop
Document Length:        0 bytes

Concurrency Level:      10
Time taken for tests:   0.564 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      27600 bytes
HTML transferred:       0 bytes
Requests per second:    354.58 [#/sec] (mean)
Time per request:       28.202 [ms] (mean)
Time per request:       2.820 [ms] (mean, across all concurrent requests)
Transfer rate:          47.79 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.7      0      11
Processing:     6   26  23.5     24     248
Waiting:        3   25  23.6     23     248
Total:          6   26  23.4     24     248

Percentage of the requests served within a certain time (ms)
  50%     24
  66%     27
  75%     29
  80%     31
  90%     34
  95%     40
  98%     51
  99%    234
 100%    248 (longest request)

Что может быть причиной этого? Единственное, о чем я могу думать, это то, что nginx отправляет запросы на сервер в другом порядке, чем они поступили, но это кажется неправдоподобным.

Машина является экземпляром EC2 c1.medium с 2 ядрами, CherryPy использует пул потоков с 10 потоками, а nginx имеет worker_connections = 1024.

ОБНОВЛЕНИЕ: Два более запутанных заключения:

  • При заданном параллельном режиме отправка большего количества запросов повышает производительность. При параллельности 40 и 40 запросов я получаю среднее время 3 с и максимум 10,5 с; при параллельности 40 и 200 запросов я получаю медиану 38 мс (!) и максимум 7,5 с. На самом деле общее время меньше на 200 запросов! (6,5 с против 7,5 с для 40). Это все повторяется.
  • Мониторинг обоих рабочих процессов nginx с помощью strace значительно улучшает их производительность, например, в среднем от 3 до 77 мс, без заметного изменения его поведения. (Я протестировал нетривиальный вызов API и подтвердил, что strace не меняет ответ, а также все эти наблюдения за производительностью, которые все еще выполняются.) Это также можно повторить.

2 ответа

Решение

3 секунды худшего случая в вашем первом ab запуск выглядит как потеря пакета. Вероятно, это результат неправильной настройки буферов / ресурсов, некоторые возможные причины в произвольном порядке:

  • Слишком маленькая очередь прослушивания в бэкэнде, приводящая к случайным переполнениям очереди прослушивания (в этом случае Linux обычно настроен так, чтобы просто отбрасывать пакет SYN, что делает его неотличимым от потери пакета; см. netstat -s | grep listen выяснить, если это проблема).
  • Statefull firewall на localhost приближается к своему пределу по количеству состояний и отбрасывает некоторые случайные SYN-пакеты из-за этого.
  • В системе отсутствуют сокеты / локальные порты из-за сокетов в состоянии TIME_WAIT, посмотрите этот вопрос, если вы используете Linux.

Вы должны тщательно изучить свою ОС, чтобы выяснить причину и соответственно настроить свою ОС. Вы также можете следовать некоторым инструкциям по настройке сетевой подсистемы для вашей ОС. Обратите внимание, что EC2 может быть немного конкретным здесь, так как были сообщения об очень ограниченной производительности сети на экземплярах EC2.

С точки зрения nginx любое решение будет более или менее неправильным (поскольку проблема не в nginx, а в ОС, которая не справляется с нагрузкой и отбрасывает пакеты). Тем не менее, вы можете попробовать некоторые приемы, чтобы уменьшить нагрузку на сетевую подсистему ОС:

  • Настройте keepalive-соединения с бэкэндом.
  • Сконфигурируйте backend для прослушивания сокета домена unix (если ваш backend поддерживает его) и сконфигурируйте nginx для запросов прокси к нему.

NGINX использует HTTP/1.0 для внутренних подключений и по умолчанию не имеет keepalive (см. Ссылку в сообщении Maxim для поддержки активности backend), так что это означает создание нового внутреннего соединения для каждого запроса, что несколько увеличивает задержку. Вероятно, у вас также должно быть больше рабочих процессов, 2* число ядер ЦП, минимум 5. Если у вас более 10 одновременных запросов, вам также может понадобиться больше потоков в CherryPy.

Другие вопросы по тегам