KeepAlive с WCF и TCP?

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

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

Правильно ли это? Или я могу просто удалить live keep, потому что receiveTimout установлен в бесконечное?

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

Ответ 1

Нет. Это широко не понято, и, к сожалению, там много дезинформации.

Во-первых, "Бесконечное" является своего рода полудействием. Существует два специальных сериализатора конфигурации, которые преобразуют "Бесконечные" в 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", так как это значительно снижает накладные расходы на надежные сеансы. Значение по умолчанию - true.

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

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

См. Также: Как правильно настроить WCF NetTcp Duplex Reliable Session?

Ответ 2

По моему опыту, я обнаружил, что проблема не обязательно вызвана службой или конфигурацией WCF, а клиентами является собственный маршрутизатор.

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