Перевод книги Кристиана Посты (Christian Posta) Microservices for Java Developers. A Hands-On Introduction to Frameworks & Containers. Продолжение. Предыдущая публикация.
ГЛАВА 1. Микросервисы для Java программистов
В среде микросервисов с автономными командами и сервисами очень важно иметь в виду взаимоотношения между поставщиком и потребителем сервиса. Как автономная команда обслуживающая сервис, Вы не можете предъявлять какие-либо требования к другим командам и сервисам потому, что Вы не владеете ими, они автономны по определению. Всё, что Вы можете сделать — это выбрать, будете ли Вы принимать или не принимать их обязательства функциональности или поведения. А как поставщик сервиса для других, всё, что Вы можете сделать — это пообещать им определенное поведение. Они вольны в выборе — доверять Вам или нет. Модель теории обязательств впервые предложена Марком Берджессом (Mark Burgess) в 2004 году и описана в его книге «В поисках определенности» (In Search of Certainty, O’Reilly, 2015). Это исследование автономных систем включая человеческие и компьютерные, оказывающие услуги друг другу.
С точки зрения распределенных систем «обязательство» помогает сформулировать, какие услуги предоставляются и какие предположения на их счет могут или не могут быть сделаны. Например, команда владеет сервисом, который рекомендует книги. Мы обещаем персонифицированный набор книг, рекомендуемый для конкретного произвольного пользователя. Что произойдет, если при обращении к этому сервису один из бэкендов (база данных, хранящая текущий профиль рекомендаций для пользователей) вдруг недоступен? Мы могли бы сгенерировать исключение и отправить обратно трассировку стека, но это было бы не очень приятно для потребителя и может потенциально развалить другие части системы. Мы дали обещание и мы попытаемся сделать всё возможное, чтобы выполнить его. В том числе вернув некий стандартный набор рекомендаций книг или подмножество, состоящее из любой книги. Бывают случаи, когда обещания невозможно выполнить и наилучшее поведение в таком случае будет определяться уровнем сервиса или результатом для пользователей, который мы хотели бы сохранить. Ключевым здесь является акцент на обещании сервиса (выдать рекомендации), даже если сервис от которого мы зависим, не может выполнить своё обещание (база данных отказала). Попытки сдержать обещание помогают сохранить остальные части системы и удержать уровень качества обслуживания.
Другой взгляд на «обязательство» — это согласованное взаимное понимание его ценности для обеих сторон (как производителя, так и потребителя). Но как же нам выбрать из двух поставщиков, что ценнее и на какие обязательства нам стоит соглашаться? Если никто не обращается к сервису или не получает результат от обещаний, чем полезен такой сервис? Один из способов сформулировать обязательства между потребителями и поставщиками — это задаваемый потребителем контракт (consumer-driven contract). В задаваемом потребителем контракте мы можем зафиксировать объем обещаний кодом или утверждениями, а в качестве поставщика мы можем использовать эти знания, чтобы проверить, действительно ли мы держим свои обещания.
В конце концов управление отдельной системой проще, чем распределенной. Если есть только одна машина, один сервер приложений и в системе случились проблемы, мы знаем где искать. Если нужно изменить конфигурацию, обновить до определенной версии или обезопасить его — это всё равно одно физическое и логическое расположение. Выполнять управление, отладку и изменения в таком случае достаточно просто. Единая система может работать для некоторых приложений, но там, где требуется масштабирование, следует обратить внимание на микросервисы. Как мы уже упоминали ранее, микросервисы не даются бесплатно — плата за гибкость и масштабируемость — более сложная система управления.
Вот некоторые вопросы управляемости развертывания микросервисов:
И это не самые легкие для решения проблемы. Остальная часть книги будет посвящена введению Java-разработчиков в мир микросервисов и в способы решения некоторых из перечисленных выше проблем. Полный, всеобъемлющий перечень инструкций и ответов на перечисленные вопросы (и многие другие) появится во втором издании этой книги.
На протяжении остальной книги мы познакомим Вас с некоторыми популярными компонентами технологий и как они решают некоторые проблемы разработки и внедрения программного обеспечения с использованием архитектуры микросервисов. Как говорилось ранее, микросервисы — это не только технологическая проблема, первостепенными являются правильная организационная структура и соответствующие команды. Переход от SOAP к REST не создает микросервисную архитектуру.
Первым шагом для команды Java разработчиков разрабатывающей микросервисы, является получение работающего результата на своей локальной машине! Эта книга познакомит Вас с тремя фреймворками Java для работы с микросервисами: Spring Boot, Dropwizard и WildFly Swarm. Каждый из них имеет свои плюсы для разных команд, организаций и подходов к микросервисам. Так же как и для любой другой технологии то, что некоторые инструменты лучше подходят для той или иной работы или команды — это норма. Перечисленные инструменты не единственные в своем роде. Есть еще пара, которые исповедуют реактивный подход к микросервисам — это Vert.x и Lagom. Переход к событийной модели разработки слегка отличается и требует несколько другого набора знаний, так что в этой книге мы будет придерживаться модели, которую большинство Java программистов найдут вполне комфортной.
Цель этой книги — подготовить Вас к использованию основных возможностей каждого из фреймворков. Мы погрузимся в пару «продвинутых» концепций в последней главе, но для первых шагов с каждым из фреймворков мы будем использовать микросервисное приложение «hello-world». Эта книга не является всеобъемлющим справочником по разработке микросервисов. В каждом разделе есть ссылки на справочные материалы, которые Вы сможете изучить по мере необходимости. Мы будем постепенно развивать приложение «hello-world», создав несколько сервисов и демонстрируя различные простые схемы взаимодействия.
Заключительный этюд для каждого из фреймворков затронет такие концепции как «переборки» (bulkheading) и «теория обязательств», чтобы сделать сервисы более устойчивыми перед лицом отказов. Мы покопаемся в таких частях стека NetflixOSS как Hystrix, что поможет облегчить реализацию этого функционала. Мы обсудим плюсы и минусы такого подхода и исследуем другие существующие варианты.
По мере продвижения по примерам мы обсудим значение Linux-контейнеров для развертывания, управления и изоляции микросервисов равно как и их значение для локальной разработки. Docker и Kubernetes внесли неоценимый вклад в упрощение работы с распределенными масштабируемыми системами, поэтому мы обсудим некоторые полезные практики связанные с контейнерами и микросервисами.
В последнем разделе, мы дадим Вам несколько мыслей на тему управления распределенными конфигурациями, логированием, мониторингу и непрерывной поставки.
Для примеров мы будем использовать Java 1.8 и собирать их с помощью Maven. Пожалуйста, убедитесь, что у Вас установлены соответствующие программы и выполнены следующие условия:
Экосистема Spring имеет несколько отличных инструментов, которые можно использовать либо в командной строке, либо в IDE. Большинство примеров будет придерживаться командной строки, чтобы оставаться независимыми от IDE потому, что каждая IDE определяет свой собственный способ работы с проектами. Для Spring Boot, мы будем использовать Spring Boot CLI 1.3.3.
Альтернативные IDE и инструментарий для Spring:
И для Dropwizard, и для WildFly Swarm мы будем использовать JBoss Forge CLI и некоторые расширения, чтобы создавать и управлять проектами: JBoss Forge 3.0+.
Альтернативные IDE и инструментарий для проектов Spring, Dropwizard или WildFly Swarm (которые отлично работают с JBoss Forge):
И наконец, для сборки и запуска микросервисов в виде Docker-контейнеров внутри Kubernetes нам понадобятся следующие инструменты для развертывания среды контейнеров:
ГЛАВА 1. Микросервисы для Java программистов
(Продолжение)
Проектирование с учетом обязательств
В среде микросервисов с автономными командами и сервисами очень важно иметь в виду взаимоотношения между поставщиком и потребителем сервиса. Как автономная команда обслуживающая сервис, Вы не можете предъявлять какие-либо требования к другим командам и сервисам потому, что Вы не владеете ими, они автономны по определению. Всё, что Вы можете сделать — это выбрать, будете ли Вы принимать или не принимать их обязательства функциональности или поведения. А как поставщик сервиса для других, всё, что Вы можете сделать — это пообещать им определенное поведение. Они вольны в выборе — доверять Вам или нет. Модель теории обязательств впервые предложена Марком Берджессом (Mark Burgess) в 2004 году и описана в его книге «В поисках определенности» (In Search of Certainty, O’Reilly, 2015). Это исследование автономных систем включая человеческие и компьютерные, оказывающие услуги друг другу.
С точки зрения распределенных систем «обязательство» помогает сформулировать, какие услуги предоставляются и какие предположения на их счет могут или не могут быть сделаны. Например, команда владеет сервисом, который рекомендует книги. Мы обещаем персонифицированный набор книг, рекомендуемый для конкретного произвольного пользователя. Что произойдет, если при обращении к этому сервису один из бэкендов (база данных, хранящая текущий профиль рекомендаций для пользователей) вдруг недоступен? Мы могли бы сгенерировать исключение и отправить обратно трассировку стека, но это было бы не очень приятно для потребителя и может потенциально развалить другие части системы. Мы дали обещание и мы попытаемся сделать всё возможное, чтобы выполнить его. В том числе вернув некий стандартный набор рекомендаций книг или подмножество, состоящее из любой книги. Бывают случаи, когда обещания невозможно выполнить и наилучшее поведение в таком случае будет определяться уровнем сервиса или результатом для пользователей, который мы хотели бы сохранить. Ключевым здесь является акцент на обещании сервиса (выдать рекомендации), даже если сервис от которого мы зависим, не может выполнить своё обещание (база данных отказала). Попытки сдержать обещание помогают сохранить остальные части системы и удержать уровень качества обслуживания.
Другой взгляд на «обязательство» — это согласованное взаимное понимание его ценности для обеих сторон (как производителя, так и потребителя). Но как же нам выбрать из двух поставщиков, что ценнее и на какие обязательства нам стоит соглашаться? Если никто не обращается к сервису или не получает результат от обещаний, чем полезен такой сервис? Один из способов сформулировать обязательства между потребителями и поставщиками — это задаваемый потребителем контракт (consumer-driven contract). В задаваемом потребителем контракте мы можем зафиксировать объем обещаний кодом или утверждениями, а в качестве поставщика мы можем использовать эти знания, чтобы проверить, действительно ли мы держим свои обещания.
Управление распределенными системами
В конце концов управление отдельной системой проще, чем распределенной. Если есть только одна машина, один сервер приложений и в системе случились проблемы, мы знаем где искать. Если нужно изменить конфигурацию, обновить до определенной версии или обезопасить его — это всё равно одно физическое и логическое расположение. Выполнять управление, отладку и изменения в таком случае достаточно просто. Единая система может работать для некоторых приложений, но там, где требуется масштабирование, следует обратить внимание на микросервисы. Как мы уже упоминали ранее, микросервисы не даются бесплатно — плата за гибкость и масштабируемость — более сложная система управления.
Вот некоторые вопросы управляемости развертывания микросервисов:
- Как запускать и останавливать весь «флот» сервисов?
- Как собирать и консолидировать логи/метрики/параметры качества со всех микросервисов?
- Как обнаруживать сервисы в изменяющемся окружении, если они могут появляться, исчезать, перемещаться и т.п.?
- Как осуществлять балансировку нагрузки?
- Как мы получим состояние кластера или отдельных микросервисов?
- Как перезапустить «упавшие» сервисы?
- Как организовать настраиваемую маршрутизацию запросов API?
- Как обеспечить безопасность сервисов?
- Как придержать/разогнать или отключить части кластера если он начал «разваливаться» или вести себя непредсказуемо?
- Как развернуть несколько версий сервиса и корректно маршрутизировать к ним запросы?
- Как провести изменения конфигурации во всем «флоте» сервисов?
- Как организовать изменение кода приложения и его конфигурации безопасным, проверяемым и повторяемым способом?
И это не самые легкие для решения проблемы. Остальная часть книги будет посвящена введению Java-разработчиков в мир микросервисов и в способы решения некоторых из перечисленных выше проблем. Полный, всеобъемлющий перечень инструкций и ответов на перечисленные вопросы (и многие другие) появится во втором издании этой книги.
Технологические решения
На протяжении остальной книги мы познакомим Вас с некоторыми популярными компонентами технологий и как они решают некоторые проблемы разработки и внедрения программного обеспечения с использованием архитектуры микросервисов. Как говорилось ранее, микросервисы — это не только технологическая проблема, первостепенными являются правильная организационная структура и соответствующие команды. Переход от SOAP к REST не создает микросервисную архитектуру.
Первым шагом для команды Java разработчиков разрабатывающей микросервисы, является получение работающего результата на своей локальной машине! Эта книга познакомит Вас с тремя фреймворками Java для работы с микросервисами: Spring Boot, Dropwizard и WildFly Swarm. Каждый из них имеет свои плюсы для разных команд, организаций и подходов к микросервисам. Так же как и для любой другой технологии то, что некоторые инструменты лучше подходят для той или иной работы или команды — это норма. Перечисленные инструменты не единственные в своем роде. Есть еще пара, которые исповедуют реактивный подход к микросервисам — это Vert.x и Lagom. Переход к событийной модели разработки слегка отличается и требует несколько другого набора знаний, так что в этой книге мы будет придерживаться модели, которую большинство Java программистов найдут вполне комфортной.
Цель этой книги — подготовить Вас к использованию основных возможностей каждого из фреймворков. Мы погрузимся в пару «продвинутых» концепций в последней главе, но для первых шагов с каждым из фреймворков мы будем использовать микросервисное приложение «hello-world». Эта книга не является всеобъемлющим справочником по разработке микросервисов. В каждом разделе есть ссылки на справочные материалы, которые Вы сможете изучить по мере необходимости. Мы будем постепенно развивать приложение «hello-world», создав несколько сервисов и демонстрируя различные простые схемы взаимодействия.
Заключительный этюд для каждого из фреймворков затронет такие концепции как «переборки» (bulkheading) и «теория обязательств», чтобы сделать сервисы более устойчивыми перед лицом отказов. Мы покопаемся в таких частях стека NetflixOSS как Hystrix, что поможет облегчить реализацию этого функционала. Мы обсудим плюсы и минусы такого подхода и исследуем другие существующие варианты.
По мере продвижения по примерам мы обсудим значение Linux-контейнеров для развертывания, управления и изоляции микросервисов равно как и их значение для локальной разработки. Docker и Kubernetes внесли неоценимый вклад в упрощение работы с распределенными масштабируемыми системами, поэтому мы обсудим некоторые полезные практики связанные с контейнерами и микросервисами.
В последнем разделе, мы дадим Вам несколько мыслей на тему управления распределенными конфигурациями, логированием, мониторингу и непрерывной поставки.
Подготовка среды разработки
Для примеров мы будем использовать Java 1.8 и собирать их с помощью Maven. Пожалуйста, убедитесь, что у Вас установлены соответствующие программы и выполнены следующие условия:
- JDK 1.8
- Maven 3.2+
- Есть доступ к командной строке (bash, PowerShell, cmd, Cygwin, и т.д.)
Экосистема Spring имеет несколько отличных инструментов, которые можно использовать либо в командной строке, либо в IDE. Большинство примеров будет придерживаться командной строки, чтобы оставаться независимыми от IDE потому, что каждая IDE определяет свой собственный способ работы с проектами. Для Spring Boot, мы будем использовать Spring Boot CLI 1.3.3.
Альтернативные IDE и инструментарий для Spring:
- IDE на базе Eclipse: Spring Tool Suite.
- Spring Initializr web interface.
И для Dropwizard, и для WildFly Swarm мы будем использовать JBoss Forge CLI и некоторые расширения, чтобы создавать и управлять проектами: JBoss Forge 3.0+.
Альтернативные IDE и инструментарий для проектов Spring, Dropwizard или WildFly Swarm (которые отлично работают с JBoss Forge):
- IDE на базе Eclipse: JBoss Developer Studio.
- Netbeans.
- IntelliJ IDEA.
И наконец, для сборки и запуска микросервисов в виде Docker-контейнеров внутри Kubernetes нам понадобятся следующие инструменты для развертывания среды контейнеров:
- Vagrant 1.8.1.
- VirtualBox 5.0.x.
- Container Development Kit 2.x.
- Kubernetes/Openshift CLI.
- Docker CLI (опционально).
sonik9
Ждём продолжения, спасибо