У меня есть приложение 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
Я потратил много времени на поиск этого исключения и почти убедил себя, что я работаюout сокеты, как описано в WCF: System.Net.SocketException - обычно разрешено только одно использование каждого адреса сокета (протокол / сетевой адрес / порт)
, но проблема не была затронутая увеличил максимальное количество доступных сокетов и уменьшил значение TIME_WAIT.
Недавно мне пришло в голову, что, хотя драйвер Mongo выполняет пул соединений, каждый рабочий процесс имеет свой собственный пул.Эти пулы либо работают вместе для запуска системы из сокетов, либо просто пытаются использовать один и тот же адрес сокета одновременно.Последнее условие кажется более вероятным, поскольку это именно то, что предлагает исключение, и проблема не возникает, когда сайт развертывается в одном процессе.Но за пределами веб-сада снижение производительности очень заметно, и в случае сбоя процесса задержка переработки недопустима.Тем не менее, пользователи, получающие 500 ответов, одинаково неприемлемы.
Я рассмотрел следующее:
- Оберните все вызовы доступа к данным в конструкции try / retry-n-times / fail (уродливый и просто плохая практика)
- Переход на несколько машин вместо многопроцессорных (дорогостоящих и ненужных при текущих пользовательских нагрузках)
Вопросы:
- Есть ли способ, чтобы эти рабочие процессы изящно разделяли адрес / порт?
- Есть ли способ выполнить своего рода «запуск порта» (я уверен, что это не правильный термин), когда исходящее соединение каждого рабочего процесса может использовать другой локальный порт для подключения ктот же удаленный порт?Удаленный компьютер может обрабатывать несколько входящих соединений на одном и том же порту без проблем.
- Если вы считаете, что у меня заканчиваются сокеты, есть ли способ ограничить количество соединений с сокетами для каждого процесса, так чтоони могут совместно использовать 65536 розеток.