Сегодня мы поговорим об одном из ключевых компонентов в архитектурах микросервисов и веб приложений - API шлюзах. Данные шлюзы являются централизованной точкой входа для управления запросами клиентов и перенаправления их к соответствующим микросервисам или внутренним службам внутри целевой системы.
По сути, API Gateway представляет собой службу, которая находится между клиентами приложения с одной стороны, и внутренними компонентами с другой, действуя как обратный прокси-сервер для приема входящих запросов от клиентов, выполнения различных операций, таких как маршрутизация, аутентификация и ограничение скорости, и последующей пересылки этих запросов соответствующим внутренним службам.
Таким образом, роль API-шлюза в архитектуре программного обеспечения — это находиться перед компонентами реализации и предоставлять необходимые сервисы.
Предоставляемые сервисы
Если более подробно говорить, о каких сервисах идет речь, то это прежде всего сервисы аутентификации и авторизации — те сервисы, которые отвечают за управление доступом к службе, перед которой стоит шлюз. Собственно, для реализации данного функционала могут использоваться различные механизмы, например использование паролей, сертификатов или двухфакторной аутентификации. Также возможна интеграция с сервисами типа межсетевого экрана.
Еще одно предназначение сервисов, предоставляемых API-службами — это защита компонентов целевого приложения от скачков нагрузки. Так, при правильной настройке шлюз API становится единственным способом, с помощью которого клиенты могут получить доступ к службе. Следовательно, механизмы регулирования нагрузки, реализованные здесь, могут обеспечить существенную защиту.
Возвращаясь к вопросам управления доступом, стоит отметить, что сервисы, входящие в состав API-шлюзов, могут также осуществлять ведение журналов доступа, так как весь трафик в службу проходит через шлюз и у нас есть возможность регистрировать весь доступ.
Шлюз API может выполнять свои функции, взаимодействуя со множеством других служб. Например, шлюз сам по себе не хранит данные о пользователях, которые должны быть аутентифицированы и авторизованы. Он зависит от решения, реализующего управление идентификацией и доступом в хранилища учетных записей (например, LDAP) для этих служб, но сам шлюз просто обеспечивает соблюдение изложенной там политики.
В качестве примера можно рассмотреть простой сценарий, в котором шлюз API находится перед парой сервисов, весь доступ к этим сервисам осуществляется через этот шлюз, и он взаимодействует с другими компонентами для поддержки той функциональности, которую он предлагает.
Проблема представленной на рисунке конфигурации API-шлюза заключается в том, что здесь он является единой точкой входа и соответственно, единой точкой отказа. Для современных высокопроизводительных систем такое решение вряд ли приемлемо.
Очевидно, что на практике у нас будет несколько экземпляров каждого сервиса, включая и сам сервис шлюза. Хорошим развитием этого решения является встраивание шлюза в сервис. Такая реализация дает некоторые очевидные преимущества: между шлюзом и самой службой нет транзитного участка сети, который в свою очередь мог стать причиной возможных проблем при передаче трафика между сервисами.
Также, имя хоста для конфигурации нам больше не требуется, а нужен только путь для подключения. Но есть и ряд трудностей, с которыми необходимо разобраться.
Фактически, нам необходимо встроить наш API шлюз в целевые сервисы.
В качестве примера можно рассмотреть решение Netflix Zuul, являющееся частью проекта Netflix Spring Cloud, предназначенного для обеспечения динамической маршрутизации, мониторинга, решения задач безопасности и другого функционала микросервисных приложений.
Про Zuul обычно говорят, что это классический шлюз, основанный на стеке сервлетов, работающий по принципу один запрос – один поток.
Zuul, написан на Java, и очевидно, работает в виртуальной машине Java. Для взаимодействия с сервисами данный шлюз использует URL-адрес. Например, чтобы настроить его в качестве шлюза для абстрактной службы Service, нужно предоставить следующие данные конфигурации:
zuul.routes.connectionService.url=http://localhost:8090/connectionPosts
server.port=8080
Тогда возникает вопрос, как включить Zuul в нашу топологию программного обеспечения. В сильно распределенной архитектуре рекомендуется использовать вариант, близкий к представленному на рисунке.
В случае с Zuul мы можем функционал Spring Cloud, позволяющий встроиться в ваш сервис.
Однако, при использовании шлюза, написанного на Java, мы оказываемся в некоторой зависимости от этого языка программирования, так как получается, что и остальные компоненты сервиса должны быть написаны на этом языке.
Также, одна из целей шаблона API-шлюза состоит в том, чтобы отделить интересы разработчика сервиса от интересов оператора услуг. Вам нужно предоставить операторам возможность применять согласованные элементы управления ко всем работающим службам и предлагать им плоскость управления, которая делает этот процесс управляемым.
Как же тогда добиться чего-то подобного, как этот шаблон шлюза, с помощью способа, который не зависит от языка программирования, более слабосвязанный и управляемый? Здесь нам на помощь приходят сервисные сети.
Сервисные сети Istio
Для того, чтобы избежать недостатков встраиваемого компонента, воспользуемся вспомогательными контейнерами Sidecar. На рисунке ниже мы можем видеть целую группу прокси-серверов Envoy, соединенных через каналы, которые будут осуществлять взаимодействие между ними. Это похоже на сетку; отсюда и название. Сервисная сеть охватывает набор связанных между собой вспомогательных контейнеров (sidecar) и добавляет уровень управления для управления этими прокси-серверами.
Одна из наиболее широко используемых сервисных сеток, доступных сегодня, принадлежит Istio, позволяющий расширить функционал Kubernetes за счет использования модулей Envoy.
Представленная архитектура является важным шаблоном для защиты сервиса от чрезмерной нагрузки, в том числе для трафика, вызванного шквалом повторных отправок запросов. Представленные шаблоны, применяемые как на клиентской, так и на сервисной стороне взаимодействия, могут быть инкапсулированы и развернуты в качестве прокси сервера с помощью сайдкара.
Сервисная сеть дает этому прокси-серверу дополнительную плоскость управления, которая позволяет оператору контролировать безопасность, обеспечивать наблюдаемость и разрешать настройку набора служб/приложений, которые образуют программное обеспечение для облачной среды.
Заключение
В этой статье мы рассмотрели один из шаблонов, предназначенный для размещения на переднем крае службы для обеспечения защиты данной службы от различных скачков нагрузок. Использование данного шаблона позволяет повысить защищенность и управляемость приложения в облачной среде.
Сегодня (16 сентября) в 20:00 пройдет открытый урок «Практическое руководство по применению SOLID принципов». На нем освоим алгоритм применения SOLID принципов для создания гибкого и легко расширяемого кода.
Если актуально — успевайте записаться на урок на странице курса «Архитектура и шаблоны проектирования».