В монолитной архитектуре данные зачастую хранятся в единой, обычно реляционной, базе данных, со строго определенной схемой и обширным использованием запросов SQL. Микросервисы снова требуют противоположного подхода – в идеале никакого разделения данных, особенно через единую базу данных. Весь доступ, любые изменения данных происходят только через программный интерфейс API, предоставляемый микросервисом.
Микросервисы, таким образом, свободны в своем выборе способа хранения данных. Это может быть любой тип базы данных, например, нереляционная база NoSQL, база на основе документов, графовая база, или что-либо еще. Конечно, возникает значительная избыточность данных, но хранение данных не так дорого, а автономность и независимость развития каждого микросервиса, в идеале, должна окупить избыточность данных.
Культура автоматизации
Учитывая лавинообразный рост зависимостей между компонентами, и независимый набор технологий в каждом из микросервисов, надежный, автоматизированный выпуск системы и ее быстрые обновления – это жизненно необходимый элемент микросервисной архитектуры. Ручная сборка и управление микросервисами практически невозможны.
Непрерывная интеграция и тестирование (CI, continuous integration), непрерывное развертывание новых версий (CD, continuous delivery) – это обязательный атрибут команд, создающих микросервисы. Здесь огромную помощь оказывают контейнеры, со своей быстрой, легковесной виртуализацией, и «чистым», изолированным пространством, в котором запускаются микросервисы, а развертывание значительно упрощает оркестратор Kubernetes, предоставляя мощный декларативный подход. Их мы тщательно рассмотрим в следующих главах, представить микросервисы без них уже практически невозможно.
Расчет на постоянные сбои
Микросервисы приводят к распределенной, гетерогенной, динамичной системе. Ей просто предначертано испытывать постоянные сбои, из-за сетевых вызовов, нагрузок, несовместимости версий, и многого другого. Этого не избежать, и на это нужно просто рассчитывать заранее, планируя каждый вызов к остальным компонентам системы как изначально не способный гарантировать успешное завершение.
Планировать сбои можно не только на этапе дизайна кода и отдельных тестов, но и более активным способом. Так, компания Netflix использует «обезьяну с гранатой» (Chaos Monkey, перевод не дословный, но наша фраза на русском языке вполне подходит!), отдельный сервис, постоянно выводящий из строя случайный набор микросервисов. Остальные компоненты системы должны подстроиться к ситуации, и правильно реагировать на сбои системы, проводя разумную политику отката своих действий, или же используя вспомогательные компоненты и альтернативные способы исполнения логики.
Небольшая команда, акцент на своей бизнес-области
Микросервисы как правило разрабатываются небольшой командой (известен практически анекдот от компании Amazon, что команда, работающая над микросервисом, всегда сможет насытиться двумя пиццами. Пиццы скорее всего большие, возможно, с разными наполнителями – так что в итоге это может быть и чуть больше 10 человек). Идея состоит в том, что небольшой команде проще координировать свои действия и быстро проводить новые идеи и изменения в жизнь.
Второй аспект – команда больше не состоит только из программистов серверной части (back end), пользовательских интерфейсов (front end, или UI), или же системных администраторов. Они работают вместе над одной, сконцентрированной бизнес-областью. Классический пример – онлайн магазин, и сервисы по доставке, оформлению заказов, и проведению платежей. В мире микросервисов все эти сервисы разрабатываются, выпускаются в эксплуатацию, и развертываются отдельными командами, в своем ритме.
Более того, у каждой команды могут быть отдельные требования, процесс, планирование, и даже заказчики – внутренние или внешние. Общаются эти команды независимо, и микросервисы работают независимо, предоставляя четко очерченные программные интерфейсы API.
Интересно, что подобное требование лежит за пределами чисто технической, программистской зоны ответственности – такое распределение обязанностей должно лежать в основе всей организации целиком, с множеством автономных зон ответственности, без единого, «жесткого» центра управления. Как гласит известный закон Конвея (Conway’s law), структура организации обязательно проявит себя в планировании и производстве любых продуктов и сервисов этой организации.
Владение продуктом, а не реализация проекта
Зачастую, в классической модели разработки, команда программистов и дизайнеров реализует проект, исполняя поставленные перед ней требования (requirements). Что происходит после того, как проект «сдан»? Команда начинает работать над чем-то новым, переходит в другие проекты, а в случае субподрядчиков и контрактных услуг, работа с ней может быть полностью закончена. Обслуживание системы, исправление ошибок, ее обновление нередко попадает совершенно в другие руки.
Парадигма микросервисов предпочитает, чтобы команда разработчиков «владела» (own) своим проектом в начале его дизайна, в процессе создания и настройки микросервисов, и обязательно после формальной сдачи системы, непрерывно продолжая работу над ее эволюцией. Постоянный контакт с пользователями системы, наблюдение за ней в условиях реальной эксплуатации позволяет максимально эффективно понять, как ее развить и улучшить. Как вариант подобной системы популярна концепция DevOps (developer + operations, совместная работа как над разработкой, так и над поддержкой и эксплуатацией системы). Оркестратор Kubernetes сам по себе подталкивает работать в концепции DevOps.
Эволюционный дизайн
«Эволюционный дизайн (evolutionary design) – попытка добиться результата не с одной попытки, чудесным образом дающей идеальное попадание, а в результате многих постепенных изменений, приводящих к эволюции дизайна и продукта», Джошуа Кириевски (Joshua Kerievsky), адепт Agile/XP-разработки.
Микросервисы дают большую свободу приверженцам эволюционного дизайна, противникам тщательного предварительного анализа системы, и попытки понять ее целиком еще до того, как написана первая строка кода, и сделан выбор первых технологий для ее реализации. Вместо классического планирования и дизайна всей необходимой функциональности системы, создается первое «примитивное» приближение (primitive whole). Система выглядит практически реально, но умеет очень мало. Пользователи получают возможность впервые посмотреть на систему, и конечно же, немедленно просят поменять или улучшить ее, не целиком, но значительно. В подобных итерациях и рождается истина.
Если создание монолитной системы немедленно приводит к сильными зависимостям от выбранной технологии, системы хранения данных и библиотек, то добавка новых микросервисов, и даже быстрое удаление «неудачных» или «временных» микросервисов становятся делом техники. У разработчиков развязаны руки – они могут свободно обращаться с выбором технологий, а также передвигать границы микросервисов – если изначально они были выбраны неверно, в первых итерациях их легко объединить или разбить.
Краткие итоги
Первый обзор типичных черт микросервисов внушает оптимизм. Четкое разделение обязанностей, абсолютная свобода в выборе технологий и хранении данных, точно настроенное масштабирование, и помощь контейнеров и Kubernetes выглядят очень заманчиво. Однако не стоит забывать о сложности распределенной системы, присущей любой, даже самой простой такой системе. Сетевые вызовы часто приносят с собой неизвестные заранее задержки (latency), и для быстрой работы приходится выполнять работу асинхронно (asynchronous), заранее не зная, в какой момент приходит ответ от остальных компонентов системы.
Сложность асинхронной, распределенной, динамично развивающейся системы в разы превышает сложность единого, монолитного приложения. Разделить систему на микросервисы зачастую очень сложно, если в компании «все делают все», и нет четко очерченных бизнес-областей. В таких случаях вместо микросервисов получается «распределенный монолит» (distributed monolith), неповоротливая, сложная система, вместо которой мог бы иметь место более эффективный монолит.
Не забывайте, что два остальных столпа концепции Cloud Native совершенно безразличны к битве монолитов, микросервисов и SOA! Вы можете совершенно спокойно развернуть классическое, монолитное приложение Enterprise Java в контейнере под управлением Kubernetes, получив многие преимущества без излишней сложности.
Один из давних соратников Мартина, Сэм Ньюмен (Sam Newman), написал отдельную, и кстати, не слишком «толстую», книгу по микросервисам, которую можно рекомендовать для чтения, и существует ее перевод на русский язык (полный список рекомендованных ресурсов вы найдете в конце этой главы).
Стандарт
О проекте
О подписке