TCP, HTTP и многопоточность - PullRequest
6 голосов
/ 09 марта 2010

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

См. В нижней части этого поста для моих результатов

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

Используется неблокирующее соединение с начальным тайм-аутом для каждого файла, равным 10 секундам, который удваивается после каждого тайм-аута и повторяется. Он также кэширует IP-адреса, поэтому каждый поток должен выполнить поиск DNS только один раз.

Общий объем загруженных данных составляет 2271122 байта в 1316 файлах через соединение 2,5 Мбит с http://hubblesite.org/gallery/album/entire/npp/all/hires/true/. Эскизы размещены компанией, которая утверждает, что специализируется на малой задержке для приложений с высокой пропускной способностью.

Время стен:

1 поток занимает 4:48 - 0 таймаутов
2 темы занимает 2:38 - 0 таймаутов
5 потоков занимает 2:22 - 20 таймаутов
10 потоков занимают 2:27 - 40 таймаутов
50 потоков занимают 2:27 - 170 таймаутов

В худшем случае (50 потоков) клиент использует менее 2 секунд процессорного времени.

средний размер файла 1.7k
среднее значение rt 100 мс (измеряется с помощью ping)
средняя скорость процессора / изображение 1 мс

Самая высокая средняя скорость загрузки составляет 5 потоков при общей скорости около 15 КБ / с.

Сервер действительно имеет довольно низкую задержку, поскольку для получения каждого изображения требуется всего 218 мс, а это означает, что в среднем сервер обрабатывает каждый запрос:

0 cli отправляет syn
50 ср.кв.син
50 срв отправляет syn + ack
100 кон конн / кл отправляет
150 srv recv's get
168 srv читает файл, отправляет данные, закрывает звонки
218 заголовков rec recv HTTP + полный файл в 2 сегмента MSS == 1448

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

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

Тайм-ауты, похоже, начинаются после примерно 900 - 1000 успешных подключений, будь то 5 или 50 потоков, что, я полагаю, является своего рода порогом регулирования на сервере, но я ожидаю, что 10 потоков все равно будут значительно быстрее, чем 2.

Я что-то здесь упускаю?

EDIT-1

Просто для сравнения я установил расширение DownThemAll Firefox и загрузил изображения, используя его. Я установил 4 одновременных соединения с 10-секундным таймаутом. DTM потребовалось около 3 минут, чтобы загрузить все файлы + записать их на диск, и он также начал испытывать таймауты после примерно 900 соединений.

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

Я также очистил кэш Firefox и нажал перезагрузить. 40 секунд, чтобы перезагрузить страницу и все изображения. Это казалось слишком быстрым - может быть, Firefox держал их в кеше памяти, который не был очищен? Итак, я открыл Opera, и это также заняло около 40 секунд. Я предполагаю, что они намного быстрее, потому что они должны использовать конвейерную передачу HTTP / 1.1?

И ответ есть! ??

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

При работе в 5 потоках нетранслируемая версия извлекает первые 1026 изображений за 77 секунд, но для извлечения оставшихся 290 изображений требуется еще 65 секунд. Это в значительной степени подтверждает теорию Мэтта о том, что мой клиент получил удар по событию SYN FLOOD, в результате которого сервер перестал отвечать на мои попытки подключения в течение короткого периода времени. Тем не менее, это только часть проблемы, так как 77 секунд все еще очень медленно для 5 потоков, чтобы получить 1026 изображений; Если вы удалите проблему SYN FLOOD, все файлы займут около 99 секунд. Поэтому, основываясь на небольшом исследовании и некоторых tcpdump, кажется, что другая часть проблемы - это задержка и накладные расходы на установку соединения.

Здесь мы возвращаемся к вопросу поиска «сладкого пятна» или оптимального количества потоков. Я изменил клиент для реализации HTTP / 1.1 Pipelining и обнаружил, что оптимальное количество потоков в этом случае составляет от 15 до 20. Например:

1 поток занимает 2:37 - 0 таймаутов
2 потока занимает 1:22 - 0 таймаутов
5 потоков занимает 0:34 - 0 таймаутов
10 потоков занимают 0:20 - 0 таймаутов
11 потоков занимают 0:19 - 0 таймаутов
15 потоков занимают 0:16 - 0 таймаутов

Есть четыре фактора, которые повлиять на это; задержка / RTT, максимальная сквозная пропускная способность, размер буфера recv и размер загружаемых файлов изображений. Смотрите этот сайт для обсуждение того, как размер буфера приема и задержка RTT влияют на доступность ширина полосы .

В дополнение к вышесказанному, средний размер файла влияет на максимальный размер соединения Скорость передачи. Каждый раз, когда вы отправляете запрос GET, вы создаете пустой пробел в Ваш канал передачи, который является размером соединения RTT. Например, если вы максимально возможная скорость передачи данных (размер буфера recv / RTT) составляет 2,5 Мбит и ваш RTT составляет 100 мс, тогда каждый GET-запрос имеет минимальный разрыв в 32 КБ в вашем труба. Для большого среднего размера изображения 320 кБ это составляет 10% накладных расходов за файл, эффективно уменьшая доступную пропускную способность до 2,25 Мбит. Тем не мение, для небольшого среднего размера файла 3,2 КБ накладные расходы увеличиваются до 1000% и доступная пропускная способность уменьшается до 232 кбит / с - около 29 кБ.

Таким образом, чтобы найти оптимальное количество потоков:

Размер зазора = MPTR * RTT
MPTR / (размер MPTR / Gap + размер файла AVG) * размер файла AVG)

Для моего вышеописанного сценария это дает мне оптимальное количество потоков из 11 потоков, что очень близко к моим реальным результатам.

Если фактическая скорость соединения ниже теоретической MPTR, тогда вместо этого следует использовать в расчете.

1 Ответ

7 голосов
/ 10 марта 2010

Пожалуйста, исправьте меня, это резюме неверно:

  • Ваш multi-threaded клиент запустит поток, который подключается к серверу и выдаст только один HTTP GET, после чего этот поток закроется.
  • Когда вы говорите 1, 2, 5, 10, 50 потоков, вы просто указываете, сколько параллельных потоков вы разрешаете, каждый поток обрабатывает только один запрос
  • Вашему клиенту требуется от 2 до 5 минут для загрузки более 1000 изображений
  • Firefox и Opera загрузят эквивалентный набор данных за 40 секунд

Я полагаю, что сервер ограничивает скорость http-подключений либо самим демоном веб-сервера, либо локальным межсетевым экраном сервера, либо, скорее всего, выделенным межсетевым экраном.

Вы на самом деле злоупотребляете веб-службой, не используя повторно HTTP-соединения для более чем одного запроса, и истечение времени ожидания происходит из-за того, что ваш SYN FLOOD зажат.

Возможно, Firefox и Opera используют от 4 до 8 соединений для загрузки всех файлов.

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

...