Нагрузочное тестирование UDP: Как вы моделируете много клиентов UDP? - PullRequest
3 голосов
/ 15 февраля 2011

Я разрабатываю инструмент для проведения нагрузочного тестирования на сервере UDP (с использованием C # /. NET 4.0, работающего на NT 6.x , хотя это менее актуально).Сервер общается с десятками тысяч клиентов, где связь между каждым клиентом очень низкая и редко встречается.Все сообщения выполняются по схеме «запрос-ответ», когда одна из сторон инициирует связь с другой стороной, которая затем отвечает.Когда серверу необходимо что-то отправить клиенту, он ищет последнюю известную конечную точку (IP + порт) клиента и отправляет пакет UDP, а также ожидает ответа на один известный порт, который используется для получения сообщений от всехклиентов.Когда клиент инициирует связь, он уже знает конечную точку сервера и просто отправляет пакет с временного порта и ожидает ответа на тот же порт.Один и тот же эфемерный порт используется для жизни клиента.

Конструкция инструмента нагрузочного тестирования довольно проста;подражать поведению, состоянию и принятию решений каждым клиентом, до низкой, но достаточной сложности.Поскольку связь с каждым клиентом носит случайный характер (каждые несколько секунд), а объем обработки, требуемый для каждого сеанса связи, минимален, наилучший подход, который я могу придумать, - это использовать один поток с одним сокетом для выполнения всего сеанса связи.для большого количества смоделированных клиентов, которые, скорее всего, все еще не будут поддерживать поток полностью занятым и насыщенным сокетом.К сожалению, с этим подходом я столкнулся с двумя проблемами, возникающими из-за того, что каждый клиент отправляет и получает данные со своего собственного порта:

  1. Сокет будет разрешать отправку UDP-пакета только с эфемерного, выделенного системойпорт или определенный порт, к которому привязан сокет.
  2. Сокет будет принимать пакеты UDP только от порта, к которому он привязан.

Один сокет на клиента

Эти два ограничения, по-видимому, означают, что я должен создать сокет для каждого клиента, поскольку UDP-пакет должен исходить из определенного порта, и на этот порт будет отправлен ответ.Итак, первое возможное решение - сделать это, создать сокет для симулируемого клиента.Допустим, мы моделируем 30 000 клиентов на одной машине:

  1. Возможно ли даже создание 30 000 сокетов?Это лучшая практика?Это исполнитель?Позволит ли Windows даже связать 30 000 сокетов с 30 000 различных портов?
  2. Как проверить через 30 000 клиентских сокетов, отправлены ли какие-либо данные сервером?Периодически ли я опрашиваю все сокеты, чтобы узнать, были ли получены какие-либо данные?Есть ли способ подождать на всех 30 000 сокетов и получить первый пакет, который поступит на любой из них?
  3. Какие ресурсы выделяет операционная система для каждого сокета?Каковы ограничения каждого из этих ресурсов и каковы последствия их достижения?

Один сокет для всех клиентов

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

  1. Первая проблема, связанная с отправкой UDP-пакета из порта, отличного от порта Socket, разрешима.Он включает в себя создание необработанного сокета и создание UDP-заголовка самостоятельно, что означает, что вы можете указать любой порт источника и назначения, какой захотите.Единственная сложность заключается в вычислении необязательной, но важной контрольной суммы UDP , для которой требуются не только заголовок и полезная нагрузка UDP, но также IP-адрес источника и назначения, причем первый является проблематичным, поскольку для его вызова требуется API-интерфейс Win32.( GetBestInterface и GetAdaptersInfo ), который включает в себя несколько собственных структур и большое количество неуправляемых распределений памяти, потенциальная ошибка надежности с точки зрения .NET, но это может быть сделано.
  2. Вторая проблема, связанная с использованием одного сокета для приема пакетов UDP из списка (или диапазона) портов, остается нерешенной мной.Даже с необработанным сокетом операционная система требует, чтобы я связал сокет с конкретным портом, прежде чем разрешить мне выполнять операции приема.Есть способ сделать это?Всегда есть методы перехвата пакетов, но я бы предпочел их избегать, если это не может быть сделано из управляемого кода надежным и несколько простым способом (в этом случае я открыт для предложений).

Другие подходы?

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

1 Ответ

4 голосов
/ 15 февраля 2011

Да, вы можете легко создать> 30 000 сокетов на компьютере с Windows, но вам может понадобиться настроить MAXUSERPORT (см. здесь ).

Используйте порты завершения ввода-вывода или асинхронный ввод-вывод, и вам не нужно беспокоиться об «опросе», а масштабируемость «просто работает».

Основная проблема с ресурсом - это пул невыгружаемых страниц, но это стало гораздо меньшей проблемой в Vista или более поздней версии (см. здесь ), следующая проблема - ограничение количества заблокированных страниц ввода-вывода, которое может быть проблема, если вы публикуете очень большие буферы для своих чтений, но, учитывая, что это UDP, я предполагаю, что у вас будут дейтаграммы «разумного» размера, и ограничение количества заблокированных страниц вряд ли будет проблемой.

Я писал о некоторых проблемах масштабируемости здесь: http://www.serverframework.com/asynchronousevents/2010/12/one-million-tcp-connections.html

Я написал инструменты, аналогичные тем, что вы пытаетесь сделать, используя мой C ++ серверный фреймворк . Существует пример инструмента тестирования UDP, который поставляется как часть платформы, которая отправляет настраиваемое количество дейтаграмм из уникальных клиентских портов и ожидает ответов, и который легко настроить, чтобы соответствовать вашим конкретным форматам дейтаграмм и требованиям к ответам (см. здесь ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...