KeepAlive с WCF и TCP?

У меня есть служба Windows, на которой размещается расширенная служба WCF, которая обменивается данными через TCP (netTCP) с protobuf.net, иногда также с сертификатами.

Для параметра receiveTimeout установлено значение бесконечно, чтобы соединение никогда не прерывалось из-за бездействия. Но насколько я понимаю, соединение может быть разорвано в любом случае, поэтому я создал простой двухсторонний сервисный метод keepalive, который клиент вызывает каждые 9 минут, чтобы поддерживать соединение. Очень важно, чтобы связь никогда не прерывалась.

Это правильный путь? Или я могу просто удалить свой Keep Live, потому что receiveTimout установлен на бесконечность?

Изменить: текущий app.config для службы WCF: http://1drv.ms/1uEVKIt


person Banshee    schedule 04.11.2014    source источник
comment
Если вы намерены поддерживать соединение открытым, вы должны периодически отправлять ping-пакеты, иначе маршрутизаторы с отслеживанием состояния могут разорвать соединение из-за бездействия.   -  person Luiz Felipe    schedule 04.11.2014
comment
Хорошо, как мне узнать, как часто нужно отправлять этот пинг?   -  person Banshee    schedule 04.11.2014
comment
Что происходит, когда соединение обрывается из-за временной ошибки? Вы не можете предотвратить это.   -  person usr    schedule 04.11.2014
comment
Я подозреваю, что если соединение будет разорвано из-за тайм-аута, это также будет timoutException, но я не уверен в этом. Однако, если соединение разорвано, есть действительно известный способ сохранить его без создания нового соединения. Если канал неисправен, с ним ничего нельзя сделать (о чем я знаю).   -  person Banshee    schedule 04.11.2014
comment
@LuizFelipe - нет, если вы правильно настроили надежный сеанс, что очень немногие делают правильно.   -  person Erik Funkenbusch    schedule 04.11.2014
comment
Это было два года назад, когда я использовал WCF, да, вы правы, я думал в терминах TCP, надежный сеанс делает это.   -  person Luiz Felipe    schedule 04.11.2014
comment
Действительна ли ссылка app.config для службы WCF?   -  person SDK    schedule 09.02.2016
comment
Связанная (для противоположной) ссылка: если вы используете http (не tcp) и хотите отключить поддержку активности, см. stackoverflow.com/questions/6535074/   -  person Michael Freidgeim    schedule 25.11.2018


Ответы (1)


Нет. Это неправильно понимают, и, к сожалению, существует много дезинформации.

Во-первых, «Бесконечное» — это своего рода полудействительное значение. Существует два специальных сериализатора конфигурации, которые преобразуют «Infinite» либо в TimeSpan.MaxValue, либо в int.MaxValue (так что в любом случае они на самом деле не «бесконечны»), но, похоже, не все в WCF распознает это. Поэтому всегда лучше явно указывать тайм-ауты со значениями времени.

Во-вторых, вам не нужен метод «keepalive» в вашей службе, так как WCF обеспечивает так называемый «надежный сеанс». Если вы добавите <reliableSession enabled="true" />, тогда WCF предоставит собственный механизм поддержания активности через «сообщения инфраструктуры».

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

В-третьих, при использовании надежного сеанса вы используете настройку inactivityTimeout для reliableSession. Это делает две вещи. Во-первых, он контролирует, как часто отправляются сообщения инфраструктуры (keepalive). Они отправляются с половиной значения времени ожидания, поэтому, если вы установите его на 18 минут, они будут отправляться каждые 9 минут. Во-вторых, если в течение тайм-аута бездействия не получены никакие инфраструктурные или операционные сообщения (т. е. сообщения, которые являются частью вашего контракта на передачу данных), соединение прерывается, потому что, вероятно, возникла проблема (сбой на одной стороне, проблема с сетью и т. д.). .).

receiveTimeout — это максимальное время, в течение которого не может быть получено ни одного сообщения о работе, прежде чем соединение будет прервано (по умолчанию — 10 минут). Установка этого значения на большое значение (Int32.MaxValue где-то около 24 дней) поддерживает подключение, устанавливая inactivityTimeout на меньшее значение (опять же, по умолчанию 10 минут) (на время, которое меньше, чем 2x максимальное количество времени до того, как сетевые маршрутизаторы разорвут соединение из-за неактивности) сохраняет соединение активным.

WCF обрабатывает все это за вас. Затем вы можете просто подписаться на сообщения «Соединение прервано», чтобы знать, когда соединение прерывается по реальным причинам (сбои приложений, тайм-ауты сети, отключение питания клиентов и т. д.), и позволяет вам воссоздать соединения.

Кроме того, если вам не нужны упорядоченные сообщения, установите ordered="false", так как это значительно снижает нагрузку на надежные сеансы. Значение по умолчанию верно.

Примечание. Вы можете не получить сообщение о разрыве соединения, пока не истечет время ожидания inactivityTimeout (или пока вы не попытаетесь использовать соединение). Помните об этом и соответственно устанавливайте тайм-ауты.

Большинство рекомендаций в Интернете — установить для ReceiveTimeout и inactivityTimeout значение Infinite. У этого есть две проблемы: во-первых, сообщения инфраструктуры не отправляются своевременно, поэтому маршрутизаторы разрывают соединение... заставляя вас выполнять свои собственные проверки активности. Во-вторых, большой тайм-аут бездействия означает, что он не распознает, когда соединение законно разрывается, и вы должны полагаться на прерывание этого пинга, чтобы узнать, когда произойдет сбой. Все это совершенно не нужно и может даже сделать ваш сервис еще более ненадежным.

См. также это: Как правильно настроить Надежный дуплексный сеанс WCF NetTcp?

person Erik Funkenbusch    schedule 04.11.2014
comment
Спасибо! Судя по тому, что я прочитал, trustSession делает то же самое, что и сам протокол TCP, но на другом уровне, поэтому мы установили для него значение enabled=false. Если я не использую trustSession, мне понадобится мой собственный KeepAlive. Этот KeepAlive очень прост, все, что он делает, это вызывает пустой сервисный метод каждые, скажем, 9 минут, просто чтобы убедиться, что соединение активно. Если это не удается, закройте приложение. Где я могу прочитать больше обо всей той информации, которую вы опубликовали? Я искал это раньше, но так и не нашел. Я все еще не уверен, какие именно параметры установить и какие накладные расходы это может создать? - person Banshee; 05.11.2014
comment
@Banshee - Надежный сеанс, если он правильно настроен, как я уже упоминал, будет с наименьшими накладными расходами и наиболее надежным. Отключив его и сделав это самостоятельно, вы принудительно внедряете то, что по сути является низкоуровневой функцией, в домен вашего приложения. Делая это самостоятельно, вы теряете важные метаданные, отчеты о трассировке и диагностике, а также статистику производительности. Другими словами, вы используете гоночный автомобиль с высокими характеристиками, вырываете двигатель и вставляете в него двигатель для картинга, а затем удивляетесь, почему он не работает. - person Erik Funkenbusch; 05.11.2014
comment
@Banshee - Как я уже сказал, это плохо задокументировано, и там много дезинформации. То, что я здесь сказал, было тяжело изучено годами проб и ошибок, отслеживанием исходного кода, чтением различной противоречивой документации и выяснением того, чего не хватает. надежный сеанс, сконфигурированный так, как я показал здесь, работает очень хорошо. Но вы должны точно понимать, что он делает, потому что документация неполная, вводящая в заблуждение, неправильная или вообще не существует. - person Erik Funkenbusch; 05.11.2014
comment
Я прикрепил ссылку на мой app.config в своем первом сообщении (отредактировать), не могли бы вы посмотреть, будет ли текущая конфигурация хорошо работать с включенным надежным сеансом. Если могут быть проблемы, пожалуйста, укажите это. Конфигурация немного сложна, но я надеюсь, вы понимаете настройку (обратите внимание, что в некоторых случаях мы также используем сертификат). - person Banshee; 07.11.2014
comment
@ Банши - нет. Вы по-прежнему устанавливаете inactivityTimeout и reciveTimeout на бесконечность. Вы должны установить inactivityTimeout либо на максимальное количество времени, которое вы хотите истечь, прежде чем соединение будет замечено как недоступное, либо на двойное значение времени ping, которое вы хотите (имейте в виду, что чем меньше это значение, тем чаще будет происходить ping). и если у вас подключено много клиентов, то это увеличивает нагрузку от пинга, поэтому устанавливать его на 1 секунду нецелесообразно). Вы также должны установить для параметра receiveTimeout фактическое значение времени, например 24.00:00:00, что составляет 24 часа. - person Erik Funkenbusch; 07.11.2014
comment
@Banshee - В любом случае Infinite на самом деле не бесконечен, в любом случае это чуть более 24 часов. Но установка фактического значения времени проясняет это, и это работает лучше для случаев, которые не понимают бесконечное значение. Если вам нужно, чтобы он не спал 24/7, вы просто переподключаетесь при прерывании. Если вам ДЕЙСТВИТЕЛЬНО нужно, чтобы он оставался на связи без перебоев (за исключением сбоя сети или приложения/компьютера), убедитесь, что в течение 24 часов отправлено хотя бы одно сообщение. - person Erik Funkenbusch; 07.11.2014
comment
Итак, вы говорите, что я должен настроить его, как вы объяснили, но также сохранить свой сервисный метод keepAlive и вызывать его раз в 23 часа? У меня нет функции повторного подключения прямо сейчас, у меня была раньше, но это было очень хлопотно, поэтому очень важно, чтобы соединение никогда не прерывалось из-за тайм-аута. - person Banshee; 09.11.2014
comment
@Banshee - Извините, я имел в виду 24 дня, а не 24 часа. Вы не можете предотвратить отключение. Всегда будут ситуации, которые вы не можете контролировать, например, сбои сетевой маршрутизации. Поддержание непрерывного соединения маловероятно, чем дольше вы держите его открытым. В конце концов, возникнет какое-то условие, даже если это просто установка исправлений и перезагрузка сервера. Вам по-прежнему нужен способ повторного подключения, когда соединение обрывается. Если вы не сделаете ни одного звонка через соединение в течение 24 дней, я сомневаюсь, насколько важно поддерживать его. - person Erik Funkenbusch; 09.11.2014
comment
Проголосовал. Этот ответ сильно неверен во всех возможных отношениях, полностью вводит в заблуждение и игнорирует все, что задокументировано Microsoft о надежных сеансах. Что вы предлагаете, так это использовать действительно тяжеловесную функцию, которая вообще не предназначена для замены поддержания жизни, на самом деле она даже не работает так, как вы упомянули. Надежные сеансы — это дорогостоящий уровень, который следует использовать на ненадежных каналах связи, а не использовать в качестве плохой замены для поддержания активности на уровне приложения, и это отражено в вашем объяснении, в котором вы объединяете inactivityTimeout и receiveTimeout. - person motoDrizzt; 13.12.2016
comment
ReceiveTimeout — это официальный параметр WCF для управления временем бездействия до того, как сеанс будет удален, точка. Надежные сеансы работают, гарантируя, что соединение не было потеряно из-за физических проблем, таких как маршрутизаторы SOAP, отбрасывание пакетов HTTP и т.п. Если приложение не должно быть развернуто на проблемных каналах связи, включение надежных сеансов — это просто огромные накладные расходы, и тогда вам все равно придется полагаться на receiveTimeout, чтобы предотвратить закрытие соединения. Этот ответ следует удалить, потому что в его нынешнем виде он предлагает сделать что-то очень неправильное. - person motoDrizzt; 13.12.2016
comment
@motoDrizzt - Вы совершенно не правы. На самом деле вся информация, которую я представил, взята непосредственно из документации MSDN. Хотя можно спорить о том, следует ли использовать такой механизм для долгосрочных связей, факт в том, что представленная мной информация на 100% верна. Например, ваши замечания о ReceiveTimeout противоречат документации MSDN. Я предлагаю вам прочитать примечания в MSDN msdn.microsoft.com/en-us/library/ - person Erik Funkenbusch; 21.12.2016
comment
Из документации MSDN: TimeSpan.MaxValue на самом деле составляет 10 675 199 дней (30 000 лет). - person Kyberias; 11.04.2017
comment
@Kyberias - Правильно, я опечатался выше. Это должно быть Int32.MaxValue, а не TimeSpan.MaxValue. Максимальное значение для параметра receiveTimeout равно 24.20:31:23.6470000. Это Int32.MaxValue и представляет собой максимальное количество миллисекунд, которое, если вы вычислите (2 ^ 31)/1000/60/60/24 = указанное выше число. - person Erik Funkenbusch; 12.04.2017
comment
Мне не удалось найти свойство с включенным параметром "надежный сеанс" в docs.microsoft.com/en-us/dotnet/framework/configure-apps/. Он больше не поддерживается? - person Michael Freidgeim; 23.11.2018
comment
@MichaelFreidgeim - я думаю, что включенное свойство все еще существует, просто не задокументировано. Возможно, он был удален, и для его включения достаточно наличия элемента, но я не вижу конкретных упоминаний об этом. - person Erik Funkenbusch; 24.11.2018