2016-09-21 4 views
2

Я нахожу интересную проблему, о которой я не уверен в первопричине. У меня есть сервер и два виртуальных хоста A и B с портом на 80 и 81 соответственно. Я пишу простой код PHP на А, который выглядит следующим образомphp curl localhost медленный при одновременных запросах

<?php 

echo "from A server\n"; 

И еще один простой код PHP на сервере B

<?php 

echo "B server:\n"; 

// create curl resource 
$ch = curl_init(); 

// set url 
curl_setopt($ch, CURLOPT_URL, "localhost:81/a.php"); 

//return the transfer as a string 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

// $output contains the output string 
$output = curl_exec($ch); 

// close curl resource to free up system resources 
curl_close($ch); 

echo $output; 

При выполнении параллельных запросов с помощью аЬ, я получаю следующие результаты:

ab -n 10 -c 5 http://192.168.10.173/b.php 
This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking 192.168.10.173 (be patient).....done 


Server Software:  nginx/1.10.0 
Server Hostname:  192.168.10.173 
Server Port:   80 

Document Path:   /b.php 
Document Length:  26 bytes 

Concurrency Level:  5 
Time taken for tests: 2.680 seconds 
Complete requests:  10 
Failed requests:  0 
Total transferred:  1720 bytes 
HTML transferred:  260 bytes 
Requests per second: 3.73 [#/sec] (mean) 
Time per request:  1340.197 [ms] (mean) 
Time per request:  268.039 [ms] (mean, across all concurrent requests) 
Transfer rate:   0.63 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 0 0.1  0  1 
Processing:  2 1339 1408.8 2676 2676 
Waiting:  2 1339 1408.6 2676 2676 
Total:   3 1340 1408.8 2676 2677 

Percentage of the requests served within a certain time (ms) 
    50% 2676 
    66% 2676 
    75% 2676 
    80% 2676 
    90% 2677 
    95% 2677 
    98% 2677 
    99% 2677 
100% 2677 (longest request) 

Но сделать 1000 запросов с уровнем параллелизма 1 очень быстро:

$ ab -n 1000 -c 1 http://192.168.10.173/b.php 
This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking 192.168.10.173 (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Completed 600 requests 
Completed 700 requests 
Completed 800 requests 
Completed 900 requests 
Completed 1000 requests 
Finished 1000 requests 


Server Software:  nginx/1.10.0 
Server Hostname:  192.168.10.173 
Server Port:   80 

Document Path:   /b.php 
Document Length:  26 bytes 

Concurrency Level:  1 
Time taken for tests: 1.659 seconds 
Complete requests:  1000 
Failed requests:  0 
Total transferred:  172000 bytes 
HTML transferred:  26000 bytes 
Requests per second: 602.86 [#/sec] (mean) 
Time per request:  1.659 [ms] (mean) 
Time per request:  1.659 [ms] (mean, across all concurrent requests) 
Transfer rate:   101.26 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 0 0.1  0  1 
Processing:  1 1 10.3  1  201 
Waiting:  1 1 10.3  1  201 
Total:   1 2 10.3  1  201 

Percentage of the requests served within a certain time (ms) 
    50%  1 
    66%  1 
    75%  1 
    80%  1 
    90%  1 
    95%  1 
    98%  1 
    99%  2 
100% 201 (longest request) 

Может ли кто-нибудь объяснить, почему это произошло? Я действительно хочу знать причину. Это проблема скручивания? Он не похож на узкое место в сети или проблему с открытым файлом, так как параллелизм составляет всего 5. Кстати, я также пытаюсь сделать то же самое с guzzlehttp, но результат тот же. Я использую ab на своем ноутбуке, и сервер находится в одной локальной сети. Кроме того, это, безусловно, не имеет ничего общего с пропускной способностью сети, поскольку запросы между хостами A и B выполняются на локальном хосте.


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

<?php 

require 'vendor/autoload.php'; 

use GuzzleHttp\Client; 

$opt = 1; 
$url = 'http://localhost:81/a.php'; 

switch ($opt) { 
    case 1: 
     // create curl resource 
     $ch = curl_init(); 

     // set url 
     curl_setopt($ch, CURLOPT_URL, $url); 

     //return the transfer as a string 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

     // $output contains the output string 
     $output = curl_exec($ch); 

     curl_close($ch); 

     echo $output; 
     break; 
    case 2: 
     $client = new Client(); 
     $response = $client->request('GET', $url); 
     echo $response->getBody(); 
     break; 
    case 3: 
     echo file_get_contents($url); 
     break; 
    default: 
     echo "no opt"; 
} 

echo "app server:\n"; 

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


Я думаю, что найти что-то связанное с этим вопросом, так что я просто опубликовать еще один вопрос concurrent curl could not resolve host. Это может быть основной причиной, но у меня пока нет ответа.


После долгих попыток, я думаю, что это определенно связано с разрешением имени. А вот скрипт, который может выполняться на уровне параллельного 500

<?php 

require 'vendor/autoload.php'; 

use GuzzleHttp\Client; 

$opt = 1; 
$url = 'http://localhost:81/a.php'; 

switch ($opt) { 
    case 1: 
     // create curl resource 
     $ch = curl_init(); 

     // set url 
     curl_setopt($ch, CURLOPT_URL, $url); 

     //return the transfer as a string 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

     curl_setopt($ch, CURLOPT_PROXY, 'localhost'); 

     // $output contains the output string 
     $output = curl_exec($ch); 

     curl_close($ch); 

     echo $output; 
     break; 
    case 2: 
     $client = new Client(); 
     $response = $client->request('GET', $url, ['proxy' => 'localhost']); 
     echo $response->getBody(); 
     break; 
    case 3: 
     echo file_get_contents($url); 
     break; 
    default: 
     echo "no opt"; 
} 

echo "app server:\n"; 

Что действительно имеет значение имеют curl_setopt($ch, CURLOPT_PROXY, 'localhost'); и $response = $client->request('GET', $url, ['proxy' => 'localhost']);. Он говорит curl использовать localhost как прокси.

И вот результат теста аб

ab -n 1000 -c 500 http://192.168.10.173/b.php 
This is ApacheBench, Version 2.3 <$Revision: 1528965 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking 192.168.10.173 (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Completed 600 requests 
Completed 700 requests 
Completed 800 requests 
Completed 900 requests 
Completed 1000 requests 
Finished 1000 requests 


Server Software:  nginx/1.10.0 
Server Hostname:  192.168.10.173 
Server Port:   80 

Document Path:   /b.php 
Document Length:  182 bytes 

Concurrency Level:  500 
Time taken for tests: 0.251 seconds 
Complete requests:  1000 
Failed requests:  184 
    (Connect: 0, Receive: 0, Length: 184, Exceptions: 0) 
Non-2xx responses:  816 
Total transferred:  308960 bytes 
HTML transferred:  150720 bytes 
Requests per second: 3985.59 [#/sec] (mean) 
Time per request:  125.452 [ms] (mean) 
Time per request:  0.251 [ms] (mean, across all concurrent requests) 
Transfer rate:   1202.53 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 6 4.9  5  14 
Processing:  9 38 42.8  22  212 
Waiting:  8 38 42.9  22  212 
Total:   11 44 44.4  31  214 

Percentage of the requests served within a certain time (ms) 
    50%  31 
    66%  37 
    75%  37 
    80%  38 
    90% 122 
    95% 135 
    98% 207 
    99% 211 
100% 214 (longest request) 

Но все-таки, почему разрешения имен не удалось на уровне параллелизма 5, если не используется Localhost в качестве доверенного лица?


Настройка виртуального хоста очень простая и чистая, и почти все в конфигурации по умолчанию. Я не использую iptables на этом сервере, ни я ничего не настраиваю.

server { 
    listen 81 default_server; 
    listen [::]:81 default_server; 

    root /var/www/html; 

    index index.html index.htm index.nginx-debian.html; 

    server_name _; 

    location/{ 
     try_files $uri $uri/ =404; 
    } 

    location ~ \.php$ { 
     include snippets/fastcgi-php.conf; 
     fastcgi_pass unix:/run/php/php7.0-fpm.sock; 
    } 
} 

Найти что-то интересное! Если вы выполните еще один тест ab сразу после первого за 3 секунды. Второй тест ab довольно быстрый.

без использования Localhost в качестве прокси-сервера

ab -n 10 -c 5 http://192.168.10.173/b.php <-- This takes 2.8 seconds to finish. 
ab -n 10 -c 5 http://192.168.10.173/b.php <-- This takes 0.008 seconds only. 

Использование Localhost в качестве прокси-сервера

ab -n 10 -c 5 http://192.168.10.173/b.php <-- This takes 0.006 seconds. 
ab -n 10 -c 5 http://192.168.10.173/b.php <-- This takes 0.006 seconds. 

Я думаю, что это все еще означает, что проблема разрешения имен. Но почему?


Предположение: Nginx не слушает локальный хост: 81

Я попытался добавить listen 127.0.0.1:81; в Nginx, и он не проявляет никакого эффекта.

Обнаружение ошибок при использовании curl proxy, , что не работает! Обновите другие детали позже.


Решенный, не имеющий отношения к прокси-серверу или чему-либо еще. Основной причиной является pm.start_servers в php-fpm's www.conf.

+0

Это радикально изменится, если вы используете другой уровень параллелизма (например, 2) или URL fopen() вместо этого (например, file_get_contents («http: // localhost: 81/a.php»);)? –

+0

@BJBlack at concurrcy = 2,3,4,5, время 0,018 с, 0,87 с, 1,75 с, 2,42 с соответственно. Я подозреваю, что это имеет какое-то отношение к низкоуровневому поведению Linux. – cwhsu

+1

@cwhsu В этом случае вы можете сжать linux в качестве тега – Goose

ответ

0

Хорошо, после стольких дней, пытаясь решить эту проблему, я наконец узнаю, почему. И это не разрешение имен. Я не могу поверить, что для отслеживания основной причины, которая является числом pm.start_servers в php-fpm's www.conf, требуется много дней. Первоначально я установил число pm.start_servers на 3, поэтому тест ab на localhost всегда ухудшается после уровня параллелизма 3. Хотя php-cli не имеет проблемы с ограниченным числом php-процессов, php-cli всегда отлично работает. После увеличения pm.start_servers до 5 результат теста ab выполняется так же быстро, как и php-cli. Если это причина того, что ваш php-fpm медленный, вы также должны подумать об изменении количества pm.min_spare_servers, pm.max_spare_servers, pm.max_children и всех связанных.

Смежные вопросы