
Это продолжение моей предыдущей статьи. Пожалуйста, прочтите это для лучшего понимания.
Вопросы, затронутые в этой статье:
- Архитектура gRPC
- Типы RPC
- Канал
- Виды заглушки
- Крайний срок
- Пример Java-клиента с крайним сроком
- Почему мы теряем начальные запросы на сервере, если Deadline меньше секунды?
Архитектура gRPC.
Архитектура gRPC разделена на 3 уровня: Surface (содержит Surface API и фильтры), Transport и IO-Manager.
- Surface API предоставляет подчеркнутые API-интерфейсы C-core, поскольку приложения не взаимодействуют напрямую с основными API-интерфейсами gRPC.
- Фильтры обеспечивают расширение основных функций gRPC, например
auth_filter - этот API выполняет аутентификацию для вызовов RPC.
deadline_filter - этот фильтр реализует крайний срок для вызовов RPC.
client_channel_filter - это очень важный фильтр, который выполняет разрешение имен, балансировку нагрузки и т. д. Мы обсудим этот фильтр подробно . - Транспорт реализует проводной протокол, по умолчанию он использует HTTP / 2, но мы можем использовать и другие протоколы, такие как QUIC и Cronet em. > и т. д.
- Уровни IO-Manager обеспечивают абстракцию для gRPC чтения / записи (т.е. конечных точек).
Этот уровень также предоставляет сетевые утилиты, таймеры и множество других примитивов, которые зависят от платформы (реализация на базе Windows или POSIX)

Типы RPC.
- Существует четыре типа RPC, Unary, Client Streaming, Server Streaming и Bidirectional Streaming. Мы собираемся обсудить первые два.
- Унарный RPC используется, когда клиент отправляет ровно одно сообщение и получает один ответ, как при обычном вызове функции.
- Клиентская потоковая передача - это когда клиент записывает последовательность сообщений и отправляет их на сервер, используя предоставленный поток.
Давайте обсудим канал.
- Канал - это канал связи или туннель между клиентом и целью.
- Вызов привязан к каналу, он имеет отношение "многие к одному", что означает, что несколько вызовов могут использовать один и тот же канал.
- Клиент и сервер выполняют операции (вызовы) в пакетном режиме, они могут выполнять все операции в пакетном режиме или разделять их на несколько пакетов на основе RPC.
- Когда пакет операций завершен, он помещается в очередь завершения.
- Очередь завершения - это очередь, в которой хранятся записи пакетов, после того, как пакет завершен с операциями, о которых сообщается в очереди завершения, чтобы можно было выполнить следующий пакет. .
- Между клиентом и сервером обмениваются сообщениями
Отправьте начальные метаданные. Ровно один раз за вызов сервером и клиентом
Получение исходных метаданных. Ровно один раз за звонок сервером и клиентом
Отправить сообщение. Ноль или более по серверу и клиенту (только одно сообщение отправлено для унарного RPC)
Получить сообщение. Ноль или более по серверу и клиенту (только одно сообщение отправлено для унарного RPC)
Отправить конечные метаданные. Ровно один раз за вызов сервером и клиентом
Получение конечных метаданных. Ровно один раз за вызов сервером и клиентом - Создание канала
- Создается очередь завершения, и поток ждет, чтобы наблюдать за этой очередью вечно.
- Вызывает API для создания канала к серверу и указывает URI сервера
- Фильтр клиентского канала выбирает преобразователь на основе схемы URI сервера
- Преобразователь возвращает список адресов, которые будут адресами сервера
- Фильтр клиентского канала затем инициализирует политику LB, в настоящее время, есть 3 политики LB - сначала выбрать (используется по умолчанию), циклический перебор, gRPC LB
- Это называется балансировкой нагрузки канала клиента
- Фильтр канала клиента затем создает канал с все бэкэнды, возвращенные преобразователем

- Канал создается ленивым способом, он не создает канал сразу, он ждет, пока на сервер не поступит вызов (запрос) (помните об этом )
- Как только сервер подтверждает создание канала клиентом, клиент создает субканалы.
- Канал - это набор субканалов, именно субканалы фактически сопоставляют вызовы с сервером.
- Создание канала может занять до 3 секунд (помните, что у нас есть вариант использования, который нужно обсудить)
Типы заглушек
- На стороне клиента у клиента есть объект, известный как заглушка, есть два типа заглушки: Блокирующая, Неблокирующая и Прослушиваемая будущая заглушка.
- Блокирующая заглушка - это когда клиент отправляет запрос на сервер и ожидает ответа.
- Неблокирующая заглушка используется для выполнения потокового вызова, он выполняет вызовы асинхронно, и ответ асинхронно возвращается с сервера. Эта заглушка может использоваться для потоковых вызовов RPC на стороне клиента.
- Listenable Future Stub - это когда клиент не ждет ответа, а вызов возвращает ListenableFuture. Клиент должен добавить обратный вызов, чтобы получить ответ на запросы.
- См. здесь для получения дополнительной информации.
Что такое крайний срок?
- Крайний срок - это период времени, который позволяет клиенту указать, как долго он будет готов ждать и RPC для завершения. крайний срок является абсолютным по времени. Если серверу требуется больше времени, чем установленный крайний срок, RPC завершается с ошибкой DEADLINE_EXCEEDED.
Как крайний срок распределяется по RPC?
- Крайний срок рассчитывается перед выполнением вызовов RPC к заглушке сервера.
- Крайний срок = текущая отметка времени + продолжительность крайнего срока
- Когда текущая отметка времени становится больше, чем крайний срок, RPC завершается
- Сервер всегда знает, действителен ли RPC

Пример Java-клиента с крайним сроком для сервера, который мы создали в предыдущей статье .
Еще один класс GrpcClient.java добавлен в тот же пакет, где присутствует сервер (проверьте структуру на изображении). Получите код из этого репозитория GitHub.

Давайте обсудим клиент gRPC. Чтобы создать клиента gRPC, нам нужно сначала создать канал, указав хост и порт. После этого мы собираемся создать блокирующую и слушаемую будущую подпрограмму (объяснялось ранее), чтобы объяснить работу.
После создания клиентской заглушки мы можем выполнить вызов RPC и получить ответ от сервера. Мы использовали крайний срок 5 мс для вызова RPC.
В случае, если сервер не может ответить в течение 5 мс, клиент завершит запрос Stream, и будет создано исключение DEADLINE_EXCEEDED. Если крайнего срока на стороне сервера нет, сервер обязательно обработает запрос.
Ответ как от блокирующей, так и от будущих заглушек

Исключение при превышении крайнего срока

Почему серверы gRPC не получают первые несколько пакетов, если крайний срок меньше?
Сценарий: нам нужно было реализовать клиент gRPC с крайним сроком 5 мс. Мы заметили, что сервер не получал некоторые из начальных запросов, отправленных клиентом.
Теперь, когда сервер не получил никаких запросов от клиента, но клиент сделал запросы и выдал исключение DEADLINE_EXCEEDED, что случилось с запросом?

Внимательно прочтите сообщение об ошибке, в котором говорится: wait_for_connection. Давайте углубимся в это и объясним, что происходит
- Клиент отправил серверу запрос на установление канала.
- Поскольку мы знаем, что создание канала - это ленивая работа, она создается не сразу, пока мы не сделаем вызов RPC.
- Клиент начинает отправлять запрос (к этому времени канал не установлен) запрос ожидает установления канала.
- По истечении крайнего срока клиент завершает RPC и выдает исключение DEADLINE_EXCEEDED.
- Таким образом, в основном вызов RPC не достиг заглушки сервера, и, следовательно, мы пропускаем начальные запросы на стороне сервера.
- В заключение давайте посмотрим на TCPdump в Wireshark. IP-адрес, заканчивающийся на .224, является заглушкой клиента, а окончание .41 - заглушкой сервера.

- Мы видим, что первые несколько попыток не смогли установить канал, поэтому любой RPC-вызов, сделанный за это время, не достигнет сервера.
- Мы также можем видеть, что для установления канала потребовалось 2,72 секунды, а затем был выполнен успешный вызов RPC, который также достиг сервера.
- Посмотрите на этот снимок экрана, здесь первый вызов с крайним сроком в 1 секунду обслуживается сервером, а последующий запрос вызывает исключение DEADLINE_EXCEEDED с сообщением [remote_addr = / 127.0.0.1: 8080]. Это означает, что канал установлен.

Полные коды, упомянутые здесь, можно найти в этом репо:
Ссылки:
https://grpc.io/docs/languages/java/basics/
https://www.wireshark.org/
https: //www.tcpdump.org/manpages/tcpdump.1.html
Удачного кодирования :)