Многие софтверные компании решают создавать свои приложения распределенным способом. Такой подход обеспечивает высокую доступность и в конечном итоге увеличивает скорость разработки. Наиболее распространенным архитектурным шаблоном для проектирования распределенных систем являются микросервисы. Архитектура микросервисов заключается в разделении приложения на небольшие автономные службы, каждая из которых играет отдельную роль в общей системе.

Представьте, что ваш клиент хочет создать бюллетень о вакансиях. Продукт должен позволять пользователям размещать предложения о работе и взимать с них небольшую плату за размещение. Он также должен отправлять несколько видов уведомлений по электронной почте. На самом деле это не одно приложение, а веб-страница, а также приложение для iPhone и Android. Первое, что нужно сделать, это решить, какую архитектуру мы выберем.

Преимущества монолитной архитектуры

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

Плюсы:

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

Минусы:

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

Преимущества микросервисов

У микросервисов есть много преимуществ перед монолитной архитектурой (где одно приложение берет на себя ответственность за всю систему). Наиболее важные из них:

  • Нет единой точки отказа. Когда одна служба не работает, пользователи все еще могут использовать приложение. Остальные сервисы все еще работают.
  • Отдельные микросервисы можно масштабировать для увеличения их емкости и доступности.
  • Безопасность - большинство сервисов не подключены к Интернету.
  • Каждую службу можно развернуть независимо от других служб. При условии, что они не нарушают контракты API.

Минусы:

  • Чтобы заложить фундамент, нужно вложить много труда.
  • Процессы развертывания более сложны. Для некоторых развертываний может потребоваться развертывание более одной службы.
  • Тонны работы над DevOps. Особенно при развертывании…
  • Работа с интеграционным тестированием.

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

Разработка микросервисов для приложения публикации вакансий

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

Представьте, что пользователь создает новую учетную запись. Они заходят на сайт, заполняют форму и отправляют запрос в API Gateway. Шлюз API доставляет этот запрос пользовательской службе, которая создает новую учетную запись. После создания учетной записи Служба пользователей отправляет в службу электронной почты запрос на отправку электронного письма для активации. Затем отправляется электронное письмо со ссылкой, которую пользователь должен щелкнуть, чтобы активировать свою учетную запись.

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

Как бороться с тестированием?

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

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

… Иногда часами, серьезно…

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

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

… После нескольких попыток ваша сборка станет зеленой. Вы потратили на это 3 часа, но теперь вы можете объединить свои изменения и предоставить функцию…

Ура! Жизнь хороша!

… К сожалению, кто-то еще что-то слил две минуты назад, поэтому вам нужно объединить эти изменения и снова запустить все тесты…

Контракты, ориентированные на потребителей

Вместо того, чтобы запускать интеграционные тесты между всеми сервисами - избавьтесь от них. Все сервисы обмениваются данными через RESTful API. Это означает, что если мы определим жесткий «контракт» между API, нам не нужно раскручивать всю платформу. Достаточно проверить выполнение требований других сервисов.

Пример кода можно найти на Github.

Как это работает?

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

Какие инструменты использовать?

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

Также можно рассмотреть Дредд.

Что такое потребитель?

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

Что такое провайдер?

Провайдер - это сервис или сервер, который предоставляет данные (например, API на сервере, который предоставляет данные, необходимые клиенту, или сервис, который отправляет сообщения). Инструмент для проверки контрактов с провайдером называется Pact Provider Verifier. Верификатор запускает HTTP-запросы на основе контрактов, созданных потребителем. Если ответ сервера находится в форме, ожидаемой потребителем, тесты проходят.

Если провайдер не оправдывает ожиданий, он терпит неудачу ...

Подождите секунду ... Итак, как доставить контракты всем коллегам?

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

  • репозиторий Git для хранения пактов и их включения в каждый проект с помощью подмодуля git. На мой взгляд, лучший способ сделать это,
  • файловая система.
  • Pact Broker.

Pact Broker - это приложение для обмена контрактами, ориентированными на потребителя, и результатами проверки. Мы можем протолкнуть туда наши контракты и разрешить поставщикам услуг загружать их и проводить с ними тесты.

DiUS предоставляет облачную версию Pact Broker, так что, может быть, вы сможете взглянуть и использовать ее. Я не вижу особых преимуществ в использовании собственного брокера Pact. В конце концов, это еще одна услуга, требующая поддержки со стороны DevOps. Если вы хотите запустить самостоятельно, вот образы Docker.

Я думаю, что достаточно хранить контракты в отдельном репозитории git. Лично я бы создавал их во время конвейера интеграции и запускал тесты поставщиков услуг в рамках одного задания интеграции - пример конвейера интеграции здесь.

Почему не Swagger?

Swagger - это формат определения для документирования API. Он создает интерфейсы для разработки и использования API путем сопоставления всех ресурсов и связанных операций. Вывод понятен людям (через веб-сайты) и машинам (через файлы yaml и json). К сожалению, Swagger не предназначался для тестирования. Мок-серверы, сгенерированные Swagger, не проверяют полезные данные запроса, проверка выполняется внешним интерфейсом.

Это не значит, что вам вообще не следует использовать Swagger, вы можете, и это настоятельно рекомендуется. Если вы работаете с Microservics, очень вероятно, что они разрабатываются многими командами и используются другими командами (иногда внешними командами). Наличие документации, связанной с вашими API, ускоряет разработку, поскольку разработчикам не нужно разбираться в том, как использовать конечные точки. Они могут прочитать его и попробовать на странице документации.

Возможно, вы захотите узнать больше о Swagger Mock Validator; инструмент, который позволяет вам проверять контракты по файлам Swagger.

Резюме

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

Если вас интересуют контракты, ориентированные на потребителей, я настоятельно рекомендую посмотреть доклады Маури Эдо и Бена Сэйерса из Atlassian.

Я решил оставить весь код на моем Github, чтобы статью было легче читать.

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

Вы можете связаться со мной в Medium и Twitter.