Микросервисная архитектура в настоящее время очень популярна. Много кто ее использует, хотя и не всегда на все 100%. Но для успешного применения такого подхода, каждый из микросервисов должен:
независимо развиваться (эволюционировать);
независимо тестироваться;
независимо развертываться.
Реальная польза от микросервисов будет при соблюдении всех этих условий. Иначе развертывание новых версий будет требовать координации с другими командами, каскадных изменений всех зависимых сервисов и молитв о том, чтобы все изменения прошли успешно. Каскадный откат изменений может стать серьезным приключением.
Независимое развитие
Приложения со временем эволюционируют. Это неизбежный процесс: бизнес не может заранее предугадать всю необходимую функциональность, а разработчики не могут реализовать все за неделю.
Например, если говорить о REST, то есть миллион статей об эволюции API, в которых рассказывается об обновлении API без влияния на клиентов.
А если вы используете очереди сообщений (например, Kafka), то обратите внимание на Avro и не начинайте сразу с JSON. Avro поддерживает эволюцию схемы и совместимость, что экономит много времени в будущем.
Проприетарные протоколы остаются на вашей совести. Вероятно, вам придется изобретать велосипед.
Независимое тестирование
На словах с тестированием обычно все просто, но на деле обработка одного запроса требует обращения к различным сервисам, которые, в свою очередь, зависят от других сервисов. И тестирование перестает быть таким уж независимым.
Я рекомендую познакомиться со Spring Cloud Contract WireMock и Spring REST Docs, которые позволят вам:
писать документацию на основе тестов;
создавать заглушки (стабы) для вашего сервиса;
использовать созданную заглушку в тестах других микросервисов для имитации обращений к сервису.
Пример использования Spring Cloud Contract:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = MOCK)
@AutoConfigureMockMvc
@AutoConfigureStubRunner(stubsMode = LOCAL, ids = "com.github.wirtsleg:my-service-stub:+:stubs:8090")
public abstract class AbstractIntegrationTest {
...
}
Таким образом, у вас будет меньше беспокойства о том, как зависимые сервисы взаимодействуют в реальности, потому что вы используете стабы.
Независимое развертывание
Не все могут себе позволить остановку сервиса при обновлении. Но это неизбежно, если есть циклические зависимости (новому сервису A нужен новый B, новому B нужен новый C, новому C нужен новый A). И я уверен, что ни у кого нет желания координировать свои действия с другими командами для релиза новой версии своего микросервиса. О том, как решить эту проблему, мы говорили ранее в разделе о независимом развитии. Но есть еще один момент: сервис должен уживаться со своей предыдущей версией.
Вы, вероятно, слышали термины "сине-зеленое развертывание" (Blue-Green deployment) и "канареечное развертывание" (Canary deployment). Эти подходы предполагают, что новая и старая версии будут сосуществовать какое-то время. А это влечет за собой использование одной и той же базы данных, распределенного кэша и т.д.
Нам нужно поддерживать совместимость с одной предыдущей версией.
При использовании реляционных баз данных, новая версия, скорее всего, приведет к некоторым миграциям в базе данных. Таким образом, если вам нужно изменить поле в версии 1, то лучше сделать это в три этапа:
Добавить новое поле в версии 2 и поддерживать оба поля.
Начать использовать только новое поле в версии 3.
Удалить старое поле в версии 4.
Таким образом, если с новой версией пойдет что-то не так, то предыдущая версия будет продолжать работать нормально, и вам не нужно останавливать сервис и восстанавливать базу данных.
Аналогичный подход применяется к распределенному кешу и NoSQL-базам данных.
Заключение
Это все требует усилий. Одновременная поддержка нескольких версий API, подготовка тестовых заглушек (особенно в первый раз), изменение структуры данных в несколько шагов — все это занимает время. В результате на релиз может уйти больше времени. Но эта дополнительная работа необходима, чтобы в полной мере использовать преимущества микросервисной архитектуры.
Материал подготовлен нашим экспертом - Александром Коженковым и опубликован в преддверии старта курса «Microservice Architecture». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.
derikn_mike
знаю одну такую независимость....
Имеет очень большую таблицу в одной базе (сервисе контента)
И имеем статистику к этому контенту в базе 2 (сервисе статистике)
И вдруг понадобилась сделать join по ним с фильтрами для базы1 и сортировкой по базе2.
Удачи!!!
BugM
Заводим базу 3 в которую льем данные из первых двух. Назовем ее "Аналитическим Хранилищем" чтобы бюджет полегче выбить было.
Обычные будни энтерпрайза.
derikn_mike
тоесть вы хотите
1) совместить абсолютно разные "микросервисные" которые по логике и смыслу работали идеально не зная об друг друга совместить в одну?
2) И самое главное это производительность , вы хотите в одну базу слить эти две логике , у которых в А - редчайшие обновления , Б(статистика) - невероятно сильная нагрузка и апдейты млн раз в секунду. Вы хотите в вашем подходе теперь чтобы тормозила невиновная А из за этого?
BugM
Зачем? Все остаётся как есть. Все сервисы и дальше работают со своей базой.
Просто рядом поднимается ещё одна в которую льются данные из этих двух. Репликацией, бекапом, кодом. Зависит от. Решений много и они все могут работать как угодно.
Когда нужен запрос с join делаем его из этой третьей БД. Учитывая ограничения на которые мы подписались при выборе алгоритма заливки данных.