В чем разница между монолитной, сервис-ориентированной (SOA) и микросервисной архитектурой?

Ответ

Эти архитектурные стили представляют собой эволюцию от тесно связанных систем к слабо связанным, распределенным.

Аспект Монолитная архитектура Сервис-ориентированная архитектура (SOA) Микросервисная архитектура (MSA)
Структура Единое, неделимое приложение. Все компоненты (UI, бизнес-логика, доступ к данным) развертываются вместе. Набор крупных, многофункциональных сервисов (например, "Сервис заказов", "Сервис клиентов"). Набор мелких, автономных сервисов, каждый отвечает за одну бизнес-возможность (например, "Сервис аутентификации", "Сервис уведомлений").
Связность Высокая. Компоненты вызывают друг друга напрямую через методы/функции. Средняя/низкая. Сервисы общаются по сети, часто через ESB (Enterprise Service Bus). Очень низкая. Сервисы общаются по сети через легковесные протоколы (HTTP/REST, gRPC, Messaging).
Масштабирование Горизонтальное масштабирование всей копии приложения, даже если нагрузка только на один модуль. Масштабирование отдельных сервисов, но они сами могут быть крупными. Точное, независимое масштабирование каждого микросервиса в зависимости от нагрузки.
Гранулярность Очень крупная. Крупная (бизнес-сервисы). Мелкая (единая ответственность).
Сложность Низкая на старте, но растет экспоненциально с увеличением кодовой базы («монстролит»). Высокая из-за сложности ESB и управления сервисами. Высокая операционная сложность (оркестрация, мониторинг, отказоустойчивость).

Пример на уровне кода:

// 1. Монолит: Всё в одном проекте
public class OrderService // В проекте MyBigApp.Web
{
    private readonly IEmailSender _emailSender;
    private readonly IInventoryRepository _inventoryRepo;

    public void ProcessOrder(Order order)
    {
        // Прямые вызовы внутри одного процесса
        _inventoryRepo.ReserveItems(order);
        SaveToDatabase(order);
        _emailSender.SendConfirmation(order.UserEmail); // Может упасть и откатить всю транзакцию
    }
}

// 2. Микросервис: Сервис заказов (отдельный проект/контейнер)
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase // Проект: OrderService
{
    [HttpPost]
    public async Task<IActionResult> CreateOrder([FromBody] Order order)
    {
        // Асинхронное взаимодействие с другими сервисами по сети
        await _httpClient.PostAsJsonAsync("http://inventory-service/api/reserve", order);
        await _dbContext.Orders.AddAsync(order);
        // Отправка события в очередь, а не прямой вызов
        await _messageBus.PublishAsync(new OrderCreatedEvent { OrderId = order.Id });
        return Accepted();
    }
}
// Сервис уведомлений (другой проект) подписывается на OrderCreatedEvent и отправляет email.

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

Ответ 18+ 🔞

Давай разберём эту пиздатую табличку про архитектуру, а то у меня уже глаза на лоб лезут от этих умных слов. Сидишь такой, думаешь — ну вот зачем они всё так усложняют, блядь?

Смотри, раньше-то всё было просто, как три копейки. Делаешь ты один здоровенный проект — монолит, ёпта. Всё в одной куче: и интерфейс, и логика, и база. Как будто в одной комнате живут, жрут из одного холодильника и срут в один унитаз. Начинаешь — красота, всё под рукой. Но потом проект растёт, и этот монолит превращается в такого пиздюка-переростка, который бензина жрёт как не в себя, а переехать на новую квартиру — вообще пиздец, всю жизнь потратишь. Хочешь поменять одну формочку на сайте — приходится пересобирать и перезапускать всю эту махину, блядь. Масштабируешь тоже по-дурацки: если у тебя только раздел "О нас" лег от нагрузки, ты всё равно вынужден клонировать всего этого монстра, всю его сраную логику заказов и корзину. Полный атас.

Потом умные дядьки подумали: "Так, бля, это же не дело". И придумали SOA — сервис-ориентированную архитектуру. Типа, давайте резать этого монстра на большие куски, по бизнес-логике: вот сервис заказов, вот сервис клиентов. Звучит вроде логично. Но, сука, они же между собой общаться как будут? А вот через такую хуйню, как ESB — Enterprise Service Bus. Представь себе главную автобусную станцию в городе-миллионнике. Все автобусы (сервисы) через неё ходят. В теории — порядок, централизованное управление. На практике — эта станция становится таким узким горлышком, таким набухшим бутылочным горлом, что любая поломка на ней парализует весь город. Сложность адская, а отказоустойчивость — ниже плинтуса.

И вот, наконец, все охуели от этих центральных шин и родили микросервисы. Смысл — режем не на большие куски, а на мелкие, самостоятельные сервисики. Каждый — за свою одну, чётко очерченную, отвественность. Сервис аутентификации, сервис нотификаций, сервис расчёта доставки. Каждый живёт в своём домике-контейнере, имеет свою базу если надо, и общается с соседями не через общую толкучку, а напрямую, по лёгким протоколам — HTTP или через асинхронные очереди.

Смотри на примере кода, тут всё наглядно.

В монолите было вот так, всё в одном месте:

public void ProcessOrder(Order order)
{
    _inventoryRepo.ReserveItems(order); // Прямой вызов
    SaveToDatabase(order);
    _emailSender.SendConfirmation(order.UserEmail); // И если тут ошибка — вся операция к херам!
}

Видишь? SendConfirmation может тупо упасть, и тогда весь заказ, который уже в базу записался, надо откатывать. Сплошные транзакционные кошмары, блядь.

А в микросервисах это выглядит иначе. Сервис заказов просто делает свою работу и кидает событие в очередь: "Мужики, заказ-то создался, id такой-то".

public async Task<IActionResult> CreateOrder([FromBody] Order order)
{
    // Резервируем товар у inventory-service
    await _httpClient.PostAsJsonAsync("http://inventory-service/api/reserve", order);
    // Сохраняем сам заказ у себя
    await _dbContext.Orders.AddAsync(order);
    // И... ВСЁ! Кидаем событие в шину и не паримся
    await _messageBus.PublishAsync(new OrderCreatedEvent { OrderId = order.Id });
    return Accepted();
}

А где-то там, в другом углу вселенной, живёт сервис уведомлений. Он подписан на события OrderCreatedEvent. Получил такое — тут же отправил письмо клиенту. Упал сервис нотификаций? Да похуй! Событие в очереди повисит, сервис поднимется — обработает. Заказ-то уже создан, всё хорошо.

Ключевой вывод, который в душу въедается: это всё — сплошной компромисс, ёпта. Нет серебряной пули.

  • Монолит — это как жить в общаге. Дёшево, весело, всё рядом. Но когда сосед начинает долбить стену в три ночи, страдают все.
  • SOA — это как переехать в отдельные квартиры, но в один дом с одним консьержем-алкашом (ESB). Если он уснёт — посылки не получает никто.
  • Микросервисы — это как разъехаться по отдельным коттеджам в пригороде. Полная независимость, свой газон, свой забор. Но, бля, чтобы просто чаю попить с соседом, надо машину заводить, ехать по пробкам (сетевые вызовы), а ещё платить за содержание двадцати котельных (операционная сложность оркестрации и мониторинга) вместо одной.

Выбирай, исходя из того, насколько у тебя команда готова к этим операционным пиздюлям и насколько быстро тебе надо масштабировать разные части системы. А то ведь можно и так переусердствовать — наделать кучу микросервисов и получить распределённый монолит, где они все друг от друга наглухо зависят. Вот тогда будет тебе настоящая хиросима в продакшене, чувак.