Перейти к основному содержимому

Синхронная коммуникация

Разработчику Архитектору Инженеру

Основы: Типы взаимодействия между системами, API и HTTP.


Синхронная коммуникация

Что такое синхронная коммуникация?

Клиент нажимает "Оплатить" и ждёт на экране спиннер, пока сервер не вернёт успех или ошибку — это синхронная модель. Синхронная коммуникация — способ взаимодействия, при котором отправитель отправляет запрос и ждёт ответа от получателя в том же логическом шаге.

Подход широко используется в микросервисной архитектуре для операций с немедленным результатом — проверка остатка, расчёт скидки, получение профиля. Для фона (письма, отчёты) берут асинхронную коммуникацию.

Синхронная коммуникация предполагает блокирующее взаимодействие: инициатор запроса ожидает завершения операции и получения ответа до продолжения выполнения. Клиент и сервер связаны во времени — задержка ответа напрямую влияет на производительность вызывающей стороны.

Примерами синхронности являются HTTP и RPC:

  • HTTP/HTTPS - клиент отправляет HTTP-запрос (например, GET или POST), и сервер немедленно отвечает на этот запрос.
  • RPC (Remote Procedure Call) - вызов удалённой процедуры, где клиент ожидает результата выполнения функции на сервере.

Для HTTP(S) используется, как правило, REST, а для RPC - gRPC.

Play ITЗагрузка интерактивного демо…


HTTP

image-9.png

HTTP — протокол прикладного уровня, реализующий модель запрос-ответ поверх надёжного транспорта (обычно TCP). HTTPS добавляет шифрование через TLS/SSL.

Архитектурные особенности

  • Состояние не сохраняется между запросами (stateless): каждый запрос должен содержать всю необходимую контекстную информацию.
  • Версии протокола:
    • HTTP/1.1: поддержка постоянных соединений (keep-alive), конвейеризация (pipeline) ограничена.
    • HTTP/2 — мультиплексирование потоков поверх одного TCP-соединения, сжатие заголовков (HPACK), серверные отправки (server push).
    • HTTP/3: замена транспорта с TCP на QUIC (поверх UDP) для снижения задержки при установке соединения и устойчивости к потере пакетов.
  • Методы запросов определяют семантику операции — GET (получение), POST (создание/действие), PUT/PATCH (обновление), DELETE (удаление).
  • Коды состояния группируются по классам — 2xx (успех), 3xx (перенаправление), 4xx (ошибка клиента), 5xx (ошибка сервера).

Механизмы надёжности

  • Повтор запроса при сетевых сбоях осуществляется на уровне приложения (идемпотентные методы GET, PUT, DELETE допускают безопасный повтор).
  • Таймауты соединения и чтения настраиваются на клиенте и сервере.
  • Для критичных операций применяется идемпотентность через идентификаторы запросов (например, идемпотентные ключи в платежных системах).

Ограничения синхронной модели

  • Блокировка потока выполнения до получения ответа.
  • Ограниченное время ожидания (таймауты прокси, балансировщиков, клиентских библиотек).
  • Неэффективность для длительных операций (долгие вычисления, внешние интеграции) — требуется применение паттернов опроса (polling) или асинхронных обратных вызовов.

Типичные сценарии применения

  • Веб-интерфейсы и мобильные клиенты.
  • Интеграция между сервисами с низкой задержкой и простой семантикой запроса.
  • RESTful API с чёткими контрактами и идемпотентными операциями.

RPC

image-10.png

RPC (Remote Procedure Call) — абстракция, позволяющая вызывать функцию на удалённом узле так, будто она локальная. Синхронная реализация подразумевает блокирующее ожидание результата.

Архитектурные особенности

  • Стек вызова расширяется через сеть: клиент сериализует параметры → отправляет запрос → ожидает ответ → десериализует результат/исключение.
  • Типы реализаций:
    • gRPC (Google) — бинарный протокол поверх HTTP/2, IDL на основе Protocol Buffers, поддержка потоковой передачи.
    • Apache Thrift — мультиязыковая поддержка, собственный бинарный протокол (также поддерживает HTTP, JSON).
    • JSON-RPC / XML-RPC: текстовые форматы поверх HTTP, простота отладки ценой производительности.
    • CORBA (устаревший): сложная распределённая объектная модель с поддержкой транзакций и безопасности.
  • Контракт интерфейса строго определяется в IDL (Interface Definition Language), что обеспечивает типобезопасность на этапе компиляции.

Механизмы надёжности

  • Автоматические повторы (retry) с экспоненциальной задержкой и ограничением количества попыток.
  • Таймауты на уровне вызова (deadline propagation) — критично для предотвращения каскадных отказов.
  • Трассировка распределённых вызовов через контекстные заголовки (например, trace ID в gRPC metadata).
  • Обнаружение сервисов (service discovery) и балансировка нагрузки на уровне клиента (client-side load balancing).

Проблемы синхронного RPC

  • Сетевые разделения приводят к блокировке или таймаутам вызывающего потока.
  • Каскадные отказы: медленный зависимый сервис блокирует все вызывающие его компоненты.
  • Сложность обеспечения согласованности при распределённых транзакциях.
  • Отсутствие встроенной очереди: пиковая нагрузка может привести к отказу сервиса.

Типичные сценарии применения

  • Высокопроизводительные внутренние API между микросервисами с низкой задержкой.
  • Системы, требующие строгой типизации и автоматической генерации клиентских библиотек.
  • Синхронные операции с предсказуемым временем выполнения (менее 100–500 мс).

HTTP(S) работают по модели "запрос-ответ", поэтому всегда подразумевает клиент-серверное взаимодействие, ведь клиент (веб-браузер или приложение) формирует и отправляет запрос на сервер, а сервер, получает запрос, обрабатывает его и отправляет ответ клиенту.

Детали HTTP, заголовков и кэша — в HTTP как основа веб-интеграций и REST. Ниже — RPC-стек и GraphQL для внутренних и гибких API.


gRPC, GraphQL

Учебное сравнение трёх стилей на сценарии "пользователь + заказы" (цепочка REST, один GraphQL-query, unary gRPC) — в основах REST, GraphQL и gRPC — стили API. Ниже — сводка для микросервисной архитектуры.

КритерийREST + JSONgRPC + ProtobufGraphQL
КонтрактOpenAPI, соглашения.proto, кодогенерацияSchema, introspection
ТранспортHTTP/1.1–2HTTP/2Обычно HTTP POST
КлиентБраузер, мобильныеСервис-сервисЧасто BFF / мобильные
Гибкость полейOver/under-fetchingФиксированные сообщенияКлиент выбирает поля
Типичное местоПубличный APIВнутренние вызовыАгрегация для UI

gRPC (Google Remote Procedure Call) — фреймворк для высокопроизводительных RPC-сервисов. В отличие от REST, gRPC использует HTTP/2 и Protocol Buffers (Protobuf).

Полная документация доступна здесь - https://grpc.io/

Этот подход лучше использовать для высокопроизводительных систем с большим объёмом данных, и если требуется строгая типизация и автоматическая генерация кода.

Protocol Buffers (Protobuf) — это специальный формат для описания контрактов (схем данных) и сериализации. Protobuf более компактный и быстрый, чем JSON.

HTTP/2 используется для передачи данных, что обеспечивает высокую производительность благодаря мультиплексированию, сжатию заголовков и двунаправленным потокам.

GraphQL — это язык запросов и среда выполнения для API, разработанный Facebook в 2012 году. Он позволяет клиентам запрашивать только те данные, которые им нужны, что делает его более гибким по сравнению с традиционными REST API. Клиент может указать точную структуру данных, которые он хочет получить.

Документация здесь - https://graphql.org/

Чит-лист - https://cheatsheets.zip/graphql

В отличие от REST, где каждый ресурс имеет свой URL, GraphQL использует один эндпоинт для всех запросов. GraphQL использует схему, которая определяет доступные данные и их типы, предоставляя документацию.


Сценарий в MSA — User Service и Order Service

Типичная схема из продакшена: внешний клиент (веб, мобильное приложение) и два доменных сервиса. Как меняется граница ответственности клиента — зависит от стиля API на границе.

Стиль на границеКто ходит в Order ServiceРиск для клиента
RESTСам клиент (второй GET /orders/{id})N+1 запросов, хрупкость при смене URL заказов
GraphQLBFF / GraphQL-слой по схемеСложность шлюза, лимиты глубины query
gRPCОбычно другой сервис (оркестратор, BFF), не браузерЖёсткий контракт .proto, нужна кодогенерация

REST. API Gateway или клиент вызывает User Service, затем Order Service. Между сервисами при этом тоже может быть gRPC — REST остаётся контрактом "наружу".

GraphQL. Один POST /graphql на BFF; резолверы внутри параллельно дергают User и Order (DataLoader, batching). Клиент не знает про разбиение на микросервисы.

gRPC. orders-api вызывает catalog-api через GetProduct / ReserveStock с deadline в metadata; мобильному клиенту отдают REST или GraphQL с того же BFF. Unary и streaming-режимы — в основах.

Практикум

Сквозной REST между двумя сервисами (каталог и заказы) — 8.08 Практикум REST и WebSocket. Там же JWT, API-ключ между сервисами и WebSocket для UI.


Паттерны устойчивости для sync-вызовов

Синхронная цепочка быстро деградирует, если один сервис в середине стал медленным. В продакшене поверх HTTP/gRPC обычно включают такие паттерны:

  • Timeout budget — общий лимит на всю цепочку (например, 800 мс), а не только на один hop.
  • Retry с backoff и jitter — только для идемпотентных операций (GET, PUT, безопасные POST с idempotency-key).
  • Circuit breaker — временно "размыкает" вызов к деградировавшему downstream, чтобы не положить весь сервис.
  • Bulkhead — отдельные пулы соединений/потоков для разных интеграций.
  • Fallback — отдача кэша/частичного ответа, если зависимый сервис недоступен.

Минимальный практический чек-лист для команды:

  1. На каждом клиенте явно задать connect timeout и read/deadline timeout.
  2. Добавить x-request-id / trace-id в каждый запрос.
  3. Логировать код ответа, latency, retry-count.
  4. Завести алерт по p95/p99 и доле 5xx для критичных endpoint.

Эти паттерны дополняют балансировку нагрузки и асинхронную коммуникацию, а не заменяют их.


Пример реализации

gRPC с Protocol Buffers

Определение контракта (.proto файл)

Код ITЗагрузка примера кода…

Разбор:

  • syntax и package задают версию proto и пространство имён; service объявляет RPC-методы; message — структуры полей на проводе.

Реализация на C#

Сервер:

Код ITЗагрузка примера кода…

Разбор:

  • AddHostedService<NotificationConsumer>() регистрирует слушателя очереди в DI; MapControllers() подключает REST-эндпоинты.
  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Клиент:

Код ITЗагрузка примера кода…

Разбор:

  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Реализация на Python

Сервер:

Код ITЗагрузка примера кода…

Разбор:

  • Импорты подключают модули проекта; выполнение идёт сверху вниз — сначала конфигурация, затем объявление сущностей или маршрутов.

Клиент:

Код ITЗагрузка примера кода…

Разбор:

  • Импорты подключают модули проекта; выполнение идёт сверху вниз — сначала конфигурация, затем объявление сущностей или маршрутов.

Реализация на Java

Сервер:

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

Клиент:

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

GraphQL

Схема типов (schema.graphql)

Код ITЗагрузка примера кода…

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Реализация на C# (Hot Chocolate)

Модели:

Код ITЗагрузка примера кода…

Разбор:

  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Резолверы:

Код ITЗагрузка примера кода…

Разбор:

  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Настройка сервера:

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddSubscriptionType<Subscription>()
.AddType<UserType>()
.AddType<PostType>();

var app = builder.Build();
app.MapGraphQL();
app.Run();

Разбор:

  • AddHostedService<NotificationConsumer>() регистрирует слушателя очереди в DI; MapControllers() подключает REST-эндпоинты.
  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Типы GraphQL:

Код ITЗагрузка примера кода…

Разбор:

  • Пространства имён группируют модели и сервисы; async/await не блокируют поток при HTTP-вызове наружу.

Реализация на Python (Strawberry)

Схема и резолверы:

Код ITЗагрузка примера кода…

Разбор:

  • Импорты подключают модули проекта; выполнение идёт сверху вниз — сначала конфигурация, затем объявление сущностей или маршрутов.

Запуск сервера (FastAPI):

from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter

graphql_app = GraphQLRouter(schema)
app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")

if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

Разбор:

  • FastAPI() создаёт приложение; декораторы @app.post / @app.get регистрируют маршруты и схемы ответа response_model.
  • Depends(get_db) внедряет сессию БД; BackgroundTasks откладывает публикацию в RabbitMQ, чтобы HTTP-ответ ушёл клиенту быстрее.
  • pika.BlockingConnection и basic_publish отправляют JSON-событие в очередь order_events; delivery_mode=2 помечает сообщение persistent.
  • Перед вставкой проверяется уникальность order_number; HTTPException(400) и (404) возвращают понятные коды клиенту.

Реализация на Java (GraphQL Java)

Схема:

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

DataFetcher для запросов:

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

Модели:

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

Запуск сервера (Spring Boot):

Код ITЗагрузка примера кода…

Разбор:

  • Пакеты model, repository, service разделяют слои — сущность, доступ к данным, бизнес-логика обработки заказов.

Примеры запросов и мутаций

Запрос пользователя с постами:

query {
user(id: "1") {
id
name
email
isActive
posts {
id
title
publishedAt
}
}
}

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Список пользователей с пагинацией:

query {
users(page: 1, pageSize: 5) {
id
name
email
posts {
id
title
}
}
}

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Создание пользователя:

mutation {
createUser(name: "Тимур", email: "timur@example.com", isActive: true) {
id
name
email
createdAt
}
}

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Создание поста:

Код ITЗагрузка примера кода…

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Фрагменты для повторного использования:

Код ITЗагрузка примера кода…

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

Параметризованный запрос:

Код ITЗагрузка примера кода…

Разбор:

  • Схема GraphQL описывает типы, запросы и подписки; директивы @key, @external используются в federation подграфов.

См. также


Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.