Erhalten Sie Zugang zu diesem und mehr als 300000 Büchern ab EUR 5,99 monatlich.
Простые и понятные API — необходимое условие успеха микросервисных приложений. Хорошо продуманные API гарантируют надежную интеграцию сервисов и помогают упростить сопровождение, масштабирование и дальнейшее совершенствование. Познакомьтесь с паттернами, протоколами и стратегиями, которые помогут вам проектировать, реализовывать и развертывать эффективные микросервисы с REST и GraphQL API. Книга наполнена проверенными советами и примерами кода на языке Python. Авторы фокусируются на реализации, а не на философии. Изучите проверенные методы проектирования простых в использовании API для микросервисных приложений. Создавайте надежные API микросервисов, тестируйте, защищайте и развертывайте их в облаке, следуя принципам и шаблонам, применимым в любом языке программирования.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 457
Veröffentlichungsjahr: 2024
Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:
Хосе Антонио Аро Перальта
Микросервисы и API. — СПб.: Питер, 2024.
ISBN 978-5-4461-2094-9
© ООО Издательство "Питер", 2024
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
Дживон, без чьей поддержки и ободрения я бы не смог написать эту книгу, и Айви, которая делает меня счастливым каждый день.
API и микросервисы захватили индустрию программного обеспечения. Под давлением растущей сложности программного обеспечения и необходимости масштабирования все больше организаций переходят от монолитной архитектуры к микросервисной. Отчет O’Reilly «Внедрение микросервисов в 2020 году» показал, что 77 % респондентов внедрили микросервисы, и эта тенденция, как ожидается, и дальше будет расти.
При использовании микросервисов стоит задача интеграции сервисов через API. По данным Nordic APIs, 90 % разработчиков применяют API и тратят 30 % своего времени на их создание1. Внедрение API привело к изменению способа разработки приложений. Сегодня все чаще создаются продукты и сервисы, которые предоставляются исключительно через API, например Twilio и Stripe. Даже такие традиционные отрасли, как банковское дело и страхование, находят новые направления деятельности, открывая свои API и интегрируясь в экосистему Open Banking. Широкое распространение продуктов, направленных на предоставление API, означает, что при разработке собственных приложений мы можем сосредоточиться на основных бизнес-функциях, используя внешние API для решения таких типовых задач, как аутентификация пользователей и рассылка электронной почты.
Быть частью этой растущей экосистемы очень интересно. Однако прежде, чем мы перейдем к микросервисам и API, необходимо понять, как разрабатывать архитектуру микросервисов, проектировать API, как спланировать стратегию развития API, как убедиться в надежности предоставляемых интеграций, как выбрать модель развертывания и защитить наши системы. По моему опыту, большинство организаций сталкиваются с одним или несколькими из этих вопросов, а недавний отчет IBM показал, что 31 % организаций не внедрили микросервисы из-за отсутствия экспертизы внутри компании2. Кроме того, в отчете Postman’s 2022 State of the API говорится, что 14 % респондентов сталкиваются с проблемами API-интеграции 11–25 % времени (http://mng.bz/Xa9v), а по данным Salt Security, 94 % организаций столкнулись с проблемами безопасности API в 2022 году3.
Во многих книгах рассматриваются проблемы, упомянутые в предыдущем абзаце, но обычно авторы делают это с узкоспециальной точки зрения: одни фокусируются на архитектуре, другие — на API, третьи — на безопасности. Мне показалось, что стоит написать книгу, которая объединяет все эти вопросы и рассматривает их с практической точки зрения: по сути, книгу, которая поможет обычному разработчику быстро освоить лучшие практики, принципы и паттерны для проектирования и разработки API микросервисов.
За последние годы я работал с различными клиентами, помогая им проектировать микросервисы и внедрять интеграции посредством API. Работа над этими проектами позволила мне получить представление об основных проблемах, с которыми сталкиваются команды разработчиков при работе с микросервисами и API. Как оказалось, обе технологии обманчиво просты. Хорошо спроектированный API прост в навигации и использовании, а хорошо спроектированные микросервисы повышают производительность разработчиков и легко масштабируются. В то же время плохо спроектированные API подвержены ошибкам и сложны в использовании, а плохо спроектированные микросервисы приводят к появлению так называемых распределенных монолитов.
Возникают очевидные вопросы: как спроектировать хорошие API? И как разработать слабосвязанные микросервисы? Книга поможет вам ответить на эти и другие вопросы. Кроме того, в процессе чтения вы сами будете разрабатывать API и сервисы и узнаете, как сделать их безопасными, как их тестировать и разворачивать. Методы, паттерны и принципы, которые я описываю в книге, стали результатом моего многолетнего опыта, и я очень рад поделиться ими. Надеюсь, эта книга будет для вас ценным источником информации на пути вашего развития как разработчика и архитектора программного обеспечения.
1Simpson J. 20 Impressive API Economy Statistics («20 впечатляющих статистических данных по экономии за счет API»). https://nordicapis.com/20-impressive-api-economy-statistics/.
2 Microservices in the enterprise, 2021: Real benefits, worth the challenges («Микросервисы на предприятии, 2021 год: реальные преимущества, возникающие проблемы»). https://www.ibm.com/downloads/cas/OQG4AJAM.
3 Salt Security. State of API Security Q3 2022 («Состояние безопасности API в III квартале 2022 года»). — P.4. https://content.salt.security/state-api-report.html.
Написание этой книги было одним из самых увлекательных событий в моей карьере, но я не решился бы на это без помощи и поддержки своей семьи и коллег. Книга посвящается моей замечательной жене Дживон, без постоянной поддержки и понимания которой я не смог бы завершить работу, и нашей дочери Айви, которая заботится о том, чтобы мне не пришлось заскучать.
Я благодарю людей, которые предложили идеи для этой книги, помогли мне лучше понять инструменты и протоколы, которые я использую в ней, и предоставили отзывы о черновиках. Особая благодарность Дмитрию Дыгало, Келвину Миксу, Себастьяну Рамиресу Монтаньо, Крису Ричардсону, Джин Янг, Гаджендре Дешпанде, Оскару Исласу, Мехди Меджуи, Бену Хаттону, Андрею Барановскому, Алексу Мистридису, Роупу Хакулинену, Стиву Ардагу-Уолтеру, Катрин Бьеркелунд, Томасу Дину, Марко Антонио Сансу, Винсенту Ванденборну и удивительным разработчикам Ariadne от Mirumee.
С 2020 года я представлял черновики и идеи из книги на различных конференциях, в частности EuroPython, PyCon India, API World, API Specifications Conference, а также на различных подкастах и встречах. Хочу поблагодарить всех, кто посетил мои выступления и дал мне ценную обратную связь. Я также хочу поблагодарить участников моих семинаров на сайте microapis.io за вдумчивые комментарии к книге.
Спасибо моему редактору по закупкам Энди Уолдрону. Энди проделал блестящую работу, помогая мне превратить мое видение книги в реальную рукопись и сфокусировать внимание на актуальных темах. Он также неустанно поддерживал меня в продвижении издания и помог выйти на более широкую аудиторию.
Книга, которую вы держите в руках, легко читается благодаря неоценимой работе моего литературного редактора Марины Майклс. Она проделала огромную работу, помогая мне улучшить стиль письма и направляя меня в нужное русло.
Хочу поблагодарить моего технического редактора Ника Уоттса, который справедливо указывал на многие недостатки и заставлял меня приводить понятные иллюстрации, и моего технического корректора Эла Кринкера, который усердно проверял все листинги и код в репозитории GitHub для этой книги, убеждаясь, что он корректен и выполняется без ошибок.
Спасибо и остальным членам команды Manning, участвовавшим в создании этой книги, включая Кэндис Гиллхулли, Глорию Лукос, Степана Юрековича, Кристофера Кауфмана, Радмилу Эрцеговац, Михаэлу Батинич, Ану Ромак, Айру Дучич, Мелиссу Айс, Элеонору Гарднер, Брекина Эли, Пола Уэллса, Энди Маринковича, Кэти Теннант, Мишель Митчелл, Сэм Вуд, Пола Спратли, Ника Нейсона и Ребекку Райнхарт. Спасибо также Марьян Бейс за то, что поверила в меня и дала этой книге шанс.
Во время работы над книгой у меня была возможность получить подробные и интересные отзывы от самой замечательной группы рецензентов, включая Алена Ломпо, Бьорна Нойхауса, Брайана Миллера, Клиффорда Тербера, Дэвида Паккуда, Дебмалью Джаша, Гаурава Суда, Джорджа Хейнса, Гленна Лео Суонка, Хартмута Пальма, Икечукву Оконкво, Яна Питера Хервейера, Джоуи Смита, Хуана Хименеса, Джастина Баура, Кшиштофа Камычека, Маниша Джайна, Маркуса Янга, Матийса Аффуртита, Матье Эврена, Майкла Брайта, Михаила Рыбинцева, Михала Рутку, Мигеля Монтальво, Нинослава Черкеза, Пьера-Мишеля Анселя, Рафаэля Айкеля, Роберта Кулаговски, Родни Вайса, Самбасиву Андалури, Сатея Кумара Саху, Симеона Лейзерзона, Стивена К. Макунзву, Стюарта Вудворда, Стути Верму и Уильяма Джейми Сильву.
С тех пор как книга попала в MEAP4, я получил множество отзывов и слов поддержки от моих читателей. Мне также посчастливилось пообщаться с читателями, которые активно участвовали в форуме книги на платформе Manning’s liveBook. Я сердечно благодарен всем вам.
Эта книга была бы невозможна без неустанной работы тысяч авторов открытого исходного кода, создавших и поддерживающих удивительные библиотеки, которые я использую в ней. Я очень благодарен всем вам и надеюсь, что моя книга поможет сделать вашу удивительную работу более заметной.
Наконец, благодарю вас, читатель, за то, что вы приобрели экземпляр моей книги. Я могу только надеяться, что вы найдете ее полезной и информативной и получите такое же удовольствие от ее чтения, как я — от ее написания. Я люблю слушать своих читателей и буду рад, если вы поделитесь со мной своими мыслями об издании.
4 Manning Early Access Program — программа издательства Manning по раннему доступу к книгам.
Цель книги — научить вас разрабатывать микросервисы, обеспечивая их интеграцию посредством API. Вы научитесь проектировать микросервисную систему и разрабатывать REST API и GraphQL API для обеспечения взаимодействия между микросервисами. Вы узнаете, как тестировать и валидировать API микросервисов, обеспечивать их безопасность, а также развертывать и эксплуатировать их в облаке.
Книга будет полезна разработчикам программного обеспечения, которые работают с микросервисами и API. В ней используется практический подход, и весь материал иллюстрируется полными примерами кода. Поэтому разработчики, уже работающие с API микросервисов, по достоинству оценят оглавление книги.
Примеры кода приведены на языке Python, однако вам не обязательно его знать, чтобы выполнять их. Перед введением нового кода каждая концепция подробно объясняется.
В книге много внимания уделяется стратегиям проектирования, лучшим практикам и процессам разработки, поэтому она также будет полезна техническим директорам (CTO), архитекторам и вице-президентам по разработкам (VP of engineering), которым необходимо решить, стоит ли их компании внедрять микросервисную архитектуру, или тем, кому необходимо сделать выбор между различными стратегиями разработки API и заставить интеграции работать.
Книга состоит из четырех частей, разделенных на 14 глав.
Часть I знакомит с концепциями микросервисов и API. В ней объясняется, как разработать простой API и спроектировать микросервисную систему.
• В главе 1 вводятся основные понятия книги: микросервисы и API. Из нее вы узнаете, чем микросервисы отличаются от монолитной архитектуры и когда имеет смысл использовать монолит, а не микросервисы. Объясняется, что такое API и как они помогают осуществлять интеграцию микросервисов.
• Глава 2 предлагает пошаговое руководство по реализации простого API с помощью популярного в Python фреймворка FastAPI. Вы научитесь читать спецификацию API и понимать ее требования. Вы также узнаете, как поэтапно создавать API и как тестировать модели валидации данных.
• В главе 3 объясняется, как спроектировать микросервисную систему. В ней описаны три фундаментальных принципа проектирования микросервисов, а также объясняется, как разделить систему на микросервисы, используя декомпозицию по бизнес-функциям и декомпозицию по модулям (поддоменам).
Часть II объясняет, как проектировать, документировать и разрабатывать REST API, а также как разработать микросервис.
• В главе 4 рассматриваются принципы проектирования REST API. В ней представлены шесть ограничений архитектуры REST и модель зрелости Ричардсона, а затем объясняется, как мы используем протокол HTTP для разработки хорошо структурированных и понятных REST API.
• В главе 5 рассказывается, как документировать REST API, используя стандарт спецификации OpenAPI. Вы освоите основы синтаксиса схемы JSON (JSON Schema), узнаете, как определять конечные точки, или эндпоинты (endpoints), моделировать данные и рефакторить документацию с помощью многократно используемых схем.
• В главе 6 объясняется, как создавать REST API с помощью двух популярных фреймворков Python: FastAPI и Flask. Вы прочтете о различиях между ними и узнаете, что принципы и модели построения API остаются неизменными и выходят за рамки деталей реализации любого технического стека.
• В главе 7 приводятся фундаментальные принципы и паттерны для построения микросервисов. В ней описана концепция гексагональной архитектуры и объясняется, как обеспечить слабую связанность между уровнями приложения. Вы также узнаете, как реализовать модели баз данных с помощью ORM SQLAlchemy и как управлять миграциями баз данных с помощью Alembic.
В части III объясняется, как проектировать, использовать и разрабатывать GraphQL API.
• В главе 8 рассказывается, как разрабатывать GraphQL API и как использовать Schema Definition Language (SDL). В ней описываются стандартные типы GraphQL, а также объясняется, как определить кастомные типы. Вы узнаете, как создавать связи между типами и писать запросы и мутации.
• В главе 9 мы поговорим о том, как использовать GraphQL API. Вы узнаете, как запустить mock-сервер и изучить документацию GraphQL с помощью GraphiQL. Вы научитесь отправлять запросы и мутации на сервер GraphQL и при этом использовать параметры.
• В главе 10 рассказывается о том, как создавать GraphQL API с помощью Python фреймворка Ariadne. Вы научитесь использовать документацию API для автоматической загрузки моделей валидации данных, а также создавать резольверы для кастомных типов, запросов и мутаций.
В части IV объясняется, как тестировать, делать безопасным и развертывать API микросервисов.
• В главе 11 вы узнаете, как добавить аутентификацию и авторизацию в ваши API с помощью стандартных протоколов, таких как OpenID Connect (OIDC) и Open Authorization (OAuth) 2.1. Мы обсудим, как создавать и валидировать JSON Web Tokens (JWT) и как разработать слой авторизации для ваших API.
• В главе 12 рассказывается о том, как тестировать и валидировать API. Вы узнаете, что такое тестирование на основе свойств (property-based testing, PBT) и как использовать его для проверки API, а также научитесь работать с фреймворками для автотестирования, в частности Dredd и schemathesis.
• В главе 13 объясняется, как упаковать микросервисы в Docker-контейнеры, запускать их локально с помощью Docker Compose и как публиковать Docker-образы в AWS Elastic Container Registry (ECR).
• В главе 14 мы обсудим развертывание микросервисов в облаке AWS с помощью Kubernetes. Вы узнаете, как создать кластер Kubernetes и управлять им с помощью Elastic Kubernetes Service AWS, как запустить бессерверную базу данных Aurora в защищенной сети, как безопасно развернуть конфиг-файл приложения с помощью шифрования по схеме envelope encryption и как развернуть сервисы с возможностью последующего масштабирования.
На протяжении всех глав мы будем работать над созданием компонентов для вымышленной платформы доставки кофе, которая называется CoffeeMesh. В главе 1 приводится вводная информация о CoffeeMesh, а в главе 3 описывается, как разделить платформу на микросервисы. Поэтому я рекомендую прочитать главы 1 и 3, чтобы лучше понять примеры, приведенные в последующих главах. В остальном все части независимы и все главы самодостаточны. Например, если вы хотите узнать, как проектировать и разрабатывать REST API, можете сразу перейти к части II, а если вас интересует GraphQL API, можете сосредоточиться на части III. Точно так же, если вы хотите научиться добавлять аутентификацию и авторизацию в ваши API, переходите к главе 11 или, если хотите научиться тестировать API, вам в помощь глава 12.
В книге приводится множество примеров исходного кода как в нумерованных листингах, так и отдельными строками. В обоих случаях исходный код оформляется шрифтом фиксированной ширины, какздесь, чтобы отделить его от обычного текста. Иногда код также выделяется жирнымшрифтом — так оформлен код, который изменился по сравнению с тем, что приводился ранее в главе.
Во многих случаях исходный код был переформатирован; мы добавили переносы строк и изменили отступы, чтобы уместить его на странице. В некоторых случаях и этого было недостаточно, и в листинги добавлялись знаки переноса строк (➥). Кроме того, комментарии в исходном коде удалены из листингов, если код описывается в тексте. Многие листинги сопровождаются выносками — в них подчеркиваются важные моменты.
Почти все главы (за исключением 1, 3 и 4-й) наполнены примерами кода, которые иллюстрируют каждую новую описанную концепцию или паттерн. Большинство примеров написаны на Python, за исключением кода для глав 5, 8 и 9, посвященных проектированию API, — они содержат примеры в формате схем OpenAPI/JSON Schema (см. главу 5) и Schema Definition Language (см. главы 8 и 9). Весь код подробно объясняется, поэтому он должен быть понятен всем читателям, в том числе тем, кто не знает Python.
Полный код примеров, приведенных в книге, можно загрузить из репозитория GitHub, посвященного этой книге, по адресу https://github.com/abunuwas/microservice-apis. Для каждой главы в репозитории GitHub создана папка, например ch02 для главы 2. Если не указано иное, все ссылки на файлы в главе относятся к соответствующей папке на GitHub. Например, в главе 2 файл orders/app.py соответствует файлу ch02/orders/app.py на GitHub.
В репозитории GitHub приводится финальный код для каждой главы. В некоторых главах постепенно показывается, как создавать функции. В этих случаях код, который представлен на GitHub, соответствует окончательной версии кода для главы.
Примеры кода на Python, приведенные в книге, были протестированы на Python 3.10, хотя любая версия Python, начиная с 3.7, должна работать точно так же. Код и команды, которые я использую в книге, были протестированы на машине Mac, но они должны без проблем работать и в Windows и Linux. Если вы работаете в Windows, рекомендую использовать POSIX-совместимый терминал, например Cygwin.
На протяжении работы над главами для управления зависимостями я задействовал Pipenv. В папке каждой главы вы найдете файлы Pipfile и Pipfile.lock, где описываются точные версии зависимостей, которые я использовал для выполнения примеров кода. Чтобы избежать проблем при запуске кода, в начале изучения каждой главы вам стоит загрузить эти файлы и установить зависимости из них.
Если вы хотите узнать больше об API микросервисов, загляните в мой блог https://microapis.io/blog, где собраны ресурсы, дополняющие уроки этой книги. Там же я поддерживаю актуальный список своих практикумов и семинаров — они также дополняют эту книгу.
Хосе Антонио Аро Перальта — консультант по программному обеспечению и архитектуре. Имея более чем десятилетний опыт работы, Хосе помогал крупным и небольшим организациям строить сложные системы, создавать микросервисные системы и обеспечивать интеграцию с помощью API. Он также является основателем компании microapis.io, предоставляющей услуги по консультированию и обучению в области программного обеспечения. Будучи авторитетным экспертом в сфере облачных вычислений, DevOps и автоматизации программного обеспечения, Хосе регулярно выступает на международных конференциях и часто организует открытые мастер-классы.
Рисунок на обложке озаглавлен L’invalide, или «Инвалид», и изображает раненого французского солдата, который проживал в Hôtel national des Invalides — Национальном доме инвалидов. Это изображение взято из коллекции Жака Грассе де Сен-Совера, опубликованной в 1797 году. Каждая иллюстрация в коллекции тщательно прорисована и раскрашена вручную.
В те времена по одежде человека можно было легко определить, где он живет, чем занимается и какое положение в обществе имеет.
Сегодня, когда сложно отличить одну компьютерную книгу от другой, издательство Manning приветствует изобретательность и новаторство компьютерного бизнеса с помощью обложек, отражающих богатое разнообразие региональной жизни многовековой давности, о котором нам напоминают картины Грассе де Сен-Совера.
Александр Петраки — старший инженер-разработчик КРОК, занимается проектированием архитектуры высоконагруженных приложений и выполняет реализацию backend-части на Java, Spring с применением СУБД Mysql, PostgreSQL, Oracle, JanusGraph.
Анатолий Смирнов — технический менеджер. Организует разработку новых систем и модулей к ним, а также руководит проектами по технической поддержке ранее разработанных информационных систем.
Ваши замечания, предложения, вопросы отправляйте по адресу [email protected] (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.
Мы выражаем огромную благодарность компании «КРОК» за помощь в работе над русскоязычным изданием книги и за их вклад в повышение качества переводной литературы.
Микросервисы — это архитектурный стиль программного обеспечения, в котором компоненты системы проектируются как отдельные и независимо развертываемые приложения. Концепция микросервисов существует с начала 2000-х годов, а с 2010-х активно набирает популярность. Сегодня микросервисы все чаще выбирают для создания современных веб-приложений. Как вы узнаете из главы 1, микросервисы позволяют использовать возможности распределенных приложений, легче масштабировать компоненты и быстрее выпускать релизы приложения.
Однако при всех своих преимуществах микросервисы имеют и недостатки. Они повышают издержки на инфраструктуру, их сложнее мониторить, ими сложнее управлять и сложнее выполнять их отладку. При работе с микросервисами основной задачей становится их правильное проектирование, и в главе 3 вы узнаете несколько принципов и стратегий, которые помогут вам создавать надежные микросервисы.
Микросервисы взаимодействуют через API, и в этой книге вы научитесь проектировать и разрабатывать REST и GraphQL API для своих микросервисов. Глава 2 даст вам представление о создании REST API, а в части II вы узнаете о различных паттернах и принципах создания надежных REST API. Сложнее всего при работе с API обеспечить, чтобы и клиент, и сервер следовали одной спецификации API. В главе 1 вы узнаете о разработке через документирование (documentation-driven development, DDD) и о том, как важно начинать путь к API с хорошо документированного проекта.
В части I вы прочтете об основополагающих паттернах и принципах создания микросервисов и их интеграции через API. В остальных частях мы будем опираться на концепции, описанные здесь, и вы узнаете, как создавать надежные API, как их тестировать, защищать и как развертывать ваши микросервисы в облаке. Наше захватывающее путешествие вот-вот начнется!
В этой главе
• Что такое микросервисы и чем они отличаются от монолитных приложений.
• Что такое веб-API и как они помогают осуществлять интеграцию между микросервисами.
• Наиболее важные задачи при разработке и эксплуатации микросервисов.
В этой главе дается определение наиболее важных понятий книги: микросервисов и API. Микросервисы — это архитектурный стиль, в котором компоненты системы проектируются как независимо развертываемые сервисы, а API — интерфейсы, позволяющие нам взаимодействовать с этими сервисами. Мы рассмотрим важные особенности микросервисной архитектуры и сравним ее с архитектурой монолитных приложений, которые строятся на основе единой кодовой базы и развертываются в виде единой сборки.
Мы обсудим преимущества и недостатки микросервисной архитектуры. В конце главы речь пойдет о проблемах, которые возникают при проектировании, внедрении и эксплуатации микросервисов. Все это я расскажу не для того, чтобы отговорить вас от внедрения микросервисов, а для того, чтобы вы могли принять взвешенное решение, подходят ли микросервисы именно для вас.
В этом разделе мы определим, что такое микросервисная архитектура, и проанализируем, чем микросервисы отличаются от монолитных приложений. Рассмотрим преимущества и недостатки каждого архитектурного стиля. Наконец, мы также бегло вспомним исторические события, которые привели к появлению современной микросервисной архитектуры.
Итак, что же такое микросервисы? Микросервисы можно определить по-разному, и в зависимости от того, какой аспект архитектуры мы хотим подчеркнуть, авторы дают немного различающиеся, но связанные между собой определения этого термина. Сэм Ньюман, один из самых известных авторов, пишущих о микросервисах, дает лаконичное определение: «Микросервисы — это небольшие, автономные, совместно работающие сервисы»5.
Определение подчеркивает тот факт, что микросервисы — это приложения, которые работают независимо друг от друга, но могут взаимодействовать при выполнении своих задач. В определении также подчеркивается, что микросервисы «небольшие». В данном контексте «небольшой» относится не к размеру кодовой базы, а к идее, что микросервисы — это приложения с узкой и четко определенной областью применения, следующие принципу единственной ответственности — делать что-то одно, причем хорошо.
В основополагающей статье Джеймса Льюиса и Мартина Фаулера дается более подробное определение. Они характеризуют микросервисы как архитектурный стиль с «подходом к разработке одного приложения в виде набора небольших сервисов, каждый из которых выполняется отдельно и которые взаимодействуют с помощью упрощенных механизмов, часто с использованием ресурсов HTTP API» (https://martinfowler.com/articles/microservices.html). Это определение подчеркивает автономность сервисов, утверждая, что они выполняются в виде отдельных процессов. Льюис и Фаулер также отмечают, что микросервисы имеют узкий функционал, говоря, что они небольшие, и четко описывают, как микросервисы обмениваются информацией с помощью таких протоколов, как HTTP.
ОПРЕДЕЛЕНИЕ
Микросервис — это архитектурный стиль, в котором компоненты системы проектируются как независимо развертываемые сервисы. Микросервисы проектируются под четко обозначенные бизнес-функции в определенных модулях (поддоменах) и взаимодействуют друг с другом с помощью простых протоколов, таких как HTTP.
Из приведенных определений видно, что микросервисы можно охарактеризовать как архитектурный стиль, в котором сервисы — это компоненты, выполняющие небольшой и четко определенный набор связанных функций. Как видно на рис. 1.1, это означает, что микросервис проектируется и строится вокруг конкретной бизнес-задачи, например обработки платежей, отправки электронной почты или обработки заказов от покупателей.
Рис. 1.1. В микросервисной архитектуре каждый сервис выполняет определенную бизнес-функцию и развертывается как независимый компонент, который выполняется в собственном процессе
Микросервисы развертываются как независимые процессы, обычно работающие в независимых средах, и предоставляют свой функционал через четко определенные интерфейсы. В книге вы научитесь создавать микросервисы, которые работают через веб-API, хотя возможны и другие типы интерфейсов, например очереди сообщений6.
Теперь, когда мы знаем, что такое микросервисы, посмотрим, как они соотносятся с монолитной архитектурой приложений. В отличие от микросервисов монолит — это система, в которой вся функциональность развертывается в виде единой сборки и выполняется в одном процессе. Например, на рис. 1.2 показано приложение для доставки еды с четырьмя сервисами: оплаты, заказов, доставки и поддержки покупателей. Поскольку приложение реализовано как монолит, все функциональные возможности развертываются вместе. Мы можем запустить несколько экземпляров монолитного приложения и заставить их работать параллельно для обеспечения избыточности и масштабируемости, но в каждом процессе все равно будет работать целое приложение.
Рис. 1.2. В монолитном приложении вся функциональность развертывается вместе в виде единой сборки на каждом сервере
ОПРЕДЕЛЕНИЕ
Монолит — это архитектурный паттерн, в котором все приложение развертывается в виде единой сборки.
Монолит стоит выбирать, когда кодовая база невелика и предполагается, что она сильно не разрастется7. Монолиты имеют свои преимущества. Во-первых, наличие всей реализации в единой кодовой базе облегчает доступ к данным и бизнес-функциям из различных модулей. А поскольку все выполняется в рамках одного процесса, легко отследить ошибки в приложении: достаточно добавить несколько точек останова в разных частях кода, и вы получите подробную картину того, что происходит, когда что-то идет не так. Кроме того, поскольку весь код находится в рамках одного проекта, вы можете использовать инструменты повышения производительности в своей любимой среде разработки при работе с бизнес-логикой приложения из различных модулей.
Однако по мере роста и усложнения приложения у данного типа архитектуры проявляются ограничения. Это происходит, когда кодовая база увеличивается до такой степени, что ею становится трудно управлять, а поиск в коде оказывается сложной задачей. Кроме того, возможность повторного использования кода из других модулей в рамках одного проекта часто приводит к сильной связанности (tight coupling) между компонентами. Сильная связанность возникает, когда компонент зависит от деталей реализации другого фрагмента кода.
Чем больше монолит, тем больше времени требуется для его тестирования. Каждую часть монолита необходимо протестировать, и по мере добавления новых функций набор тестов увеличивается. Следовательно, развертывание становится медленнее и разработчикам приходится накапливать изменения в рамках одного релиза, что делает релизы более сложными. Поскольку многие изменения выпускаются вместе, то, если в релизе появляется новая ошибка, часто бывает трудно определить, какое именно изменение ее вызвало, и откатить его назад. А поскольку все приложение работает в рамках одного процесса, при масштабировании ресурсов для одного компонента требуется масштабирование всего приложения. Короче говоря, изменения кода оказываются все более рискованными, а управлять развертыванием становится все сложнее. Как микросервисы могут помочь решить эти проблемы?
Микросервисы помогают нам благодаря жестким границам, разделяющим компоненты. Когда вы реализуете приложение с использованием микросервисов, каждый микросервис работает в отдельном процессе (часто на разных серверах или виртуальных машинах) и может иметь любую модель развертывания. Фактически микросервисы могут быть написаны на совершенно разных языках программирования (но это не значит, что так и должно быть!).
Поскольку у микросервисов кодовая база меньше, чем у монолита, и их логика ограничена и определена в рамках конкретной бизнес-задачи, их легче тестировать и их наборы тестов выполняются быстрее. Микросервисы не зависят от других компонентов платформы на уровне кода (за исключением, возможно, некоторых общих библиотек), их код понятнее, и их легче рефакторить. Это означает, что со временем код может улучшаться и становиться более удобным для поддержки. Следовательно, мы можем вносить небольшие изменения в код и выпускать его чаще. Маленькие релизы более управляемы, и, если обнаружится ошибка, их легче откатить назад. Но я хотел бы подчеркнуть, что микросервисы — это не панацея. Как вы увидите в разделе 1.3, они также имеют ограничения и создают свои проблемы.
Теперь, разобравшись, что такое микросервисы и чем они отличаются от монолитных приложений, сделаем шаг назад и посмотрим, какие события привели к появлению этого типа архитектуры.
Во многих отношениях микросервисы не новинка8. Компании внедряли и развертывали компоненты в виде независимых приложений задолго до того, как стала популярной концепция микросервисов. Они просто не называли это микросервисами. Вернер Фогельс, технический директор компании Amazon, рассказывает, что Amazon начала экспериментировать с этим типом архитектуры в начале 2000-х годов. К тому времени кодовая база сайта Amazon превратилась в сложную систему без четкой архитектурной схемы, а выпуск новых релизов и масштабирование системы стали серьезными проблемами. Для их решения они начали искать независимые части логики в коде и разделять их на независимо развертываемые компоненты, сопровождая их API. В рамках этого процесса в компании также определили данные, принадлежащие этим компонентам, и убедились, что другие части системы не могут получить доступ к этим данным иначе как через API. Они назвали этот новый тип архитектуры сервис-ориентированной архитектурой (https://vimeo.com/29719577). Компания Netflix также стала пионером в создании архитектурного стиля такого масштаба, и они назвали его «детальной сервис-ориентированной архитектурой» (fine-grained service oriented architecture) 9.
Для описания этого типа архитектуры термин «микросервис» стали активно употреблять в начале 2010-х годов. Например, Джеймс Льюис использовал это понятие на конференции в Кракове в 2012 году в презентации под названием Micro-Services — Java, the Unix way («Микросервисы — Java, путь Unix») (https://vimeo.com/74452550). В 2014 году концепция была закреплена статьей Мартина Фаулера и Джеймса Льюиса об архитектурных особенностях микросервисов (https://martinfowler.com/articles/microservices.html), а также публикацией известной книги Сэма Ньюмана «Создание микросервисов».
Сегодня микросервисы — это широко распространенный архитектурный стиль. Очень многие компании уже используют микросервисы или движутся в направлении их внедрения. Однако микросервисы подходят не всем и, несмотря на множество существенных преимуществ, также могут привести к значительным проблемам, о чем вы узнаете в разделе 1.3.
В этом разделе мы поговорим о веб-API. Вы узнаете, что это конкретный пример более общего интерфейса прикладного программирования (API). Важно понимать, что API — это просто слой поверх приложения и что существуют различные типы интерфейсов. Начнем с определения API, а затем обсудим, как API позволяют нам интегрировать микросервисы.
API — это интерфейс, который позволяет нам программно взаимодействовать с приложением. Программные интерфейсы мы можем использовать из нашего кода или терминала — в этом их отличие от графических, в которых пользовательский интерфейс предназначен для взаимодействия с приложением. Существует несколько типов интерфейсов приложений: интерфейсы командной строки (CLI; позволяют использовать приложение из терминала), пользовательские интерфейсы (UI) для настольных компьютеров, пользовательские интерфейсы (UI) для веб-приложений или веб-API. Как показано на рис. 1.3, приложение может иметь один или несколько таких интерфейсов.
Рис. 1.3. Приложение может иметь несколько интерфейсов
Для иллюстрации этой идеи вспомните популярную утилиту cURL (client URL). cURL — это интерфейс командной строки для библиотеки libcurl, которая реализует функциональность, позволяющую нам взаимодействовать с URL-адресами, в то время как cURL раскрывает эти возможности через CLI. Например, мы можем использовать cURL для отправки GET-запроса на URL:
$ curl -L http://www.google.com
Мы также можем использовать cURL с флагом -O, чтобы загрузить содержимое URL в файл:
$ curl -O http://www.gnu.org/software/gettext/manual/gettext.html
Библиотека libcurl скрыта за интерфейсом командной строки cURL, и ничто не мешает нам получить к ней прямой доступ через исходный код (если вам интересно, можете взять его с Github: https://github.com/curl/curl) и создать для нее дополнительные типы интерфейсов.
Теперь, когда мы поняли, что такое API, перейдем к описанию веб-API. Веб-API — это API, который для передачи данных использует HyperText Transfer Protocol (HTTP). HTTP — это протокол связи, лежащий в основе Интернета и позволяющий нам обмениваться по сети различными типами данных (текстом, изображениями, видео и данными в формате JSON10). HTTP использует понятие Унифицированного указателя ресурса (Uniform Resource Locator, URL) для определения ресурсов в Интернете, а также предоставляет возможности, которые могут быть использованы при разработке API для улучшения взаимодействия с сервером, например методы запроса (GET, POST, PUT) и HTTP-заголовки. Веб-API реализуются с помощью таких технологий, как SOAP, REST, GraphQL, gRPC и других, которые подробно рассматриваются в приложении A.
Микросервисы взаимодействуют друг с другом через API, поэтому API по сути являются интерфейсами к микросервисам. Эти интерфейсы документируются с использованием стандартных протоколов. Документация API точно указывает нам, что нужно сделать для взаимодействия с микросервисом и каких ответов мы можем от него ожидать. Чем лучше документирован API, тем понятнее разработчикам клиентских приложений, как он работает. В этом смысле документацию API можно представить как контракт между сервисами (рис. 1.4).
Фаулер и Льюис популяризировали идею о том, что наилучшей стратегией интеграции микросервисов является создание умных эндпоинтов (smart endpoints) и взаимодействие через глупые каналы (dumb pipes) (https://martinfowler.com/articles/microservices.html). В основе этой идеи лежат принципы проектирования Unix-систем, которые устанавливают, что:
• система должна состоять из небольших независимых компонентов, которые выполняют только одну задачу;
• выходные данные для каждого компонента должны быть спроектированы таким образом, чтобы они могли легко стать входными данными для другого компонента.
Рис. 1.4. Спецификация API представляет собой контракт между сервером и клиентом. Пока клиент и сервер следуют спецификации API, коммуникация будет происходить так, как ожидается
Программы Unix взаимодействуют друг с другом с помощью конвейеров, которые представляют собой простые механизмы передачи сообщений от одного приложения к другому. Чтобы проиллюстрировать этот процесс, вспомните цепочку команд, которую можно запустить с терминала машины на базе Unix (например, компьютера с Mac или Linux):
$ history | less
Команда history выводит список всех команд, которые вы выполняли из профиля Bash. Список может быть длинным, поэтому можно разбить вывод истории на страницы с помощью команды less. Чтобы передать данные от одной команды к другой, используйте символ вертикальной черты (|), который дает оболочке команду перехватить вывод history и передать его на вход less. Мы говорим, что этот тип канала глупый, потому что его единственная задача — передача сообщений от одного процесса к другому.
Как показано на рис. 1.5, веб-API обмениваются данными через HTTP. На транспортном уровне передачи данных ничего не известно о конкретном протоколе API, который мы используем, поэтому он представляет собой наш глупый канал, в то время как сам API содержит всю необходимую логику для обработки данных.
API не должны изменяться, при этом вы можете изменять внутреннюю логику работы сервиса при условии, что она соответствует документации API. Это означает, что покупатели, взаимодействующие с API, должны иметь возможность продолжить обращаться к API точно так же, как и раньше, и получать при этом те же ответы. Это приводит к еще одной важной концепции в микросервисной архитектуре: заменяемости (replaceability)11. Идея заключается в том, что вы должны иметь возможность полностью заменить код, который скрыт за эндпоинтом, но при этом эндпоинт останется доступным, а значит и взаимодействие между сервисами не нарушится. Теперь, когда вы понимаете, что такое API и как эти интерфейсы помогают осуществлять интеграцию сервисов, рассмотрим наиболее важные проблемы, возникающие при создании микросервисов.
Рис. 1.5. Микросервисы взаимодействуют через API, используя транспортный уровень передачи данных, такой как HTTP-over-TCP
Как вы видели в подразделе 1.1.2, микросервисы дают существенные преимущества. Однако их использование также сопряжено со значительными трудностями. В этом разделе мы обсудим наиболее важные проблемы, которые я разделил на пять основных категорий, таких как:
• оптимальная декомпозиция сервиса;
• интеграционные тесты микросервисов;
• обработка недоступности сервиса;
• трассировка распределенных транзакций;
• повышение сложности эксплуатации и накладных расходов на инфраструктуру.
Все проблемы и трудности, которые мы обсуждаем в этом разделе, можно решить с помощью конкретных паттернов и стратегий — часть из них подробно описана в книге. Вы также найдете ссылки на другие ресурсы, где рассматриваются эти вопросы. Главное, чтобы вы понимали, что микросервисы не являются панацеей от всех проблем, с которыми сталкиваются монолитные приложения.
Одна из самых важных задач при проектировании микросервисов — это декомпозиция системы. Мы должны разбить систему на слабо связанные, но достаточно независимые компоненты с четко заданными границами. Вы можете выявить нецелесообразную связь между сервисами, если всякий раз, когда вы меняете один сервис, приходится менять и другой. Это означает, что либо между сервисами неустоявшиеся правила обмена, либо оба компонента достаточно зависимы друг от друга, чтобы можно было объединить их в один. Неспособность разбить систему на независимые микросервисы может означать то, что Крис Ричардсон, автор книги «Микросервисы. Паттерны разработки и рефакторинга», называет распределенным монолитом, — решение, когда вы объединяете все проблемы монолитной и микросервисной архитектур и не получаете при этом преимуществ ни от одной из них. В главе 3 вы узнаете, какие паттерны проектирования и стратегии декомпозиции сервисов могут помочь разбить систему на микросервисы.
В подразделе 1.1.2 мы говорили, что микросервисы обычно легче тестировать, и их наборы тестов выполняются быстрее. Однако интеграционные тесты микросервисов могут быть значительно сложнее, особенно в тех случаях, когда для выполнения одной транзакции требуется взаимодействие нескольких микросервисов. Когда все ваше приложение работает в рамках одного процесса, тестировать интеграцию между различными компонентами довольно легко, и для этого в основном требуются хорошо написанные модульные тесты. В контексте микросервисов для тестирования интеграции между несколькими сервисами необходимо иметь возможность запускать их все с параметрами, как в продакшен-окружении.
Для тестирования интеграции микросервисов можно использовать различные стратегии. В первую очередь нужно убедиться, что каждый сервис имеет хорошо документированный и правильно реализованный API. Вы можете проверить реализацию API на соответствие спецификации с помощью таких инструментов, как Dredd и Schemathesis, которые мы рассмотрим в главе 12. Вы также должны убедиться, что клиент использует API именно так, как предписано его документацией. Для этого вы можете написать модульные тесты для клиента, сгенерировав по документации API ответы от сервиса12. Но ни один из этих тестов не будет достаточным без полноценного сквозного тестирования (end-to-end, e2e-тестирование), при котором запускаются реальные микросервисы, отправляющие запросы друг другу.
Необходимо убедиться, что приложения устойчивы к недоступности сервисов, тайм-аутам подключений и запросов, ошибочным запросам и т.д. Например, когда мы размещаем заказ через приложение доставки еды, такое как Uber Eats, Delivery Hero или Deliveroo, запускается цепочка запросов между сервисами для обработки и доставки заказа, и любой из этих запросов может завершиться неудачей. Рассмотрим процесс, который происходит, когда пользователь размещает заказ (см. рис. 1.6 для иллюстрации цепочки запросов).
1. Покупатель размещает заказ и оплачивает его. Заказ размещается с помощью сервиса заказов, а для обработки платежа тот взаимодействует с сервисом платежей.
2. Если оплата прошла успешно, сервис заказов делает запрос в сервис кухни для постановки в очередь заказа на приготовление.
3. После приготовления заказа сервис кухни делает запрос в сервис доставки, чтобы запланировать доставку.
Рис. 1.6. Микросервисы должны быть устойчивы к таким событиям, как недоступность сервиса, тайм-аут запроса и ошибки обработки, полученные от других сервисов, и либо повторно выполнять запросы, либо выдавать пользователю понятный ответ
Если в столь сложной цепочке запросов один из используемых сервисов не ответит так, как ожидалось, это может вызвать каскадный отказ в приложении, при котором заказ останется или необработанным, или в неопределенном состоянии. Поэтому важно спроектировать микросервисы таким образом, чтобы они могли надежно работать с отказавшими эндпоинтами. Тесты end-to-end должны учитывать эти сценарии и проверять поведение сервисов в таких ситуациях.
Взаимодействующим сервисам иногда приходится обрабатывать распределенные транзакции. Например, в приложении для доставки еды нужно отслеживать имеющиеся запасы ингредиентов, чтобы ассортимент был актуальным. Когда пользователь делает заказ, нам нужно обновить запас ингредиентов, чтобы актуализировать ассортимент в приложении. В частности, следует обновлять запас ингредиентов сразу после успешной обработки платежа. Как показано на рис. 1.7, успешная обработка заказа включает в себя следующие действия.
1. Обработать платеж.
2. Если оплата прошла успешно, обновить статус заказа, чтобы указать, что он находится в процессе выполнения.
3. Связаться с сервисом кухни, чтобы поставить заказ в очередь на приготовление.
4. Обновить запас ингредиентов, чтобы отразить их наличие на текущий момент.
Рис. 1.7. Распределенная транзакция подразумевает взаимодействие между несколькими сервисами. Если какой-либо из них отказывает, то эта ситуация должна быть обработана и пользователю должен быть предоставлен понятный ответ
Все эти операции связаны между собой и должны быть управляемы таким образом, что все либо должны успешно выполниться вместе, либо завершиться отказом. Мы не можем оплатить заказ без корректного обновления его статуса, и мы не должны отправлять его на приготовление, если оплата не прошла. Можно изменить информацию о наличии запаса ингредиентов во время создания заказа, но если впоследствии платеж не пройдет, мы должны убедиться, что откатили это изменение. Если все эти действия происходят в рамках одного процесса, то управление потоком простое, но при использовании микросервисов приходится управлять результатами различных процессов. В таком случае важно обеспечить надежный процесс взаимодействия между сервисами, чтобы мы точно знали, какая ошибка когда возникает, и принимали соответствующие меры.
Если какие-то сервисы совместно обрабатывают определенные запросы, также нужно иметь возможность трассировать путь прохождения запроса через различные сервисы, чтобы выявлять ошибки во время транзакции. Для мониторинга распределенных транзакций необходимо настроить распределенное логирование и трассировку ваших микросервисов. Вы можете узнать больше об этой теме из книги Джейми Ридесела Software Telemetry: Reliable logging and monitoring (Manning, 2021).
Еще одна важная проблема, возникающая при использовании микросервисов, — это повышенная сложность управления и увеличение накладных расходов для вашей платформы. Когда весь бэкенд вашего сайта работает в рамках одной сборки приложения, вам нужно развернуть и мониторить только один процесс. Когда у вас дюжина микросервисов, каждый должен быть настроен, развернут и управляем. И это подразумевает не только выделение серверов для развертывания сервисов, но и управление потоками агрегации логов, настройку систем мониторинга, настройку оповещений, механизмов автоматического восстановления и т.д. Как вы узнаете в главе 3, у каждого сервиса есть собственная база данных, а значит, им также требуется несколько инсталляций баз данных со всеми функциями, необходимыми для масштабирования. И вполне обычна ситуация, когда при новом развертывании меняется эндпоинт микросервиса, будь то IP, базовый URL или конкретный путь в полном URL, а это означает, что об изменениях нужно уведомить покупателей.
Когда компания Amazon только начала переходить к микросервисной архитектуре, обнаружилось, что команды разработчиков тратят около 70 % своего времени на управление инфраструктурой (https://vimeo.com/29719577, 07:53). Такое вполне вероятно может произойти, если вы с самого начала не внедряете лучшие практики по автоматизации инфраструктуры. И даже если вы это сделаете, вам, скорее всего, придется потратить много времени на разработку собственных утилит для эффективного управления вашими сервисами.
Как пояснялось в подразделе 1.2.3, успех интеграции с помощью API зависит от хорошей документации API, и в этом разделе мы познакомимся с процессом разработки API, при котором документация первична. Как показано на рис. 1.8, разработка через документирование — это подход к разработке API, который состоит из трех этапов.
1. Проектирование и документирование API.
2. Разработка клиентской и серверной части в соответствии с документацией.
3. Тестирование клиента и сервера на соответствие документации.
Рис. 1.8. Разработка через документирование состоит из трех этапов: проектирования и документирования, разработки и валидации
Рассмотрим каждый из этих пунктов. Первый шаг включает в себя проектирование и написание спецификации. Мы разрабатываем API для кого-то, поэтому перед этим должны спроектировать API, который отвечает потребностям разработчиков клиентской части. Точно так же, как мы привлекаем пользователей к проектированию пользовательского интерфейса приложения (UI), мы должны привлекать разработчиков клиентских сервисов к проектированию API.
Хороший дизайн API удобен при разработке, а хорошая документация API способствует успешной интеграции. Что такое документация API? Это описание API в соответствии с языком описания интерфейсов (interface description language, IDL), таким как OpenAPI для REST API и Schema Definition Language (SDL) для GraphQL API. Стандартные IDL имеют экосистемы инструментов и фреймворков, которые облегчают разработку, тестирование и визуализацию API, поэтому стоит потратить время на их изучение. В этой книге вы научитесь документировать API с помощью OpenAPI (см. главу 5) и SDL (см. главу 8).
Создав документацию на спроектированный API, мы переходим ко второму этапу — к созданию сервера и клиента на ее основе. В главах 2 и 6 вы научитесь анализировать требования спецификации OpenAPI и разрабатывать на их основе приложение, а в главе 10 мы применим тот же подход к GraphQL API. Разработчики API клиентов могут также использовать документацию API для запуска mock-серверов и тестирования на них своего кода13.
На последнем этапе мы тестируем нашу реализацию на соответствие документации API. В главе 12 вы научитесь использовать автоматизированные инструменты тестирования API, такие как Dredd и Schemathesis, которые предоставляют возможность сгенерировать набор тестов для вашего API. Запуск Dredd и Schemathesis в сочетании с модульными тестами позволяет убедиться в том, что ваша реализация API работает так, как должна. Эти тесты следует запускать на CI-сервере (сервере непрерывной интеграции), чтобы случайно не допустить в релиз код, который нарушает контракт документации API.
Благодаря тому, что на первом этапе разработки API выполняется документирование, подход DDD помогает избежать одной из самых распространенных проблем: разногласий между командами разработчиков клиента и сервера по поводу того, как должен работать API. При отсутствии подробной документации API разработчикам часто приходится гадать о деталях реализации. В таких случаях API редко успешно проходит первое интеграционное тестирование. Хотя разработка через документирование не дает стопроцентной гарантии того, что интеграция будет работать, она значительно снижает риск отказа API-интеграции.
Чтобы проиллюстрировать концепции и идеи, которые объясняются в книге, мы создадим компоненты приложения CoffeeMesh. Это вымышленное приложение, через которое покупатели могут заказывать кофе в любом месте и в любое время. Платформа CoffeeMesh состоит из набора микросервисов, реализующих различные возможности, например обработку заказов и планирование доставки. В главе 3 мы спроектируем платформу CoffeeMesh. Чтобы дать вам представление о том, чему вы научитесь в книге, начнем реализовывать API сервиса заказов CoffeeMesh в главе 2. Но прежде, чем мы закончим главу, я хотел бы еще раз кратко сделать обзор того, что вы узнаете из этой книги.
Чтобы извлечь максимальную пользу из книги, вы должны знать основы веб-разработки. Примеры кода в книге написаны на Python, поэтому неплохо иметь базовое понимание Python, хотя это не обязательно. Вам не нужно уметь разбираться в веб-API или микросервисах, поскольку я подробно расскажу об этих технологиях. Хорошо, если вы знакомы с паттерном Model-View-Controller (MVC) для веб-разработки или с его вариантами, такими как паттерн Model-Template-View (MTV), реализованный в популярном фреймворке Django на Python. Периодически мы будем сравнивать эти паттерны для иллюстрации некоторых концепций. Базовое знакомство с Docker и облачными вычислениями будет полезно для понимания материала глав о развертывании, но я сделаю все возможное, чтобы подробно объяснить каждую концепцию.
В этой книге на практических примерах объясняется, как разрабатывать микросервисы на основе API на Python. Вы узнаете:
• стратегии декомпозиции сервисов для проектирования микросервисной архитектуры;
• как проектировать REST API и документировать их с помощью спецификации OpenAPI;
• как разрабатывать REST API на Python с использованием популярных фреймворков, таких как FastAPI и Flask;
• как проектировать и использовать GraphQL API и разрабатывать их с помощью Python-фреймворка Ariadne;
• как выполнять тестирование API на основе свойств (property-based testing, PBT) и с помощью таких фреймворков, как Dredd и Schemathesis;
• полезные паттерны проектирования для достижения слабой связанности в ваших микросервисах;
• как добавить аутентификацию и авторизацию в ваши API с помощью протоколов Open Authorization (OAuth) и OpenID Connect (OIDC);
• как развернуть микросервисы с помощью Docker и Kubernetes в AWS.
К концу этой книги вы в полной мере оцените преимущества, которые дает веб-приложениям микросервисная архитектура, а также узнаете обо всех возможных проблемах и трудностях ее использования. Вы будете знать, как интегрировать микросервисы с помощью API, как разрабатывать и документировать эти API, используя стандарты и лучшие практики, и будете готовы определить модуль API с четкими границами в приложении. Наконец, вы научитесь тестировать, развертывать и делать безопасными свои микросервисы.
• Микросервисы — это архитектурный стиль, при котором компоненты системы проектируются и разрабатываются как независимо развертываемые сервисы. Это снижает размеры кодовых баз, упрощает их поддержку и позволяет оптимизировать и масштабировать сервисы независимо друг от друга.
• Монолиты — это архитектурный стиль, при котором целые приложения развертываются в одной сборке и запускаются в одном процессе. Это облегчает развертывание и мониторинг приложения, но усложняет развертывание, когда кодовая база разрастается.
• Приложения могут иметь несколько типов интерфейсов: пользовательские интерфейсы, интерфейсы CLI и API. API — это интерфейс, который позволяет нам программно взаимодействовать с приложением из нашего кода или терминала.
• Веб-API — это API, который работает на веб-сервере и использует протокол HTTP для передачи данных. Мы используем веб-API для предоставления возможностей сервиса через Интернет.
• Микросервисы взаимодействуют друг с другом с помощью умных эндпоинтов и глупых каналов. Глупый канал — это канал, который просто передает данные от одного компонента к другому. Отличным примером такого канала для микросервисов является протокол HTTP, который обменивается данными между клиентом и сервером, ничего не зная о протоколе, используемом API. Поэтому веб-API являются отличной технологией для интеграции между микросервисами.
• Несмотря на свои преимущества, микросервисы влекут за собой некоторые проблемы.
• Эффективная декомпозиция сервисов — необходимо проектировать сервисы с четкими границами вокруг конкретных бизнес-задач; в противном случае мы рискуем построить так называемый распределенный монолит.
• Необходимость проведения интеграционных тестов — интеграционное тестирование всех микросервисов оказывается сложной задачей, но можно снизить риск отказов интеграции, обеспечив проверку правильности реализации API.
• Обработка недоступности сервиса — совместно работающие сервисы могут сталкиваться с недоступностью сервисов, тайм-аутами запросов и ошибками обработки, поэтому они должны уметь обрабатывать такие ситуации.
• Трассировка распределенных транзакций — трассировка ошибок в нескольких сервисах является сложной задачей и требует наличия средств программной телеметрии, которые позволяют централизовать логи, обеспечить видимость API и мониторить запросы в разных сервисах.
• Повышенная сложность эксплуатации и накладные расходы на инфраструктуру — каждый микросервис требует создания собственной инфраструктуры, включая серверы, системы мониторинга и оповещения, поэтому вам придется вкладывать дополнительные усилия в автоматизацию инфраструктуры.
• Разработка через документирование — это процесс разработки API, который состоит из трех этапов:
1) проектирования и документирования API;
2) разработки API на основе документации;
3) тестирования API на соответствие документации.
Когда документирование API стоит во главе угла процесса разработки, можно избежать многих распространенных проблем, с которыми сталкиваются разработчики API, и, следовательно, снизить вероятность отказа API-интеграции.
5Ньюман С. Создание микросервисов. — СПб.: Питер, 2016. — С. 23.
6 Полный обзор различных интерфейсов, которые можно использовать для обеспечения взаимодействия между микросервисами, приведен в книге: Ричардсон К. Микросервисы. Паттерны разработки и рефакторинга. — СПб.: Питер, 2019.
7 Подробный анализ стратегических архитектурных решений, связанных с монолитами и микросервисами, приведен в книге: Vernon V., Jaskula T. Strategic Monoliths and Microservices (Addison-Wesley, 2021).
8 Более полный анализ истории появления микросервисной архитектуры и ее предшественников см. в книге: Dragoni N. et al. Microservices: Yesterday, Today and Tomorrow, Present and Ulterior Software Engineering. — Springer, 2017. — P. 195–216.
9Wang A., Tonse S. Announcing Ribbon: Tying the Netflix Mid-Tier Services Together («Анонс ленты: связывая вместе сервисы промежуточного слоя Netflix») // Netflix Technology Blog, 18 января 2013 г. https://netflixtechblog.com/announcing-ribbon-tying-the-netflix-mid-tier-services-together-a89346910a62. Прекрасное объяснение различий между сервис-ориентированной архитектурой (SOA) и микросервисной архитектурой см. в книге: Ричардсон К. Микросервисы. — С. 40–41.
10 Данные в формате JSON в общем виде тоже текст. — Примеч. ред.
11Ньюман С. Создание микросервисов. — С. 30.
12 Чтобы больше узнать о процессе разработки API и о том, как использовать mock-серверы при разработке клиента, посмотрите мою презентацию API Development Workflows for Successful Integrations («Процессы разработки API для успешных интеграций») // Manning API Conference, 3 августа 2021 года. https://youtu.be/SUKqmEX_uwg.
13 Чтобы узнать, как разработчики могут использовать документацию API, ознакомьтесь с моим докладом Leveraging API Documentation to Deliver Reliable API Integrations («Использование документации API для разработки надежных интеграций») // API Specifications Conference, 28–29 сентября 2021 года. https://youtu.be/kAWvM-CVcnw.
В этой главе
• Чтение и понимание требований к спецификации API.
• Разделение приложения на уровень данных, уровень приложения и уровень интерфейса.
• Реализация эндпоинтов API с помощью FastAPI.
• Реализация моделей (схем) валидации данных с помощью pydantic.
• Тестирование API с помощью Swagger UI.
В этой главе мы реализуем API для сервиса заказов, который является одним из микросервисов сайта CoffeeMesh, проекта, представленного в разделе 1.5. CoffeeMesh — это приложение, в котором можно заказать доставку кофе в любое время, где бы вы ни находились. Сервис заказов позволяет покупателям размещать заказы в CoffeeMesh. По мере реализации API сервиса заказов вы получите первое представление о понятиях и процессах, которые мы более подробно рассмотрим в книге. Код для этой главы доступен в папке ch02 репозитория GitHub к книге.
Начнем с анализа требований API. Используя API сервиса заказов, мы можем размещать заказы, получать сведения о них, изменять или отменять их. Спецификация API сервиса заказов доступна в файле с именем ch02/oas.yaml в репозитории GitHub. OAS расшифровывается как OpenAPI Specification (спецификация OpenAPI), которая является стандартным форматом для документирования REST API. Как документировать API с помощью OpenAPI, мы обсудим в главе 5.
Как видно на рис. 2.1, спецификация API описывает REST API с четырьмя основными путями URL:
• /orders — позволяет получать списки заказов (GET) и создавать заказы (POST);
• /orders/{order_id} — позволяет получить информацию о конкретном заказе (GET), изменить (PUT) и удалить заказ (DELETE);
• /orders/{order_id}/cancel — позволяет отменить заказ (POST);
• /orders/{order_id}/pay — позволяет оплатить заказ (POST).
Рис. 2.1. API сервиса заказов предоставляет семь эндпоинтов, построенных на четырех URL-путях. Каждый реализует различные функции, такие как размещение и отмена заказа
В дополнение к документированию эндпоинтов спецификация API также содержит модели данных, которые описывают данные, передающиеся между этими эндпоинтами. В OpenAPI мы называем эти модели схемами (schemas), и вы можете найти их в разделе components