2009-10-21 5 views
1

Я использую VSTS 2008 + C# + .Net 3.5 для разработки консольного приложения, и я отправляю запрос на другой сервер (IIS 7.0 на Windows Server 2008). Я обнаруживаю, что если количество потоков запросов велико (например, потоки 2000), клиент будет получать сообщение об ошибке «Не удается подключиться к удаленному серверу» при вызове response = (HttpWebResponse) request.GetResponse(). Мое замешательство - у меня есть установить таймаут, чтобы быть большой величиной, но я получил сообщение об ошибке в течение минуты. Я думаю, что даже если соединение действительно больше, чем то, что может обслуживать IIS, клиент не должен так быстро получать сообщение об ошибке, он должен получить такое сообщение после периода ожидания. Любые комментарии? Какие-нибудь идеи, что не так? Любые идеи по увеличению количества параллельных соединений, которые обслуживаются IIS 7.0?«Не удалось подключиться к удаленному серверу сбой» в HttpWebRequest

Вот мой код,

class Program 
    { 
     private static int ClientCount = 2000; 
     private static string TargetURL = "http://labtest/abc.wmv"; 
     private static int Timeout = 3600; 

     static void PerformanceWorker() 
     { 
      Stream dataStream = null; 
      HttpWebRequest request = null; 
      HttpWebResponse response = null; 
      StreamReader reader = null; 
      try 
      { 
       request = (HttpWebRequest)WebRequest.Create(TargetURL); 
       request.Timeout = Timeout * 1000; 
       request.Proxy = null; 
       response = (HttpWebResponse)request.GetResponse(); 
       dataStream = response.GetResponseStream(); 
       reader = new StreamReader(dataStream); 

       // 1 M at one time 
       char[] c = new char[1000 * 10]; 

       while (reader.Read(c, 0, c.Length) > 0) 
       { 
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message + "\n" + ex.StackTrace); 
      } 
      finally 
      { 
       if (null != reader) 
       { 
        reader.Close(); 
       } 
       if (null != dataStream) 
       { 
        dataStream.Close(); 
       } 
       if (null != response) 
       { 
        response.Close(); 
       } 
      } 
     } 

     static void Main(string[] args) 
     { 
      Thread[] workers = new Thread[ClientCount]; 
      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i] = new Thread((new ThreadStart(PerformanceWorker))); 
      } 

      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i].Start(); 
      } 

      for (int i = 0; i < ClientCount; i++) 
      { 
       workers[i].Join(); 
      }   

      return; 
     } 
    } 
+1

Я обновил свой ответ, вы можете вставить полное исключение? – Kev

ответ

3

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

Быстрый ответ: использовать асинхронные операции для чтения данных вместо создания пучка потоков. Или, по крайней мере, использовать пул потоков (и подсчет нижних рабочих потоков). Помните, что больше подключений к одному источнику будет только ускорять работу до некоторой степени. Попробуйте сравнить его, и вы увидите, что, вероятно, 3-5 соединений будут работать быстрее, чем 2000, которые вы используете сейчас.

Подробнее об асинхронной архитектуре клиент/сервер (IOCP - порты ввода/вывода) и его преимуществах. Вы можете начать отсюда:

MSDN - Using an Asynchronous Server Socket

MSDN - Asynchronous Server Socket Example

CodeProject - Multi-threaded .NET TCP Server Examples

Все эти примеры использует нижний объект уровня TCP, но он может быть применен к WebRequest/WebResponse, а также.

UPDATE

Чтобы попробовать версию пула потоков, вы можете сделать что-то вроде этого:

ManualResetEvent[] events = new ManualResetEvent[ClientCount]; 
for (uint cnt = 0; cnt < events.Length; cnt++) 
{ 
    events[cnt] = new ManualResetEvent(false); 
    ThreadPool.QueueUserWorkItem(obj => PerformanceWorker()); 
} 

WaitHandle.WaitAll(events); 

Не тестировался, может потребоваться некоторые корректировки.

+0

Я хочу симулировать (выполнять тестирование производительности) сценарий, когда имеется большое количество одновременных соединений. Использование пула потоков может имитировать это лучше, чем использование реальных параллельных потоков? – George2

+1

Вы действительно должны попробовать сами. Я не уверен, что это принесет пользу вам в этом случае (так как это для нагрузочного тестирования, поэтому не очень важна производительность), но вы узнаете что-то новое (-. Обновленный ответ с примером пула потоков. – Audrius

+0

У меня есть связанный с этим вопрос, оцените, если вы можете взглянуть. Спасибо http://stackoverflow.com/questions/1600002/configure-iis-7-0-meta-database-issue – George2

2

Я думаю, вы увеличившихся очереди пула приложений веб-сайта. По умолчанию задано 1000 запросов, вы наводняете сервер с 2000 запросами более или менее сразу. Увеличение таймаута не решит этого.

Try увеличение длины очереди для пула приложений сайта проживает в.

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

Update:

Когда я запускаю свой код и попытаться скачать ощутимый файл (200MB) я получаю (503) Server Unavailable.. Увеличение размера очереди запросов пула приложений решает эту проблему (я установил мой 10000).

Только один раз я видел Unable to connect to remote server и, к сожалению, не удалось выполнить репликацию. Эта ошибка звучит так, как будто что-то сломалось на уровне TCP/IP. Можете ли вы опубликовать полное исключение?

+0

Спасибо! 1. Я увеличил его до 65535. Я думаю, вы имеете в виду диспетчер IIS => пулы приложений => расширенные настройки => длина очереди. Является ли это правильным местом и значением, которое вы хотите установить? 2. Для базового статуса Http, как его получить? – George2

+2

Как я прокомментировал форум iis.net, журналы ошибок HTTP содержат эту информацию. –

+0

Спасибо Kev, потому что «очередь запросов пула приложений решает это», вы имеете в виду IIS Manager => пулы приложений => расширенные настройки => длина очереди? – George2

1

Перейдите по ссылке Smart Thread Pool и снимите код. Это пул потоков экземпляров, который ограничивает количество потоков. Пул потоков .Net может быть проблематичным в приложениях, которые подключаются к веб-серверам и серверам SQL.

Изменение цикла к этому

static void Main(string[] args) 
     { 
      var stp = new SmartThreadPool((int) TimeSpan.FromMinutes(5).TotalMilliseconds, 
              Environment.ProcessorCount - 1, Environment.ProcessorCount - 1); 
      stp.Start(); 
      for (var i = 0; i < ClientCount; i++) 
      { 
       stp.QueueWorkItem(PerformanceWorker); 
      } 
      stp.WaitForIdle(); 
      stp.Shutdown(); 

      return; 
     } 

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

Также добавьте эту конфигурацию. Значение 100 используется по умолчанию. В коде есть способ сделать это, но синтаксис ускользает от меня сейчас.

<system.net> 

    <connectionManagement> 

     <add address=“*“ maxconnection=“100“ /> 

    </connectionManagement> 

</system.net> 
+0

Пул интеллектуальных потоков не может быть открыт. Я искал несколько в Интернете, вы имеете в виду это? http://www.codeproject.com/KB/threads/smartthreadpool.aspx – George2

+0

Почему «пул потоков .Net может быть проблематичным в приложениях, которые подключаются к веб-серверам и серверам SQL»? – George2

0

Я использую Visual Studio 2005. Как отправить SMS, вот мой код:

IPHostEntry host; 
host = Dns.GetHostEntry(Dns.GetHostName()); 
UriBuilder urlbuilder = new UriBuilder(); 
urlbuilder.Host = host.HostName; 
urlbuilder.Port = 4719; 
string PhoneNumber = "9655336272"; 
string message = "Just a simple text"; 
string subject = "MMS subject"; 
string YourChoiceofName = "victoria"; 
urlbuilder.Query = string.Format("PhoneNumber=%2B" + PhoneNumber + "&MMSFrom=" + YourChoiceofName + "&MMSSubject=" + subject + "&MMSText=" + message);//+ "&MMSFile=http://127.0.0.1/" + fileName 
HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(urlbuilder.ToString(), false)); 
HttpWebResponse httpResponse = (HttpWebResponse)(httpReq.GetResponse()); 
Смежные вопросы