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

Однако, когда впервые пришло время представить некоторые из этих сервисов через Интернет, мы столкнулись с проблемой. Мы поняли, что каждый из них должен уметь решать кучу задач:

  • Принудительный транспорт TLS
  • Аутентификация
  • Контроль доступа
  • Ограничение скорости

Обратите внимание, что эти проблемы характерны только для служб с выходом в Интернет. Для сервисов, которые использовались исключительно из нашего частного облака на AWS, мы были рады просто использовать обычный HTTP для транспорта, не использовать аутентификацию/регулирование и позволить группам безопасности EC2 управлять доступом.

ПО промежуточного слоя приложения

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

Промежуточное программное обеспечение приложения — это функция (или класс, или какая-либо другая языковая конструкция), которая получает изменяемый доступ к HTTP-запросу и ответу в течение жизненного цикла запроса. Один запрос последовательно проходит через цепочку промежуточного программного обеспечения. Таким образом, промежуточное программное обеспечение является мощным компонуемым строительным блоком службы HTTP. Вот почему эта концепция породила целую экосистему плагинов для каждого поддерживающего ее фреймворка (пример). Эти плагины обрабатывают множество вариантов использования, включая те, которые я перечислил ранее.

Ограничение

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

Слои

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

В настоящее время мы используем два слоя промежуточного программного обеспечения:

  • Терминатор TLS
  • Шлюз

Терминатор TLS

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

Для этого можно использовать кучу инструментов.

Шлюз

Он получает запросы по простому HTTP от уровня выше и выполняет множество функций:

  • Маршрутизация. Она отвечает за обнаружение серверной микрослужбы для прокси-сервера. Это основано либо на HTTP-заголовке Host, либо, чаще всего, на URI запроса.
  • Идентификация. Для клиентов с отслеживанием состояния он выдает токены при представлении действительных учетных данных и проверяет токены, отправленные с запросами. Для клиентов без отслеживания состояния он проверяет учетные данные, отправляемые вместе с каждым запросом на защищенную конечную точку серверной службы.
  • Контроль доступа: после того, как их личность определена, он проверяет, разрешен ли клиенту доступ к рассматриваемой конечной точке службы.
  • Ограничение скорости: гарантирует, что авторизованный клиент не злоупотребит службой. Это достигается за счет ограничения количества запросов от клиента в течение небольшого временного окна. В случае с нашим продуктом API это на самом деле первоклассная функция.
  • Балансировка нагрузки. Позволяет серверной службе работать как несколько экземпляров и по-прежнему обслуживаться с одного URI Интернета. В этом случае шлюз отвечает за выбор правильного экземпляра серверной службы для проксирования каждого запроса.

Шлюз обрабатывает каждый из этих вариантов использования на основе правил, с которыми он настроен. Хотя верно то, что каждую из этих функций можно выделить в отдельные слои, мы пока не обнаружили в этом необходимости.

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

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

Почему Слои?

  • Система напоминает конвейер Unix, где каждый уровень берет на себя единственную ответственность, которая для микросервиса (последний уровень) просто управляет своей собственной бизнес-логикой.
  • Разные участники команды могут владеть разными слоями. Например. Авторы серверных сервисов в нашей команде почти полностью абстрагированы от инфраструктуры (слоев), перед которыми стоят их сервисы.
  • Различные слои могут быть написаны на разных языках программирования, что позволяет выбрать правильный инструмент для работы. Если вы запускаете слои промежуточного программного обеспечения из изолированных контейнеров Linux, как это делаем мы, вы также получаете дополнительное преимущество в виде простой замены/обновления слоев.
  • Вы можете масштабировать промежуточное ПО независимо от вашего приложения.
  • Работу многоуровневой системы легче объяснить. Его легче отлаживать и, следовательно, легче поддерживать.

Резюме

Эта система использования промежуточного ПО в качестве слоев до сих пор хорошо нам служила. Мы использовали его в производстве в течение последних нескольких лет для обслуживания различных типов потребителей услуг через Интернет: