Как создать много (я имею в виду много) сокетов в Linux? - PullRequest
6 голосов
/ 18 апреля 2009

Я пытался создать простую программу на разных языках (C #, Java, C ++, PHP) для подключения к серверу, и все вели себя одинаково. Поэтому я считаю, что эта проблема скорее относится к уровню ОС.

По сути, я хочу, чтобы программа подключилась к серверу через сокет TCP, отправила 1 байт и затем закрыла сокет. Это необходимо делать тысячи раз в секунду и поддерживать в течение определенного периода времени. Это для целей сравнительного анализа сервера.

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

Теперь эта проблема знакома с серверами, такими как Apache, где утилиты (например, ab / siege) рекомендуют тестировать Apache с использованием протокола keep-alive. Т.е. создать небольшое количество TCP-соединений, но сделать несколько запросов через них для целей тестирования. Однако в нашем случае это невозможно, поскольку наш собственный сервер не обслуживает HTTP и не поддерживает модель поддержки активности HTTP 1.1.

Так как же этого достичь? Я проверил следующие ограничения

  1. ulimit установлен на очень большое число
  2. TCP TIME_WAIT устраняется установкой /proc/sys/net/ipv4/tcp_rw_recycle и /proc/sys/net/ipv4/tcp_rw_reuse на 1. (Я действительно подтвердил с netstat нет TIME_WAIT сокетов)
  3. Это не связано с ограничениями на количество потоков / процессов. Я попытался перезапустить мое клиентское приложение, и это то же самое. Как только ОС откажется от новых сокетов, ничто не поможет.

PS. Это НЕ ограничение на стороне сервера. Мы проверили это, купив другой ящик и запустив на нем тот же код клиента, когда первый клиентский ящик отказался создавать новые сокеты. Сервер справился с этим нормально. Мы не хотим покупать 5-10 коробок и вращаться между ними, чтобы преодолеть эту проблему.

ОС: Fedora 10 Linux 2.6.24-23-xen # 1 SMP

Ответы [ 6 ]

9 голосов
/ 18 апреля 2009

Старая шутка: Человек идет к доктору, говорит: «Доктор, мне больно, когда я делаю это », поворачивая руку в странном положении.

Доктор отвечает: «Ну, не делай это!»

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

Итак, что вы действительно пытаетесь измерить? Что вы действительно пытаетесь сделать ? Если вы действительно пытаетесь отправить один байт за раз - не дай бог, - хотя бы подумайте об использовании udp; Там нет ужасной настройки / демонтажа. Это все еще чрезвычайно неэффективно по сравнению с издержками - даже пакет UDP требует примерно 20 байтов кадрирования - но это лучше.

7 голосов
/ 18 апреля 2009

Взгляните на статью Ричарда Джонса, Приложение для кометы на миллион пользователей с Mochiweb, часть 3 . Речь идет о реализации приложения Comet в Erlang, но в разделе «Повышение его до 1 миллиона» описывается, как он провел тестирование своего сервера; он открывается заявлением «Создание миллиона tcp-соединений с одного хоста нетривиально». Это должно дать вам некоторое представление о том, для чего вы.

5 голосов
/ 18 апреля 2009

Вы пытались установить флаг SO_REUSEADDR на сокете?

2 голосов
/ 18 апреля 2009

Возможно ли, что вы исчерпали порты? Вы получаете только 5000 - 1024 порта, если не хотите вызывать bind () в цикле для поиска следующего свободного порта.

bind () с 0 для порта возвращает свободный порт в диапазоне 1024-5000. bind () с указанным портом получает этот порт, если он доступен.

int bindnextport(int s, struct sockaddr sa)  
{  
   static int nextport = 1025;  
   int lastport;  
   lastport = nextport;  
   do {  
      sa.sa_data[0] = nextport >> 8;  
      sa.sa_data[1] = nextport & 255;  
      if (!bind(s, &sa, sizeof(sa))  
         return 0;  
      ++nextport;  
      if (nextport >= 65536) nextport = 1024;  
   } while (lastport != nextport);  
   return 1;  
}
1 голос
/ 18 апреля 2009

http-сервер nginx заявляет, что он может поддерживать 10 000 неактивных HTTP-соединений поддержки активности Вы могли бы взглянуть на то, как они делают это .

1 голос
/ 18 апреля 2009

Подключение и отправка 1 байта не является эталоном ничего, кроме, возможно, самого протокола TCP. Как сказал выше Чарли Мартин, большую часть времени тратится на подключение, а затем на отключение розетки.

Я понимаю, что вы ХОТИТЕ оценить, но действительно ли это хорошее представление о том, что делает ваше приложение? Вы действительно собираетесь устанавливать соединение только для отправки 1 байта?

...