7 Доступ через сетевые порты
Микросервисы общаются через сетевые порты, обычно с помощью HTTP в стиле REST, отсылая данные в формате JSON или XML, или используют бинарный протокол gRPC. Если микросервис вызывает другие микросервисы-партнеры, адреса доступа к ним и их порты хранятся отдельно, в конфигурации, или с помощью системы обнаружения сервисов (service discovery). Данное требование идеально исполняется контейнерами, которые объявляют, по какому порту они будут ожидать соединений, и сервисами (service) Kubernetes, описывающими, как эти порты будут доступны в кластере. Kubernetes обеспечивает обнаружение сервисов с помощью простых имен DNS. Все необходимое для работы HTTP сервера находится внутри контейнера (встроенные сервера, например Netty для Java).
8 Масштабирование через запуск дополнительных экземпляров
Концепция микросервисов позволяет снизить количество ресурсов для четко выделенного компонента системы, и провести его точечное горизонтальное масштабирование это возможно только в случае микросервисов без состояния (фактор 6). Kubernetes делает масштабирование, в том числе автоматическое в зависимости от загрузки системы, тривиальной задачей, и поддерживает желаемое количество экземпляров микросервиса.
9 Быстрый запуск и надежная остановка
Микросервисы должны запускаться как можно быстрее, вновь в целях быстрой адаптации к возрастающей нагрузке, и более эффективного использования освобождающихся ресурсов. Легковесная виртуализация контейнеров Linux делает запуск новых контейнеров практически мгновенным, почти неотличимым от запуска обычного процесса. Отсутствие состояния и данных в основных компонентах бизнес-логики позволяет быстро их остановить, обновить, без потери данных и функциональности.
10 Одинаковая среда разработки и эксплуатации
В больших распределенных системах, особенно если используется сложная авторизация, роли, базы данных, облачное хранилище данных, сразу же возникает вопрос как организовать среду разработки с похожим поведением, для отладки и проверки нового кода. Часто в целях экономии производственные облачные системы заменяют на менее мощные, или даже на локальные эмуляторы, которые отдаленно напоминают среду эксплуатации (production), но все же имеют множество мелких различий, и называют это средой разработки (dev environment).
Авторы 12 факторов яростно протестуют против подобного подхода среда разработки, среда тестирования, и среда эксплуатации должны полностью совпадать, даже если придется платить за дополнительные ресурсы. В долгосрочном плане это сэкономит множество ресурсов на поиске проблем и сделает возможным более быстрый выпуск надежного нового кода. Я думаю, многие из нас сталкивались с неполноценными средами разработки, и абсолютно не поддающимися воспроизведению в них ошибками реальной эксплуатации. Анализ ошибки в таком случае значительно усложняется.
Хотя контейнеры и Kubernetes не смогут автоматически предоставить вам идентичные среды, они сделают это намного проще, благодаря неизменности образов контейнеров, работающих в системе, и легкой переносимости конфигураций YAML. Следование факторам 2, 3, 4 и 6 также сделает создание идентичной среды разработки проще. Более того, если среды абсолютно идентичны, то любой член команды сможет выполнить развертывание, приближая команду к DevOps.
11 Журналы logs в виде потока событий
В классических монолитных системах журналы пишутся на диск, в файлы. Используется заранее выбранный формат, архивация и инструменты для их обработки (например, Log4J для Java). Ситуация кардинально меняется для контейнеров и системы из распределенных микросервисов. Контейнеры эфемерны и их файловая система пропадает вместе с их остановкой, разные технологии применяют различные форматы журналов, а понять что происходит с системой целиком по разнородным журналам крайне сложно.
В облачном приложении журналы не сохраняются и не обрабатываются. Все записи делаются в стандартный вывод (standard output), тот самый, что выводится в терминал при ручном запуске. Именно стандартный вывод используется в контейнерах и Kubernetes. Дополнительные решения (ELK ElasticSearch + Logstash + Kibana, или Fluentd), работающие под управлением Kubernetes, собирают журналы с различных микросервисов, форматируют, хранят их, и предоставляют инструменты для полного анализа.
12 Администрирование как часть приложения
12 Администрирование как часть приложения
Дополнительные административные задачи, такие как миграция данных или удаление неудачных записей из распределенного кэша, могут исполняться только из среды эксплуатации, эти задачи тестируются вместе с построением и выпуском системы, и поставляются вместе. Уверенность в том, что дополнительное администрирование сделано проверенным способом, и в нужной среде, уменьшит количество ошибок. Неизменность контейнеров и легкий откат к предыдущим версиям развертываний (deployment) в Kubernetes позволят исправить неудачный выпуск системы.
Резюме
Завершая свой обзор мира Cloud Native, можно подчеркнуть, что в этой концепции сконцентрирован многолетний опыт технологических гигантов, прошедших путь от первых идей, воплощенных на нескольких слабых серверах, простейшими страницами на PHP и MySQL, к географически распределенным, работающим в виде десятков тысяч микросервисов системам, практически неуязвимым к простоям, пиковым нагрузкам, и трафику миллиардов пользователей со всего мира. Создаваемые вами системы могут быть более скромными, однако разрабатывая их «рожденными для облака», вы воспользуетесь опытом тысяч инженеров и успешных компаний, и разработаете приложения, удобные в эксплуатации и поддержке, надежные как Google и Yandex.
2. Микросервисы
«Невозможно описать термин микросервис, потому что не существует даже словарного запаса для этой области. Вместо этого мы опишем список типичных черт микросервисов, но сделаем это со следующей оговоркой большинству микросервисных систем присущи лишь некоторые из приведенных черт, но не всегда, и даже для совпадающих черт будут значительные различия от канона.»
Мартин Фаулер (Martin Fowler), одно из первых выступлений, посвященных глубокому анализу микросервисов).Как мы выяснили из первой главы, обзора концепции и технологий, «созданных для облака» (cloud native), практически неотъемлемой частью проектирования и разработки приложений для работы в облаке стали «микросервисы» (microservices), особенно бурно ворвавшиеся в тренд популярности на волне успеха стека технологий и способа разработки Netflix, Twitter, Uber, и до этого идей от Amazon.
Определить точно, что это за архитектура, и чем она формально отличается от очень известного до этого подхода SOA (service oriented architecture), то есть архитектуры ориентированной на сервисы, довольно сложно. Многие копья сломаны на конференциях и форумах, создано множество блогов, можно сделать определенные выводы. Прежде всего микросервисы отличаются от «монолитов» (monolith), приложений, созданных с помощью единой технологии или платформы, внутри которой находятся вся деловая логика системы, анализ данных, обслуживание и выдача данных пользовательским интерфейсам. Любое взаимодействие модулей, сервисов и компонентов внутри монолита как правило происходит в рамках одного или максимум несколько процессов.
Плюсы монолита очевидны мгновенная скорость общения между сервисами и компонентами, зачастую в рамках одного процесса, общая база кода, меньше ограничений на взаимодействие между компонентами и модулями, менее общие, более точные и выделенные интерфейсы между ними.
Однако с развитием облачных вычислений, и особенно легких контейнеров, изолирующих любые технологии, возрастанием скорости обмена данных по сети, и общей надежности и встроенной устойчивости к отказам, предоставляемых основными провайдерами облака, стало особенно удобно разбивать приложение на множество более мелких приложений. Легко обмениваясь информацией (как правило, это текстовый формат HTTP/JSON, или двоичный формат gRPC), они предоставляют друг другу сфокусированные, маленькие услуги и сервисы, независимые от использованных для их реализации технологий.
Подобное разбиение идеально ложится на разделение бизнес-функций в общем приложении, а что еще лучше, великолепно разделяет обязанности большой команды инженеров на независимые, маленькие команды, способные к экспериментам, быстрым изменениям и использованию любых технологий.
Монолиты
Красивое слово монолит (monolith) описывает хорошо известный, наиболее часто используемый способ разработки программного продукта. Ваша команда определяется с набором требований к продукту и делает примерный выбор технологий и архитектуры. Далее вы создаете репозиторий для исходного кода (чаще всего GitHub), выделяете общую функциональность и библиотеки (пытаясь сократить количество повторяющегося кода, DRY dont repeat yourself!), и вся команда добавляет новый код и функциональность в этот единственный репозиторий, как правило, через ветви кода (branch). Код компилируется единым блоком, собирается одной системой сборки, и все модульные тесты прогоняются также сразу, для всего кода целиком. Рефакторинг и масштабные изменения в таком коде сделать довольно просто.