Работа с потерей подключения
После завершения вызова RPC соединение не закрывается; он помечен как бесплатный. Таким образом, сервер может выйти из строя или сетевое подключение может быть потеряно во время или между вызовами, когда подключение находится в пуле. В соответствии с политикой время выполнения RPC повторно пытается выполнить эти вызовы только в том случае, если выполняются следующие два условия:
- Сервер не может выполнить вызов, или вызов является идемпотентным.
- Клиент может реализовать повторные попытки с эффективной производительностью.
Следующие пункты расширяют и поясняют эти два условия.
Идемпотентный вызов — это вызов, который может выполняться несколько раз на сервере без нежелательных побочных эффектов. Например, вызов RPC, который запрашивает баланс в банке для определенного счета, является идемпотентным. Если этот вызов выполняется дважды из-за потери подключения, вред не будет нанесен. Другим примером идемпотентного вызова является изменение адреса клиента в базе данных. Выполнение дважды нормально, так как второе выполнение просто заменяет уже текущий адрес тем же адресом. Операция, подобная "вычитание пятидесяти долларов из счета xyz", не является идемпотентной. Потеря сетевого подключения не должна приводить к многократному выполнению такого вызова.
Чтобы обеспечить безопасность, во время выполнения RPC все вызовы считаются неидемпотентными. Атрибут [идемпотентный] не поддерживается для ncacn_ip_tcp и игнорируется. Таким образом, первое условие в предыдущем списке сводится к серверу, который не может выполнить вызов.
Во многих случаях во время выполнения RPC не удается окончательно определить, что вызов еще не был выполнен на сервере. В таких случаях клиент не будет повторять выполнение вызова.
В следующих примерах показано, когда время выполнения RPC повторяет или не повторяет вызов:
Сервер перезагружается.
Простой вызов RPC без безопасности выполняется в интерфейсе, на котором после перезагрузки не было выполнено ни единого предыдущего вызова. Так как вызовы для этого интерфейса не выполнялись, во время выполнения RPC сначала предпринимается попытка согласовать использование интерфейса. Он отправляет пакет с помощью подключения в пуле. Так как сервер был перезагружен, а подключение больше не является допустимым, он возвращает ошибку. Так как время выполнения RPC на стороне клиента еще не начало отправку данных для фактического вызова, клиент определяет, что сервер не мог выполнить эти данные. Таким образом, он закрывает подключение и ищет другое соединение в пуле. Если не удается найти подключение, открывается новое подключение и предпринимается попытка согласовать использование интерфейса еще раз. В случае успешного выполнения вызова выполняется (то есть выполняется повторная попытка, так как сбой был обнаружен до начала вызова).
Вызов RPC с безопасностью (шифрованием) на уровне конфиденциальности выполняется при подключении с уже согласованным контекстом безопасности.
Чтобы обеспечить эффективную производительность, время выполнения RPC шифрует маршалированный пакет в встроенном коде (по данным с прозрачным текстом). Если попытка отправки данных завершается неудачно, время выполнения RPC не может повторить вызов, так как данные в виде ясного текста были перезаписаны зашифрованными данными и не могут повторно зашифровать данные с помощью нового контекста безопасности. Поэтому повторная попытка не выполняется.
Отправка фрагмента, отличного от первого, завершается сбоем.
Повторная попытка не выполняется, так как во время выполнения RPC может быть удалено содержимое первого фрагмента после его завершения и не может повторить отправку первого фрагмента.
Отправляется запрос RPC.
Сервер прерывает подключение. Повторные попытки не выполняются, так как RPC не может определить, получил ли сервер вызов и начал ли он его выполнять.
Если сервер использует динамическую конечную точку, RPC не будет повторно разрешать конечную точку во время повторных попыток. Это означает, что если сервер не работает и выполняет резервное копирование, он может находиться в другой конечной точке, и RPC не будет прозрачно повторно разрешать конечную точку при повторном вызове. Для принудительного повторного разрешения конечной точки клиент RPC должен вызвать RpcBindingReset , прежде чем повторить вызов.
Во многих случаях, если клиент RPC может определить, является ли вызов идемпотентным или сохраняет данные, которые RPC удаляет, он может создать механизм повтора на основе RPC.
Примечание
Если сервер является кластером и на разных узлах кластера работают разные версии серверного программного обеспечения, RPC может повторить вызов на другом узле кластера в случае отработки отказа и, возможно, на другой версии сервера. В таких сценариях развертывания убедитесь, что клиент не использует определенную версию серверного программного обеспечения для выполнения заданного вызова. Если это так, клиент должен создать механизм поверх RPC, который обнаруживает и обрабатывает такие условия.