KeepAlive с WCF и TCP?

Имам услуга на Windows, хостваща разширена WCF услуга, която комуникира през TCP(netTCP) с protobuf.net, понякога и със сертификати.

ReceiveTimeout е зададено на безкрайно, за да никога не прекъсва връзката поради неактивност. Но доколкото разбирам, връзката така или иначе може да бъде прекъсната, така че създадох прост двупосочен метод за услуга keepalive, който клиентът извиква на всеки 9 минути, за да поддържа връзката жива. Много е важно връзката никога да не се прекъсва.

Това ли е правилният начин? Или мога просто да премахна поддържането си на живо, защото 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, pouzdanата сесия прави това.   -  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" е нещо като полувалидна стойност. Има два специални конфигурационни сериализатора, които преобразуват "Infinite" в TimeSpan.MaxValue или int.MaxValue (така че те така или иначе не са наистина "безкрайни"), но не всичко в WCF изглежда разпознава това. Така че винаги е най-добре да посочите изрично времето за изчакване с времеви стойности.

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

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

Трето, когато използвате надеждна сесия, вие използвате настройката inactivityTimeout на reliableSession. Това прави две неща. Първо, той контролира колко често се изпращат инфраструктурни (keepalive) съобщения. Те се изпращат на половината от стойността на времето за изчакване, така че ако го зададете на 18 минути, те ще се изпращат на всеки 9 минути. Второ, ако не се получат съобщения за инфраструктура или операция (т.е. съобщения, които са част от вашия договор за данни) в рамките на времето за изчакване на неактивност, връзката се прекъсва, защото вероятно е имало проблем (една страна се е сринала, има мрежов проблем и т.н.). .).

receiveTimeout е максималният период от време, в който не могат да се получават съобщения за операция, преди връзката да бъде прекратена (по подразбиране е 10 минути). Задаването на това на голяма стойност (Int32.MaxValue е някъде в близост до 24 дни) поддържа връзката активирана, задаването на inactivityTimeout на по-малка стойност (отново, по подразбиране е 10 минути) (на време, което е по-малко от 2 пъти максималното количество време преди мрежовите рутери да прекъснат връзката от неактивност) поддържа връзката жива.

WCF се справя с всичко това вместо вас. След това можете просто да се абонирате за съобщенията за прекъсната връзка, за да знаете кога връзката е прекъсната поради реални причини (сривове на приложения, изтичане на времето на мрежата, загуба на захранване на клиенти и т.н.) и ви позволява да създадете отново връзките.

Освен това, ако не се нуждаете от подредени съобщения, задайте ordered="false", тъй като това значително намалява разходите за надеждни сесии. По подразбиране е вярно.

Забележка: Може да не получите събитие за прекъсване на връзката, докато не изтече inactivityTimeout (или не опитате да използвате връзката). Бъдете наясно с това и задайте съответно времето за изчакване.

Повечето препоръки в интернет са да зададете и receiveTimeout, и inactivityTimeout на Infinite. Това има два проблема, първите инфраструктурни съобщения не се изпращат навреме, така че рутерите ще прекъснат връзката... принуждавайки ви да правите свои собствени keepalive. Второ, голямото време за изчакване на неактивност означава, че няма да разпознае, когато връзката законно прекъсне, и трябва да разчитате на това прекъсване на ping, за да разберете кога възникне грешка. Всичко това е напълно ненужно и може дори да направи услугата ви още по-ненадеждна.

Вижте също това: Как да конфигурирам правилно WCF NetTcp Duplex надеждна сесия?

person Erik Funkenbusch    schedule 04.11.2014
comment
Благодаря! Доколкото прочетох, trustedSession прави същото като самия TCP протокол, но на друго ниво, затова сме го задали на enabled=false. Ако не използвам trustedSession, ще ми трябва собствен KeepAlive. Този KeepAlive е много прост, всичко, което прави, е да се обажда на празен метод на услуга на всеки, да кажем 9 минути, само за да се увери, че връзката е на живо. Ако не успее, затворете приложението. Къде мога да прочета повече за цялата тази информация, която публикувахте? Търсих това преди, но никога не го намерих. Все още не съм сигурен какви точно настройки да задам и какви допълнителни разходи може да създаде? - person Banshee; 05.11.2014
comment
@Banshee - Надеждната сесия, ако е правилно конфигурирана, както споменах, ще бъде най-малкото натоварване и най-надеждната. Като го изключите и го направите сами, вие принуждавате това, което по същество е функция от ниско ниво, в домейна на вашето приложение. Като го правите сами, вие губите важни метаданни, проследяване и отчитане за диагностика и статистики за perfmon. С други думи, вие използвате състезателна кола с висока производителност и изваждате двигателя и поставяте в него двигател за количка, след което се чудите защо не работи. - person Erik Funkenbusch; 05.11.2014
comment
@Banshee - Както казах, това не е добре документирано и има много дезинформация. Това, което казах тук, е трудно научено от години опити и грешки, проследяване в изходния код и четене на различна противоречива документация и откриване на това, което липсва. надеждна сесия, конфигурирана, както съм показал тук, работи много добре. Но трябва да разберете какво точно прави, защото документацията е непълна, подвеждаща, грешна или несъществуваща. - person Erik Funkenbusch; 05.11.2014
comment
Прикачих връзка към моя app.config в моята първа публикация (редактиране), бихте ли могли да погледнете дали текущата конфигурация ще работи добре с активиран trustedSession. Ако може да има проблеми, моля, посочете го. Конфигурацията е малко сложна, но се надявам, че разбирате настройката (имайте предвид, че ние също използваме сертификат в някои случаи). - person Banshee; 07.11.2014
comment
@Banshee - не. Все още настройвате inactivityTimeout и recieveTimeout на безкрайност. Трябва да зададете inactivityTimeout или на максималния период от време, който искате да изтече, преди връзката да бъде забелязана като прекъсваща, или на два пъти стойността на времето за ping, което искате (имайте предвид, че колкото по-малка е тази стойност, толкова по-чести ще бъдат 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
Не можах да намеря свойство с активиран trustedSession в docs.microsoft.com/en-us/dotnet/framework/configure-apps/. Не се ли поддържа повече? - person Michael Freidgeim; 23.11.2018
comment
@MichaelFreidgeim - Мисля, че активираното свойство все още е там, просто не е документирано. Възможно е да е премахнат и само присъствието на елемента да е достатъчно, за да го активира, но не виждам конкретни споменавания за него. - person Erik Funkenbusch; 24.11.2018