16

В нашей компании мы переходим от огромного монолитного приложения к архитектуре микросервиса. Основными техническими драйверами для этого решения были необходимость иметь возможность масштабировать услуги независимо и масштабируемость разработки - у нас есть десять команд схватки, работающих в разных проектах (или «микро-службах»).Как работать с общим состоянием в архитектуре микросервиса?

Процесс перехода является плавным, и мы уже начали извлекать выгоду из преимуществ этих новых технических и организационных структур. Теперь, с другой стороны, есть главный момент боли, с которым мы боремся: как управлять «состоянием» зависимостей между этими микросервисами.

Приведем пример: один из микросервисов касается пользователей и регистраций. Эта услуга (давайте назовем ее X) несет ответственность за сохранение информации о личности и, таким образом, является основным поставщиком идентификаторов пользователей. Остальные микросервисы сильно зависят от этого. Например, существуют некоторые службы, ответственные за информацию профиля пользователя (A), разрешения пользователя (B), группы пользователей (C) и т. Д., Которые полагаются на эти идентификаторы пользователей и, следовательно, существует потребность в поддержании некоторой синхронизации данных между этими службами (т.е. служба A не должна иметь информацию для пользователя, не зарегистрированного в сервисе X). В настоящее время мы поддерживаем эту синхронизацию, уведомляя изменения состояния (например, новые регистрации) с помощью RabbitMQ.

Как вы можете себе представить, есть many Xs: многие «основные» службы и многие более сложные зависимости между ними.

Основная проблема возникает при управлении различными средами dev/testing. Каждая команда (и, следовательно, каждая служба) должна пройти через несколько окружений, чтобы добавить код в живую: непрерывная интеграция, интеграция в группы, приемочные испытания и живая среда.

Очевидно, что нам нужны все службы, работающие во всех этих средах, чтобы проверить, что система работает в целом. Теперь это означает, что для тестирования зависимых сервисов (A, B, C, ...) мы должны не только полагаться на сервис X, но и на его состояние. Таким образом, нам нужно как-то поддерживать целостность системы и хранить глобальное состояние &.

Наш текущий подход к этому - получение моментальных снимков всех БД из живой среды, что делает некоторые преобразования для сокращения и защиты конфиденциальности данных и распространения их во всех средах перед тестированием в конкретной среде. Очевидно, это огромные накладные расходы, как организационно, так и в вычислительных ресурсах: у нас есть десять непрерывных интеграционных сред, десять интеграционных сред и одна среда приемочного тестирования, которые все нужно «обновить» с помощью этих общих данных из живой и последней версии кода часто.

Мы изо всех сил пытаемся найти лучший способ облегчить эту боль. В настоящее время мы оцениваем два варианта:

  1. использованием Докер-подобных контейнеров для всех этих услуг
  2. имеет две версии каждой службы (один предназначенный для развития этой службы и друг с другом в песочнице, чтобы использоваться остальные команды в их развитие & интеграционного тестирования)

Ни одно из этих решений облегчить боль общих данных между службами. Мы хотели бы знать, как некоторые другие компании/разработчики решают эту проблему, поскольку мы считаем, что это должно быть общим в архитектуре микросервисов.

Как вы, ребята, это делаете? У вас также есть эта проблема? Любая рекомендация?

Извините за подробные объяснения и большое спасибо!

+0

Когда вы говорите _store глобальное и когерентное состояние_, вы имеете в виду то же состояние, что и живая система или какое-то синтетическое состояние? Как я вижу, у вас есть несколько уровней интеграции, где каждый из них ориентирован на конкретный микросервис. – neleus

+0

В идеале микросервис не должен зависеть от другого (а также от его состояния, как указано в @Eugene), но только по четко определенному договору связи. Основным преимуществом такого разложения является независимая доставка. Каждая служба может быть развернута независимо, и это верно для любого уровня среды (для каждой команды, постановки или живого выступления). С этой точки зрения каждая среда может поддерживать собственную реализацию контракта (контрактов). Для разработчиков и командных сред это могут быть сервисные эмуляторы (эмулятор X в вашем примере). Он может быть похож на ваш _sandbox_, Im не уверен. – neleus

+0

Подводя итог.Идея состоит в том, что вам не нужно поддерживать живое состояние во всех средах, потому что большинство из них им не нужны. Единственное исключение - постановка. – neleus

ответ

0

С моей точки зрения, только объекты, пользующиеся услугами, должны иметь состояние. Рассмотрим ваш пример: служба X, ответственная за идентификатор пользователя, службу Ответственность за информацию профиля и т. Д. Предположим, что пользователь Y, у которого есть определенный токен безопасности (который может быть создан, например, с использованием имени пользователя и пароля), должен быть уникальные) записи в систему. Затем клиент, содержащий информацию пользователя, отправляет токен безопасности службе X. Служба X содержит информацию об идентификаторе пользователя, связанном с таким токеном. В случае нового пользователя служба X создает новый идентификатор и сохраняет его. Затем служба X возвращает идентификатор объекту пользователя. Пользовательский объект запрашивает службу A о профиле пользователя, предоставляя идентификатор пользователя. Служба A берет идентификатор и запрашивает службу X, если этот идентификатор существует. Служба X отправляет положительный ответ, тогда служба A может осуществлять поиск информации профиля по идентификатору пользователя или попросить пользователя предоставить такую ​​информацию для ее создания. Та же логика должна работать с службами B и C. Они должны говорить друг с другом, но им не нужно знать о состоянии пользователя.

Несколько слов об окружающей среде. Я бы предложил использовать puppets. Это способ автоматизации процесса развертывания службы. Мы используем куклы для развертывания служб в разных средах. Марионеточный скрипт доступен и обеспечивает гибкую настройку.

+0

Спасибо за ваш ответ и за ваше предложение о Puppet, выглядит действительно интересно. Что касается услуг, позвольте мне подробнее рассказать. Следуя уже установленному примеру, служба X будет отвечать за userIds (это означает, что она каким-то образом хранит пары ). Служба A отвечает за профили пользователей, и поэтому ей необходимо сохранить . –

+0

Как вы упомянули, при извлечении пользовательского файла с учетом userId служба A связывается с Service X, чтобы проверить, активна ли эта учетная запись. При таком подходе служба X и служба A логически независимы, и поэтому их код может развиваться и развертываться независимо, без проблем. –

+0

Чтобы дополнительно объяснить проблему общего состояния, давайте предположим, что мы используем докереподобные контейнеры для наших сервисов. При создании новой среды test/integration/etc контейнеры для службы X и службы A могут быть развернуты в машине/среде. Теперь, что происходит с данными, на которые полагаются оба сервиса? Для того чтобы общая система была последовательной, данные, хранящиеся в сервисе X, и данные, хранящиеся в сервисе А, должны быть согласованными. Это означает, что даже если код служб может быть развернут независимо, данные, которые они используют, не могут. –

1

Попробую переформулировать проблему:

Актеры:

  • X: UserIds (состояние счета)
    • предоставляют услуги, чтобы получить идентификатор (на основе учетных данных) и статус счета
  • A: UserProfile
    • Использование X для проверки статуса учетной записи пользователя. Магазины имя вместе с ссылкой на счет
    • предоставляют услуги, чтобы получить/имя редактирования на основе ID
  • B: UserBlogs
    • Использование X таким же образом.Магазины блог вместе с ссылкой на счет, когда пользователь пишет один
    • , используя для поиска в блоге на основе имени пользователя
    • предоставляют услуги прибудут/редактировать список записей блог, основанные на ID
    • предоставляют услуги для поиска в блоге на основе имени (зависит от A)
  • C: MobileApp
    • обертывания функции X, A, B в мобильное приложение
    • предоставлять все услуги выше, опираясь на четко определенный контракт связи остроумие ч все остальные (следующее @neleus заявления)

Требования:

  1. Работа команды X, A, B, C должен быть отцеплен
  2. интеграция среды для X, A, B, C необходимо обновить с помощью функций latests (для выполнения интеграционных тестов)
  3. Интеграционные среды для X, A, B, C должны иметь «достаточный» набор данных (для выполнения нагрузки t ресы и найти крайние случаи)

После @eugene идеи: имеющие издевается для каждого сервиса, предоставляемого каждой команды позволит 1) и 2)

  • стоимость более развитие от команд
  • также поддержание издевается, а также главная особенность
  • препятствием является тот факт, что у вас есть монолитную систему (не есть набор чистых хорошо определенных/отдельных услуг еще)

Предлагаемое решение:

Что о наличии общей среды с набором основных данных для решения 3)? Все «поставленные услуги» (то есть работающие на производстве) будут доступны. Каждая команда могла выбрать, какие услуги они будут использовать отсюда, и какой из них они будут использовать из своей собственной среды.

Один непосредственный недостаток. Я вижу, что это общие состояния и согласованность данных.

Рассмотрим автоматизированные тесты, проведенные против основных данных, например.г:

  • B изменяет имена (принадлежащие A) для того, чтобы работать на своем блоге сервиса
    • может сломать, или C
  • изменяется состояние счета в целях работать на некоторых сценариях разрешения
    • может сломаться X, B
  • C изменяет все это на тех же счетах
    • брейки всех других

Мастера набор данных быстро становится непоследовательным и теряет свою ценность для 3 требования) выше.

Таким образом, мы могли бы добавить «обычный» уровень на общие основные данные: любой может читать из полного набора, но может только изменять созданные им объекты?

7

На этот раз я прочитал ваш вопрос с разных точек зрения, так что вот «другое мнение». Я знаю, что может быть слишком поздно, но надеюсь, что это поможет в дальнейшем развитии.

Похоже, что shared state является результатом неправильной развязки. В «правильной» архитектуре микросервиса все микросервисы должны быть изолированы функционально, а не логически. Я имею в виду, что все три user profile information (A), user permissions (B), user groups (C) выглядят функционально одинаковыми и более или менее функционально когерентными. Они кажутся единственными user microservice с когерентным хранилищем. Я не вижу здесь причин их развязывания (или, по крайней мере, вы не сказали о них).

Таким образом, настоящая проблема связана с изоляцией микросервиса. В идеале каждый микросервис может жить как полный автономный продукт и поставить четко определенную значение для бизнеса. При разработке архитектуры системы мы разбиваем ее на маленькие логические единицы (A, B, C и т. Д. В вашем случае или даже меньше), а затем определяем функционально-когерентные подгруппы. Я не могу сказать вам точных правил, как это сделать, возможно, некоторых примеров. Сложные связи/зависимости между подразделениями, многие общие термины на их вездесущих языках, поэтому похоже, что такие единицы относятся к одной и той же функциональной группе и, следовательно, к микросервису.

Итак, из вашего примера, поскольку есть единственное хранилище, у вас есть только способ управления своей консистенцией, как и вы.

BTW Интересно, какой фактический способ решения вашей проблемы? Кроме того, если вам нравится моя идея, вы можете принять ее.

 Смежные вопросы

  • Нет связанных вопросов^_^