5 техник описания интеграции между системами и взаимодействия микросервисов

интеграция информационных систем примеры описания, UML-диаграммы, диаграммы C4 пример, обучение аналитиков, курсы системного анализа, Школа прикладного бизнес-анализа

Как описать интеграцию между системами и взаимодействие микросервисов в текстовом и графическом видах: схемы C4, UML-диаграммы и таблицы с практическими примерами.

Постановка задачи, описание контекста и структуры

Чтобы продемонстрировать рассматриваемый вопрос на практическом примере, возьмем микросервисную систему из области электронной коммерции. Сперва опишем системный контекст в виде диаграммы С4.

Диаграмма контекста С4
Диаграмма контекста С4
@startuml
!include <C4/C4_Container>
title Уровень контекста

LAYOUT_LEFT_RIGHT()

Person(User, "Пользователь", "Не аутентифицированный пользователь")
Person(Manager, "Менеджер", "Менеджер интернет-магазина")
Person(Customer, "Покупатель", "Клиент, покупатель товаров")

Manager -|> User
User <|- Customer

System(IShop, "I-Shop", "Система с микросервисной архитектурой")
Rel(Manager, IShop, "Управлять поставщиками и товарами")
Rel(Customer, IShop, "Управлять заказами")
Rel(User, IShop, "Смотреть каталог")

System_Ext(DeleveryExtSys, "Внешняя служба доставки")
System_Ext(PaymentExtSys, "Внешний шлюз онлайн-оплаты")
System_Ext(NotificationExtSys, "Внешняя система уведомлений", "TG, Email, WhatsApp, SMS")

Rel(NotificationExtSys, Manager, "Показать уведомление")
Rel( NotificationExtSys, Customer,"Показать уведомление")
Rel(IShop, NotificationExtSys, "Отправить уведомление")
Rel(IShop, PaymentExtSys, "Оплатить заказ")
Rel(IShop, DeleveryExtSys, "Запросить параметры доставки")

SHOW_LEGEND()
@enduml

На уровне контейнеров покажем 3-хзвенную архитектуру системы.

Диаграмма контейнеров С4
Диаграмма контейнеров С4
@startuml
!include <C4/C4_Container>
title Уровень контейнеров
LAYOUT_LEFT_RIGHT()
Person(User, "Пользователь", "Не аутентифицированный пользователь")
Person(Manager, "Менеджер", "Менеджер интернет-магазина")
Person(Customer, "Покупатель", "Клиент, покупатель товаров")
Manager -|> User
User <|- Customer
System_Boundary(c1, "I-Shop") {
    Container(frontend, "Клиентское приложение (Frontend)", "HTML, JS", $descr="Веб-страницы для отображения и запроса данных, а также отправки команд")
    Container(backend, "Серверное приложение (Backend)", "Python", $descr="Серверное веб-приложение с МСА")
    ContainerDb(shared_db, "Общая БД", "PostgreSQL", "Общая база данных")
    ContainerDb(paths_db, "БД путей", "Neo4j", "Графы для расчета логистики")
}

Rel(Manager, frontend, "Управлять заказами, поставщиками и товарами")
Rel(Customer, frontend, "Управлять заказами")
Rel(User, frontend, "Смотреть каталог")

Rel(frontend, backend, "запросы", "HTTPS")
Rel(frontend, backend, "команды", "HTTPS")

Rel(backend, shared_db, "управлять товарами, заказами и пользователями", "postgres")
Rel(backend, paths_db, "рассчитать оптимальный путь", "neo4j+s")

System_Ext(DeleveryExtSys, "Внешняя служба доставки")
System_Ext(NotificationExtSys, "Внешняя система уведомлений", "TG, Email, WhatsApp, SMS")

System_Ext(PaymentExtSys, "Внешний шлюз онлайн-оплаты")
Rel(NotificationExtSys, Manager, "Показать уведомление")
Rel(NotificationExtSys, Customer, "Показать уведомление")
Rel(backend, NotificationExtSys, "Отправить уведомление")
Rel(backend, PaymentExtSys, "Оплатить заказ")
Rel(backend, DeleveryExtSys, "Запросить стоимость и время доставки")

SHOW_LEGEND()
@enduml

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

Бизнес-задача Сервис
Управлять заказами Сервис Заказы
Управлять поставщиками и товарами Сервис Склад
Управлять упаковкой товаров в заказ Сервис Склад
Определить время и стоимость доставки Сервис Доставка
Оплатить заказ Сервис Оплаты
Отправить уведомление об изменении статуса заказа Сервис Уведомлений

Однако, несмотря на разделение микросервисов, бизнес-операции часто реализуются как межсервисные транзакции. Например, при создании заказа предполагается вычисление его времени и стоимости доставки в зависимости от локации товаров на складах и распределительных центрах магазина, а также отправка уведомления об этом клиенту.

UML-диаграмма вариантов использования (Use Case)
UML-диаграмма вариантов использования (Use Case)
@startuml
title: Управление заказами в интернет-магазине
skinparam packageStyle rectangle
actor Покупатель AS C
actor Менеджер AS M
actor Сервис_Доставка AS D
actor Сервис_Склад AS W
actor Сервис_Уведомлений AS MS
rectangle Сервис_Заказы {
    C --> (Создать заказ)
    (Создать заказ) ..> (Найти локацию \nтоваров на складах) : include
    (Создать заказ) ..> (Определить время\n и стоимость доставки) : include
    (Создать заказ) ..> (Отравить уведомление\n о параметрах доставки) : include
    C --> (Посмотреть заказ)
    (Посмотреть заказ) <.. (Изменить заказ) : extend
    (Посмотреть заказ) <.. (Отменить заказ) : extend
    (Найти локацию \nтоваров на складах) -- W
    (Определить время\n и стоимость доставки) -- D
    (Отравить уведомление\n о параметрах доставки) -- MS
    M --> (Посмотреть заказ)
}
@enduml

Поэтому на уровне компонентов C4 раскроем, что серверная часть состоит из взаимодействующих микросервисов, а не одного приложения.

Диаграмма компонентов С4
Диаграмма компонентов С4
@startuml
!include <C4/C4_Container>
title Уровень компонентов

Person(Customer, "Покупатель", "Клиент, покупатель товаров")
System_Ext(DeleveryExtSys, "Внешняя служба доставки")
System_Ext(NotificationExtSys, "Внешняя система уведомлений", "TG, Email, WhatsApp, SMS")

System_Boundary(c1, "I-Shop") {
System(frontend, "Клиентское приложение (Frontend)", "HTML, JS", $descr="Веб-страницы для отображения и запроса данных, а также отправки команд")
    Container_Boundary(c2, "I-Shop Backend") {
    Container(orderService, "Сервис Заказы", "Создание и управление заказами")
    Container(warehouseService, "Сервис Склад", "Управление товарами и поставщиками")
    Container(deliveryService, "Сервис Доставка", "Управление доставкой")
    Container(notificationService, "Сервис Уведомлений", "Отправка уведомлений")
}
LAYOUT_LEFT_RIGHT()
    ContainerDb(kafka, "Message Broker", "Apache Kafka", "Брокер сообщений для асинхронного взаимодействия")
    ContainerDb(shared_db, "Общая БД", "PostgreSQL", "Общая база данных")
    ContainerDb(paths_db, "БД путей", "Neo4j", "Графы для расчета логистики")
}

Rel(frontend, orderService, "Создать заказ")

Rel(notificationService, NotificationExtSys, "Отправить уведомление")
Rel(deliveryService, DeleveryExtSys, "Запросить стоимость и время доставки")


Rel(orderService, kafka, "Опубликовать заказ")
Rel(orderService, shared_db, "управлять заказами", "postgres")
Rel(kafka, warehouseService, "Получить заказ")
Rel(warehouseService, kafka, "Опубликовать локации товаров на складах")
Rel(warehouseService, shared_db, "управлять товарами и поставщиками", "postgres")

Rel(kafka, deliveryService, "Получить заказ")
Rel(kafka, deliveryService, "Получить локации товаров на складах")
Rel(deliveryService, kafka, "Опубликовать время и стоимость доставки")
Rel(deliveryService, paths_db, "расчитать оптимальный путь", "neo4j+s")

Rel(kafka, notificationService, "Получить заказ")
Rel(kafka, notificationService, "Получить время и стоимость доставки")

Rel(Customer, frontend, "Управлять заказами")

SHOW_LEGEND()
@enduml

Описание последовательности и деталей интеграции

Согласно ранее представленной UML-диаграмме Use Case, поиск товаров на складах, вычисление параметров доставки и отправка уведомлений об этом предполагает взаимодействие с внешними системами, т.е. другими микросервисами. В табличном виде представить это можно как реестр интеграционных вариантов использования. А, поскольку интеграция между системами предполагает обмен данными, можно добавить сведения об этих данных характере самого информационного обмена, составив такую таблицу:

Бизнес-задача (исходный ВИ) Интеграционный ВИ Сервис-инициатор Сервис-приемник Частота взаимодействия

(по расписанию или по событию)

Характер взаимодействия

(синхронно, асинхронно)

Полезная нагрузка запроса Полезная нагрузка ответа (для синхронного взаимодействия) или результата обработки (для асинхронного)
Максимальный объем Формат Схема данных Максимальный объем Формат Схема данных
UC-1. Создать заказ UC-1.1 Найти локацию товаров на складах Сервис Заказов Сервис Склад По событию Асинхронно 1 МБ JSON См. А 1 МБ JSON См.Б
UC-1.2 Определить время и стоимость доставки Сервис Заказов Сервис Доставка По событию Асинхронно 1 МБ JSON См. А 1 МБ JSON См.В
Сервис Склад См.Б
UC-1.3 Отправить уведомление о параметрах доставки Сервис Заказов

Сервис Доставка

Сервис Уведомлений По событию Асинхронно 1 МБ JSON См. А

См.В

1 МБ JSON См.Г

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

  • А (схема полезной нагрузки сообщения с заказами):
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "order": {
      "type": "number"
    },
    "date": {
      "type": "string"
    },
    "sum": {
      "type": "number"
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          }
        },
        "required": [
          "name",
          "quantity"
        ]
      }
    },
    "location": {
      "type": "string"
    }
  },
  "required": [
    "order",
    "date",
    "sum",
    "products",
    "location"
  ]
}
  • Б (схема полезной нагрузки сообщения с локациями товаров):
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "order": {
      "type": "number"
    },
    "date": {
      "type": "string"
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "location": {
                  "type": "string"
                },
                "quantity": {
                  "type": "number"
                }
              },
              "required": [
                "location",
                "quantity"
              ]
            }
          }
        },
        "required": [
          "name"
        ]
      }
    }
  },
  "required": [
    "order",
    "date",
    "products"
  ]
}
  • В (схема полезной нагрузки сообщения с параметрами доставки заказа):
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "order": {
      "type": "number"
    },
    "date": {
      "type": "string"
    },
    "delivery_time": {
      "type": "string"
    },
    "delivery_price": {
      "type": "number"
    }
  },
  "required": [
    "order",
    "date",
    "delivery_time",
    "delivery_price"
  ]
}
  • Г (схема полезной нагрузки сообщения с параметрами заказа и его доставки):
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "Hello": {
      "type": "string"
    },
    "order": {
      "type": "number"
    },
    "date": {
      "type": "string"
    },
    "sum": {
      "type": "number"
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          }
        },
        "required": [
          "name",
          "quantity"
        ]
      }
    },
    "location": {
      "type": "string"
    },
    "delivery_time": {
      "type": "string"
    },
    "delivery_price": {
      "type": "number"
    }
  },
  "required": [
    "Hello",
    "order",
    "date",
    "sum",
    "products",
    "location",
    "delivery_time",
    "delivery_price"
  ]
}

Поскольку в моем случае взаимодействие является асинхронным и реализовано через Apache Kafka, сервис Заказы является продюсером отправляемых событий, а сервисы Склад и Доставка – потребителями. Если взаимодействие между ними организовано в хореографическом стиле, т.е. без центрального управляющего звена Оркестратор, который подписан на все события от целевых сервисов и формирует для них задания, также публикуя события в Kafka, то визуализировать публикацию и прием сообщений можно в виде следующей UML-диаграммы последовательности.

UML-диаграмма последовательности
UML-диаграмма последовательности
@startuml
title Создать заказ
autonumber
actor Клиент AS C
participant Сервис_Заказов AS Z
participant Kafka AS K
participant Сервис_Склад AS W
participant Сервис_Доставка AS D
participant Сервис_Уведомлений AS M
C -> Z: создать(Заказ)
activate Z
Z -\ K: опубликовать\n(Заказ)
activate K
W -> K: получить(Заказ)
activate W
K --> W: Заказ
W -> W: найти товары\n(Заказ)
W -\ K: опубликовать(локации товаров)
par
D -> K: получить(Заказ)
activate D
K --> D: Заказ
D -> K: получить(локации товаров)
K --> D: локации товаров
end par
D ->D : вычислить время \nи стоимость \nдоставки(локации \nтоваров, Заказ)
D -\ K: опубликовать(параметры доставки)
M -> K: получить(параметры доставки)
K -->M: параметры доставки
M -> M: сформировать \nуведомление\n(параметры \nдоставки)
M -\C : отправить уведомление(параметры доставки)
@enduml

Это визуальное отображение взаимодействия между сервисами, помимо которого следует также сделать текстовое описание вариант использования, пример которого я ранее показывала здесь.

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

  • диаграммы C4, чтобы наглядно показать контекстное окружение и состав всей системы;
  • таблица с реестром вариантов использования;
  • UML-диаграммы вариантов использования и последовательности, чтобы визуализировать взаимосвязь между рассматриваемыми сценариями и логику их выполнения;
  • текстовая форма Use Case;
  • форматы и схемы данных полезной нагрузки запросов и ответов сервисов.

Можно расширить этот перечень, включив в таблицу с описанием взаимодействия сервисов максимально допустимое время задержки, что особенно актуально при синхронном обмене данными, а также статусы HTTP-ответов в этом же случае. Примеры того, как это выглядит на UML-диаграмме последовательности, я описывала здесь.

Освоить все эти и другие техники вы сможете на моих курсах в Школе прикладного бизнес-анализа на базе нашего лицензированного учебного центра обучения и повышения квалификации системных и бизнес-аналитиков в Москве:

 

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Поиск по сайту

Напишите нам, мы онлайн!