HTTP Server-Push: служба для службы, без браузера

Я разрабатываю облачную серверную HTTP-службу, которая будет доступна для интеграции с некоторыми локальными системами. Клиентские системы изготавливаются на заказ внешними поставщиками, это серверные системы с собственными базами данных. Эти системы развернуты в компаниях наших клиентов, мы не имеем к ним доступа и не контролируем их. Мы предоставляем поставщикам наши спецификации API, и они реализуют клиентский код.

Формат данных, которыми моя служба обменивается с клиентами, основан на XML и соответствует определенному стандарту. Поставщики реализуют свои клиентские системы на разных языках программирования, и со временем появятся новые поставщики. Я хочу, чтобы как можно больше клиентов могли работать с моим сервисом.

Большая часть моего сервисного API похожа на REST: он получает HTTP-запросы, обрабатывает их и отправляет обратно HTTP-ответы.

Кроме того, моя служба накапливает некоторые изменения состояния данных и должна регулярно передавать эти данные в клиентские системы. Из-за приведенных ниже ограничений этот вариант использования не подходит для традиционной модели HTTP-запрос-ответ клиент-сервер.

  1. Из-за характера бизнеса клиентские системы не могут позволить себе открывать свои собственные конечные точки HTTP API, поэтому моя служба не может установить к ним исходящее HTTP-соединение для доставки уведомлений о состоянии данных. т.е. использование WebHooks не вариант.

  2. В то же время заинтересованным сторонам моей службы требуется записанное подтверждение того, что уведомления о состоянии данных были приняты клиентской системой, поэтому системы типа «запустил и забыл», такие как Amazon SNS, похоже, не применяются.

Я рассматривал несколько подходов к этой проблеме, но я не уверен, упускаю ли я какие-то простые варианты или какие-то технологии, которые уже решают проблему. Отсюда этот вопрос.

Текст вопроса обновлен: параметры перемещены в мой собственный ответ.

Связанные вопросы и ресурсы


person Mike    schedule 27.10.2020    source источник
comment
Моя первая интуиция: веб-сокеты   -  person Evert    schedule 27.10.2020


Ответы (2)


В конце концов я нашел ответы на свой вопрос сам и с некоторой помощью моей команды. Для таких людей, как я, которые приходят сюда с вопросом, как мне организовать доставку уведомлений от моего сервиса его клиентам, вот обзор доступных вариантов.

Вебхуки

Это когда клиент сам открывает конечную точку. Служба вызывает конечные точки клиента всякий раз, когда у службы есть какое-либо уведомление для доставки. Таким образом, клиент также действует как служба, поэтому клиент и служба меняются ролями во время доставки уведомления.

При использовании WebHooks клиент должен иметь возможность открыть конечную точку с известным адресом. Это сложно, если программное обеспечение клиента работает за NAT или брандмауэром, или если клиент является браузером или мобильным приложением.

Служба должна быть готова к тому, что конечные точки WebHook клиента не всегда могут быть подключены к сети и не всегда могут быть работоспособными.

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

Опрос

В этом случае клиент остается клиентом, а служба — службой, в отличие от WebHooks. Служба предлагает конечную точку, где клиент может постоянно запрашивать новые уведомления. Преимущество этого варианта в том, что он не меняет направление соединения и направление запроса-ответа, поэтому он хорошо работает с сервисами на основе HTTP.

Предостережение заключается в том, что API опроса должен иметь некоторую богатую семантику, чтобы быть достаточно надежным, если потеря уведомлений неприемлема. Хорошими примерами могут быть Google Pub/Sub pull и Amazon SQS.

Вот несколько соображений:

  1. Получение и удаление уведомления должны быть отдельными операциями. В противном случае, если служба удалит уведомление непосредственно перед его передачей клиенту, а клиент не сможет обработать уведомление, уведомление будет потеряно навсегда. Когда операция удаления отделена от получения, клиент вынужден выполнять удаление явно, что обычно происходит после успешной обработки.

  2. В случае, если клиент получил уведомление и еще не удалил его, может быть нежелательно, чтобы такое же уведомление обрабатывалось каким-либо другим субъектом (возможно, параллельным процессом того же клиента). Поэтому уведомление должно быть скрыто от получения после того, как оно было впервые получено.

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

  4. Если у службы нет уведомлений для доставки, она должна заблокировать вызов клиента на некоторое время, не доставляя немедленно пустой ответ. В противном случае, если клиент опрашивает в цикле и ответ приходит немедленно, итерация цикла будет короткой, и клиенты будут делать чрезмерные запросы к сервису, увеличивая сеть, анализируя нагрузку и количество запросов. Приятной особенностью является то, что служба разблокирует и ответит клиенту, как только появится какое-либо уведомление о доставке. Иногда это называют долгим опросом.

События, отправленные HTTP-сервером

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

Недостатком является то, что связь является односторонней, у клиента нет возможности сообщить службе, если она успешно обработала событие. Поскольку эта обратная связь отсутствует, службе может быть сложно контролировать частоту событий, чтобы не перегрузить клиента.

Веб-сокеты

Веб-сокеты были созданы для обеспечения произвольной двусторонней связи, поэтому это жизнеспособный вариант для службы отправки уведомлений клиенту. Клиент также может отправить подтверждение обработки обратно в службу.

WebSockets существуют уже некоторое время и должны поддерживаться многими фреймворками и языками. Соединение WebSocket начинается как соединение HTTP 1.1, поэтому WebSockets через HTTPS должны поддерживаться многими балансировщиками нагрузки и обратными прокси-серверами.

Веб-сокеты часто используются с браузерами и мобильными клиентами и реже при обмене данными между службами.

gRPC

gRPC похож на WebSockets в том смысле, что он обеспечивает произвольную двустороннюю связь. Преимущество gRPC заключается в том, что он сосредоточен на файлах определений протоколов и форматов сообщений. Эти файлы используются для генерации кода, необходимого для разработчиков клиентов и служб.

gRPC используется для связи между службами, а также поддерживается для клиентов браузера с помощью grpc-web.

gRPC поддерживается несколькими популярными языками программирования и платформами, но эта поддержка более узкая, чем для HTTP.

gRPC работает поверх HTTP/2, что может вызвать трудности с обратными прокси-серверами и балансировщиками нагрузки из-за таких вещей, как завершение TLS.

Очередь сообщений (PubSub)

Наконец, служба и клиент могут использовать очередь сообщений в качестве механизма доставки уведомлений. Служба ставит уведомления в очередь, и клиент получает их из очереди. Очередь может быть предоставлена ​​одной из многих систем, таких как RabbitMQ, Kafka, Celery, Google PubSub, Amazon SQS и т. д. Существует широкий выбор систем очередей с различными свойствами, и выбор одной из них сам по себе является сложной задачей. Очередь также можно эмулировать, например, с помощью базы данных.

Это должно быть решено между службой и клиентом, которому принадлежит очередь, т.е. кто за нее платит. В любом случае, система очередей и очередь должны быть доступны всякий раз, когда сервису необходимо отправить ей уведомления, в противном случае уведомления будут потеряны (если только сервис не буферизует их внутри с помощью другой очереди).

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

Стоит отметить, что неявная внутренняя очередь может использоваться на стороне службы в других вариантах, перечисленных выше. Одна из причин — предотвратить потерю уведомлений, когда нет доступных клиентов для их получения. Есть много других веских причин, таких как предоставление клиентам возможности обрабатывать уведомления в своем темпе, что позволяет максимизировать пропускную способность обработки, позволяя обрабатывать скачкообразный трафик с фиксированной пропускной способностью.

В этом варианте очередь используется явно как механизм доставки, т. е. служба не ставит какой-либо другой механизм (HTTP, gRPC или конечную точку WebSocket) перед очередью и позволяет клиенту получать уведомления из очереди напрямую.

Передача сообщений популярна при организации взаимодействия микросервисов.

Общие соображения

Во всех вариантах необходимо решить, допустима ли потеря уведомлений для сервиса, клиента и бизнеса. Возможны некоторые более простые технические варианты, если можно потерять уведомления из-за ошибок обработки, недоступности и т. д.

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

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

Если доставка уведомления организована таким образом, что уведомление удаляется только после успешной обработки клиентом, это же уведомление может застрять в бесконечном цикле получения, когда клиент не сможет его обработать. Такое уведомление иногда называют подозрительным сообщением. Ядовитые сообщения должны удаляться службой или системой очередей, чтобы клиенты не застревали в бесконечном цикле. Распространенной практикой является перемещение подозрительных сообщений в специальное место, иногда называемое очередью недоставленных сообщений, для последующего вмешательства человека.

person Mike    schedule 29.10.2020

Одной из альтернатив WebSockets для проблемы уведомлений сервер → клиент с подтверждением от клиента, по-видимому, является gRPC.

  • Он поддерживает двунаправленную связь между сервером и клиентом в двунаправленной потоковой передаче. режим.
  • Он работает поверх HTTP 2.0. В нашем случае важна работа через HTTP-порты.
  • Существуют генераторы клиентов и серверов для нескольких популярных языков и платформ. Приятно то, что я могу поделиться файлом определения протокола с поставщиками и быть уверенным, что мой сервис и их клиенты будут говорить на одном языке.

Недостатки:

  • Поддерживается не так много языков и платформ по сравнению с HTTP. Альтернатива C из вопроса будет более доступной, если она основана на HTTP 1.1. WebSockets также существуют дольше, и я ожидаю более широкого распространения, чем gRPC.
  • В настоящее время не все реализации gRPC поддерживают формат XML для данных согласно часто задаваемым вопросам. Чтобы передать XML, моя служба и ее клиенты должны будут передавать XML-сообщение в виде байтовых массивов внутри сообщения gRPC protobuf.
  • При использовании gRPC завершение TLS не может быть выполнено на универсальном балансировщике нагрузки HTTP 1.1. Требуется обратный прокси-сервер прикладного уровня с поддержкой HTTP/2 (балансировщик нагрузки), такой как Traefik.
    Существуют такие подходы, как это и это, чтобы разрешить протоколы, совместимые с HTTP 1.1, но они имеют свои собственные ограничения, такие как ограниченное количество доступных клиентов или необходимые настройки клиента.
person Mike    schedule 28.10.2020