Клиентский канал не работает после сброса сети - PullRequest
1 голос
/ 01 апреля 2019

Сводка: если клиентский канал находится в состоянии READY и сеть отключена, канал становится непригодным для использования, и клиент не будет пытаться повторно подключиться к серверу после восстановления сетевого подключения.Канал не переходит из состояния READY в состояние TRANSIENT_FAILURE при ошибке DEADLINE_EXCEEDED (крайний срок, установленный моим клиентским приложением).

Какая версия gRPC и на каком языкеВы используете?

1.17.2 То же, что и в версии 1.11.x C ++

Какая операционная система (Linux, Windows, ...) и версия?

Клиент работает на Ubuntu 16.04.Сервер под управлением Windows Enterprise.

Что вы сделали?

Сервер и клиент оба запущены в подключенной сети.Я могу успешно совершать звонки и получать ответы от сервера.Когда сеть выключена, сервер получает ошибку "Disconnected client - Endpoint read failed".Некоторые другие соответствующие поля в этом отладочном сообщении - "grpc_status":14 (UNAVAILABLE), "occured_during_write":0, "description":"An established connection was aborted by the software in your host machine".

Во время отключения сети клиент вообще не печатает никаких журналов (используя GRPC_TRACE=connectivity_state,call_error,op_failure,server_channel,client_channel,channel GRPC_VERBOSITY=DEBUG).

Один разсеть включается снова, журналы не обнаруживаются ни на сервере, ни на клиенте.Попытка сделать звонок с помощью клиента (отправить запрос на запуск) приводит к повторяющейся ошибке DEADLINE_EXCEEDED.Отключение сетевого подключения в это время не приводит к ошибке "Disconnected client" на стороне сервера.

В контексте клиента задано использование крайнего срока (проверено с 2 и 10 секундами).В этом случае используются синхронные вызовы.

Фрагменты кода:

/ rpc_service.proto

syntax = "proto3";

import "google/rpc/status.proto";

message RpcRequest {
}

message RpcResponse {
}

service RpcService{
rpc Call(RpcRequest) returns (RpcResponse);
}

/ client.cc

Инициализация:

std::unique_ptrRpcService::Stub stub_ = RpcService::NewStub(::grpc::CreateChannel(
server_endpoint, ::grpc::InsecureChannelCredentials()));

Отправка запроса RPC:

::grpc::ClientContext context;
context.set_deadline(
gpr_time_from_micros(call_timeout_.InMicroseconds(), GPR_TIMESPAN));
RpcRequest request;
RpcResponse response;
::grpc::Status grpc_status = stub_->Call(&context, request, &response);

/ server.cc

grpc::ServerBuilder builder;
builder.AddListeningPort(endpoint, ::grpc::InsecureServerCredentials());
builder.RegisterService(&rpc_service);
std::unique_ptrgrpc::Server grpc_server_ = builder.BuildAndStart();

Что вы ожидали увидеть?

Клиент должен сделать успешный вызов после сброса сети.

Что вы видели вместо этого?

Клиент не получает ответс сервера.

Что еще мы должны знать о вашем проекте / среде?

Когда сетевое соединение восстанавливается и клиент не получает ответ отсервер tcpdump перехватывает клиента, отправляющего некоторые пакеты.Запуск клиента и сервера с включенной сетью, а затем отключение от сети не приводит к сообщениям об ошибках, пока не будет предпринята попытка вызова.Это тот же результат, что и при запуске клиента и сервера с отключенной сетью.После попытки вызова клиент перейдет из IDLE в CONNECTING, а затем начнет подпрыгивать назад и вперед между состояниями CONNECTING и TRANSIENT_FAILURE (пытаясь восстановить соединение с экспоненциальным отключением), пока соединение не будет повторно установлено.

Если клиент запускается с подключенной сетью, но не отправляет запрос и сеть отключена, сервер не получает ошибку отключенного клиента.До тех пор, пока не будет выполнен вызов, клиент остается в "IDLE".

. Если клиент инициализируется и выполняется вызов в отключенной сети, клиент перейдет в состояние CONNECTING (с экспоненциальным откатом).максимум до 2 минут, когда клиент будет в состоянии TRANSIENT_FAILURE).Как только сеть будет подключена, соединение будет восстановлено в следующий раз, когда канал перейдет в состояние CONNECTING, а клиент перейдет в состояние READY.После этого каждый вызов будет успешным, пока сеть не будет сброшена.Отключение сети после того, как клиент находится в состоянии READY, не переведет клиента из состояния READY.

В итоге: до тех пор, пока не будет выполнен вызов, клиент будет оставаться в состоянии "IDLE" независимо от состояния сети.После совершения вызова клиент попытается установить соединение, войдя в состояние CONNECTING.Если соединение не найдено, оно переходит отказов в состояние между CONNECTING и TRANSIENT_FAILURE.Как только соединение найдено, клиент перейдет в состояние READY.Отсюда, если соединение потеряно, клиент больше не будет пытаться войти в состояние CONNECTING.

Проблема, аналогичная той, которая у меня возникла:

https://github.com/grpc/grpc/issues/16974

Известное исправление:

Создание нового канала при каждом вызове.

Неудачные попытки исправления:

Set GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA = 0

Вопросы:

Может ли клиент использовать уже созданный канал после сброса сети?

Поддерживает ли каналнужно перезапускать при перезагрузке сети?

Примечание: Я открыл тикет на grpc github и не получил ответа в течение 5 дней, поэтому я публикую здесь какЧто ж.Ссылка на выпуск GTP GPRC: https://github.com/grpc/grpc/issues/18554

...