Исключения сокетов MongoDB C# в IIS 7.0 Web Garden (например, разрешено только одно использование каждого адреса сокета (протокола / сетевого адреса / порта))
У меня есть приложение ASP MVC, использующее драйвер 10gen Mongo C# ( github) для подключения к серверу базы данных через определенный порт. Я развернул это в веб-саду IIS 7.0 с 3 рабочими процессами. Каждые несколько минут под нагрузкой выдается следующее исключение, и 500 возвращается пользователю:
Only one usage of each socket address (protocol/network address/port) is normally permitted <database-ip>:<database-port>
Stack Trace:
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
at System.Net.Sockets.TcpClient.Connect(IPEndPoint remoteEP)
at MongoDB.Driver.Internal.MongoConnection.Open() in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 266
at MongoDB.Driver.Internal.MongoConnection.GetNetworkStream() in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 409
at MongoDB.Driver.Internal.MongoConnection.SendMessage(MongoRequestMessage message, SafeMode safeMode) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 377
at MongoDB.Driver.Internal.MongoConnection.RunCommand(String collectionName, QueryFlags queryFlags, CommandDocument command) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 296
at MongoDB.Driver.Internal.MongoConnection.Authenticate(String databaseName, MongoCredentials credentials) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 98
at MongoDB.Driver.Internal.MongoConnection.CheckAuthentication(MongoDatabase database) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Internal\MongoConnection.cs:line 195
at MongoDB.Driver.MongoServerInstance.AcquireConnection(MongoDatabase database) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoServerInstance.cs:line 185
at MongoDB.Driver.MongoServer.AcquireConnection(MongoDatabase database, Boolean slaveOk) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoServer.cs:line 893
at MongoDB.Driver.MongoCursorEnumerator`1.AcquireConnection() in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs:line 184
at MongoDB.Driver.MongoCursorEnumerator`1.GetFirst() in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs:line 194
at MongoDB.Driver.MongoCursorEnumerator`1.MoveNext() in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs:line 126
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at MongoDB.Driver.MongoCollection.FindOneAs[TDocument](IMongoQuery query) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCollection.cs:line 493
at MongoDB.Driver.MongoCollection.FindOneByIdAs[TDocument](BsonValue id) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCollection.cs:line 529
at MongoDB.Driver.MongoCollection`1.FindOneById(BsonValue id) in C:\work\10gen\mongodb\mongo-csharp-driver\Driver\Core\MongoCollection.cs:line 1462
Я потратил много времени на поиск этого исключения и почти убедил себя, что у меня заканчиваются сокеты, как описано в WCF: System.Net.SocketException - только одно использование каждого адреса сокета (протокол / сетевой адрес / порт) обычно разрешено
но проблема не была затронута моим увеличением максимального числа доступных сокетов и уменьшением значения TIME_WAIT.
Недавно мне пришло в голову, что, хотя драйвер Mongo выполняет пул соединений, каждый рабочий процесс имеет свой пул. Эти пулы либо работают вместе, чтобы запустить систему из сокетов, либо просто пытаются использовать один и тот же адрес сокета одновременно. Последнее условие представляется более вероятным, поскольку это именно то, что предлагает исключение, и проблема не возникает, когда сайт развертывается в одном процессе. Но за пределами веб-сада снижение производительности очень заметно, и в случае сбоя процесса задержка повторного использования недопустима. При этом пользователи, получившие 500 ответов, в равной степени неприемлемы.
Я учел следующее:
- Оберните все вызовы доступа к данным в конструкции try / retry-n-times / fail (некрасиво и просто плохо)
- Переход на несколько машин вместо многопроцессорных (дорогостоящих и ненужных при текущих пользовательских нагрузках)
Вопросы:
- Есть ли способ, чтобы эти рабочие процессы изящно разделяли адрес / порт?
- Есть ли способ сделать своего рода "запуск порта" (я уверен, что это не правильный термин), когда исходящее соединение каждого рабочего процесса может использовать другой локальный порт для подключения к тому же удаленному порту? Удаленный компьютер может обрабатывать несколько входящих соединений на одном и том же порту без проблем.
- Если вы думаете, что у меня заканчиваются сокеты, есть ли способ ограничить количество соединений сокетов для каждого процесса, чтобы они могли совместно использовать 65536 сокетов.