Я практически уверен, что все хотят создавать легко
масштабируемые приложения, верно? А кто нет, все хотят. Если это так, вы, должно быть,
сталкивались со словами "Cloud Native". Этот подход похож на ангела, который, кажется, что
может решить большинство проблем связанных с масштабированием приложения.
Cloud Native - это подход, используемый при разработке приложений,
который позволяет им (приложениям) соответствовать следующим критериям: быть
эксплуатируемыми(т.е. ими можно пользоваться, их можно менять внешними инструиментами),
быть наблюдаемыми(т.е. можно с помощью какого-либо инструмента узнать текущее состояние
приложение и его производительность), быть эластичными(т.е. они могут изменяться в
размерах в рамках ресурсов и в зависимости от нагрузки), быть отказоустойчивыми(их можно
быстро восстановить после падения), быть динамичными(конфигурируемыми, деплой, в общем,
к нему должна быть возможность применить практики DevOps).
Да, вы поняли это корректно: это именно подход. Не фреймворк.
Не пошаговая инструкция. И, как следствие, существуют миллионы таких Cloud Native-подходов
чтобы достичь этого вожделенного эффекта «Мокша».
Один из ключевых принципов Cloud Native - это разделение приложения на
микросервисы. Микросервисы представляют собой крошечные (иногда не особо)
программные модули, которые могут работать независимо друг от друга. Они могут
иметь зависимости от других микросервисов или даже от базы данных, но зависимость должна
быть слабой - т.е. каждый микросервис если он и имеет зависимость от другого, должен быть
готов к тому, что другой перестанет существовать. Микросервисы взаимодействуют между собой
посредством «общения» - т.е. посредством диалога между собой - отправления
запросов и получения ответов.
Это означает, что каждый микросервис находится в отдельном репозитории и может
быть обновлен независимо от других. Для DevOps-разработчиков также есть возможность
организовывать непрерывную доставку для микросервиса не зависимо от других
микросервисов.
И это приводит нас к самому важному вопросу.
Как заставить микросервисы общаться?
Даже не касаясь сложности соблюдения восходящей
совместимости API для микросервисов, просто заставить их общаться не так просто как
может показаться на первый взгляд. Есть несколько параметров, которые необходимо учитывать.
Это пропускная способность, задержка и масштабируемость.
В настоящее время существует множество классификаций способов общения между
микросервисами.
Синхронный (блокирующий) и асинхронный (неблокирующий) используются довольно часто, но
я предполагаю, что это в основном характеристики языка программирования.
Я также планирую не заострять внимание на режимах "дуплекс" или "полудуплекс", т.к. сейчас
очень легко использовать один или даже оба в большинстве облачных архитектур.
Итак, давайте погрузимся в детали.
Архитектура без брокера
Что на изображении: здесь мы заставляем наши микросервисы
общаться напрямую друг с другом. Вы можете использовать HTTP для
традиционного запроса-ответа или использовать веб-сокеты (или HTTP2) для потоковой передачи.
Между двумя и более микросервисами нет абсолютно никаких промежуточных узлов
(кроме маршрутизаторов и балансировщиков нагрузки). Вы можете подключиться к любому
микросервису напрямую, при условии, что вы знаете их адрес службы и используемый ими
API.
Звучит довольно просто, верно? Это в значительной степени так. Есть
замечательные протоколы, такие как GRPC, чтобы сделать жизнь намного проще.
Плюсы:
- Низкая задержка: этот метод имеет минимально возможную задержку. Здесь нет посредников.
Это быстро. Ограничения могут быть в основном из-за плохой реализации API. Но опять же,
такие инструменты как GRPC, обеспечивают максимальную производительность на уровне API
- Простота реализации: архитектуру без посредников легко визуализировать и реализовать.
Это делает жизнь намного проще и мир становится счастливее.
- Простая отладка: этот метод довольно прост в отладке, особенно по сравнению со
следующим, о котором я собираюсь рассказать. Отладка или отслеживание ошибок - это очень
важная тема в распределенных системах. Это становится еще более важным, когда вы
релизитесь несколько раз в день.
- Высокая пропускная способность: в этом методе больше циклов CPU фактически расходуется
на выполнение работы, а не на маршрутизацию. Сейчас это может быть не так очевидно, но
архитектура с брокером продемонстрирует это более явно. Неудивительно, что большинство
API баз данных на самом деле используют дизайн без посредников.
Минусы:
- Безопасность данных: В такой конструкции обнаружение сервиса имеет первостепенное
значение. Механизм обнаружения сервисов должен быть достаточно гибким и реагирующим,
чтобы отражать последнее состояние кластера.
- Много ресурсов простаивает: представьте, если бы все микросервисы общались друг с
другом. При этом было бы достаточно много соединений. В данной схеме этого нет, а значит
большое количество времени микросервисы простаивают. В результате много ресурсов
тратится впустую из-за этого.
- Много ресурсов простаивает: представьте, если бы все микросервисы общались друг с
другом. При этом было бы достаточно много соединений. В данной схеме этого нет, а значит
большое количество времени микросервисы простаивают. В результате много ресурсов
тратится впустую из-за этого.
- Взаимозависимость: по своей природе конструкции без посредников тесно связаны.
Представьте, что у вас есть микросервис для обработки онлайн-платежей. Теперь вы хотите,
чтобы другой микросервис в режиме реального времени обновлял количество платежей,
совершаемых за минуту. Это потребует от вас внесения изменений в несколько
микросервисов, что нежелательно.
Во многих случаях архитектура без брокера просто не работает. Часто могут
появиться требования, когда необходимо чтобы на одно событие реагировали несколько
микросервисов. В этом случае как раз появляется необходимость в брокере.
На этом я завершаю первую часть статьи. Во второй
части продолжу.