Close

Как создавать микросервисы

Рекомендации по переходу на микросервисную архитектуру

Фотография Чендлера Харриса
Стен Питтет

менеджера по продукту


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

По мере того, как приложения становятся более распределенными и сложными, растет популярность микросервисов. Основной принцип микросервисной архитектуры — создание приложения путем разделения компонентов его бизнес-логики на небольшие сервисы, которые можно развертывать и использовать независимо друг от друга. Задачи распределяются между сервисами, которые разделены между собой так называемыми «границами сервисов».

Границы сервисов тесно связаны с бизнес‑требованиями и границами организационной структуры. Отдельные сервисы могут быть привязаны к отдельным командам, бюджетам или дорожным картам. В качестве примеров границ сервисов можно привести сервисы обработки платежей и аутентификации пользователей. Микросервисный подход отличается от прежних принципов разработки ПО, в котором все компоненты были связаны воедино.

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

Как создавать микросервисы


Шаг 1. Начните с монолита

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

Например, в случае с Pizzup мы начинаем с простой проблемы, которую нужно решить: мы хотим, чтобы клиенты могли заказывать пиццу онлайн.

Пользователь Pizzup, который говорит: «Как пользователь, я могу заказать пиццу онлайн».
Значок: хранилище кода
Связанные материалы

Сравнение микросервисной и монолитной архитектур

Значок: три кольца
См. решение

Управление компонентами с помощью Compass

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

Иллюстрация, показывающая разницу между конечным пользователем и администратором в приложении Pizzup.

То, что вначале было простой потребностью, быстро превратилось в список новых возможностей.

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

Помните о том, что создание монолита может быстро привести к усложнению кода, который затем будет очень сложно разбить на части. Лучше всего создавать четко определенные модули, которые в дальнейшем можно будет извлечь из монолита. Вы также можете начать с отделения логики от пользовательского веб-интерфейса и предусмотреть взаимодействие с серверной частью через API REST по протоколу HTTP. Это облегчит переход на микросервисную архитектуру, когда вы будете переносить API-ресурсы в различные сервисы.

Шаг 2. Правильно организуйте команды

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

Закон Конвея работает, его действие можно наблюдать во всех типах команд. Если команда разработчиков ПО разделена на команды бэкенда, фронтенда и эксплуатации, работающие независимо друг от друга, в итоге будут созданы отдельные монолиты фронтенда и бэкенда, которые будут «отданы на откуп» команде по эксплуатации для поставки в рабочую среду. Такая структура команды не подходит для микросервисов, поскольку каждый сервис следует рассматривать как отдельный продукт, который должен поставляться независимо от других.

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

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

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

Обеспечьте простое взаимодействие между сервисами с помощью API RESTful

Если вы еще не используете технологию API REST, сейчас самое время внедрить ее. Как объясняет Мартин Фаулер, вам нужны «умные конечные точки и глупые каналы». Это означает, что протокол связи между сервисами должен быть максимально простым и отвечать только за передачу данных без какого-либо преобразования. Все волшебство происходит в конечных точках: они получают запрос, обрабатывают его и выдают ответ.

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

Разделяйте данные на ограниченные контексты или предметные области

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

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

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

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

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

Выстраивайте микросервисную архитектуру с расчетом на отказ

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

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

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

Усильте мониторинг, чтобы упростить тестирование микросервисов

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

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

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

Используйте непрерывную поставку, чтобы упростить процесс развертывания

Ручной выпуск монолитной системы в рабочую среду — это утомительная и рискованная затея, но принципиально это возможно. Конечно, мы не рекомендуем этот подход и призываем все команды разработчиков ПО использовать непрерывную поставку при любом типе разработки, однако в начале проекта вы можете сделать первые развертывания самостоятельно через командную строку.

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

Использование микросервисов — это не спринт


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

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

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

Заключение


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

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

Sten Pittet
Sten Pittet

Я уже 10 лет работаю в сфере ПО, занимал различные должности: от разработчика до менеджера продукта. Проработав 5 лет в Atlassian, где я участвовал в создании инструментов разработки, теперь я пишу статьи о разработке ПО. За пределами офиса я работаю над тем, чтобы стать хорошим отцом для своего потрясающего малыша.


Поделитесь этой статьей

Рекомендуемые статьи

Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.

Рисунок: DevOps

Сообщество Compass

рисунок: преодоление препятствий

Обучающее руководство: создание компонента

Рисунок: карта

Начните работу с Compass бесплатно

Подпишитесь на информационную рассылку по DevOps

Thank you for signing up