Asynchronouos Socket Communication и фрагментация кучи

Я написал многопоточное приложение Socket Server, которое принимает более 1000 одновременных подключений. Недавно у нас был сбой приложения; после анализа файлов дампа стало известно, что приложение имеет сбой из-за повреждения кучи. Я нашел ту же самую проблему, обсужденную в следующих ссылках.

.NET не имеет надежной асинхронной сокетной связи? http://support.microsoft.com/kb/947862

А также обсуждение предлагает 3 решения.

  1. Сетевое приложение должно иметь верхнюю границу числа ожидающих асинхронных операций ввода-вывода, которые оно публикует.

  2. Используйте Microsoft CCR

  3. Используйте TPL

Из-за временного фактора я думал придерживаться #1, но у меня нет четкой картины, как это реализовать. Кто-нибудь может дать хорошую отправную точку, пожалуйста?

А также кто-нибудь использовал Async с TPL для решения этой проблемы?

2 ответа

Вы имеете в виду лучшую отправную точку, чем публикация в блоге, на которую я ссылался в ответе, на который вы ссылаетесь?

Проблема заключается в следующем:

  • Память и другие ресурсы для каждой операции, которые используются во время асинхронной записи, часто "используются", пока стек TCP удаленного однорангового узла не подтвердит данные, и локальный стек не сможет завершить операцию асинхронной записи, чтобы сообщить вам, что вы можете повторно использовать свой буфер.
  • Локальный одноранговый узел не имеет никакого контроля над этим, поскольку все это зависит от скорости, с которой удаленный одноранговый узел считывает данные из своего сокета, и от перегруженности канала связи между двумя одноранговыми узлами.

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

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

Вы можете просто остановить отправку одноранговым сервером, когда достигнете своего предела - и теперь API, который вы строите на основе асинхронного API, должен иметь "не может быть отправлено в данный момент, попробуйте еще раз позже", возврат из отправки, который раньше всегда "Работа".

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

Во-первых, это очень старая статья в КБ. Как вы уверены, что у вас есть именно эта проблема? Затем, как Ханс Пассант отвечает на вопрос SO, если вы напишите неверный асинхронный код, он вас укусит. Если вы не позаботитесь о своих ресурсах (а буферы памяти являются ресурсами), параллельная программа столкнется с ошибками памяти

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

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

  1. Используйте BufferManager для повторного использования буферов памяти вместо выделения новых.
  2. Используйте очередь для хранения запросов и их асинхронной обработки вместо того, чтобы начинать новый поток для каждого запроса.

Есть и другие методы, которые вы можете использовать, в зависимости от типа приложения, которое вы создаете. Например, вы можете использовать TPL DataFlow для прерывания обработки в независимых шагах.

Что касается CCR, то нет особого смысла использовать его вне Robotics Studio. TPL содержит большую часть соответствующих функций, необходимых для написания параллельных приложений.

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