Управління розподіленими транзакціями за допомогою патерну Saga

pic

У світі мікросервісів управління розподіленими транзакціями є значною проблемою. Традиційні монолітні архітектури обробляють транзакції в межах однієї бази даних, забезпечуючи властивості ACID (Атомарність, Узгодженість, Ізоляція, Стійкість). Однак у мікросервісній архітектурі кожен сервіс зазвичай має свою базу даних, що ускладнює підтримку цих властивостей на декількох сервісах. Ось тут і вступає в гру патерн Saga.

Виклик: Розподілені транзакції в мікросервісах

Уявіть собі додаток для електронної комерції, де робочий процес обробки замовлення включає кілька мікросервісів: Сервіс замовлень, Сервіс платежів, Сервіс інвентаризації та Сервіс доставки. Кожен сервіс виконує локальну транзакцію для реалізації своєї функціональності. Забезпечити узгодженість даних між цими сервісами складно, особливо коли один з сервісів дає збій. Традиційні протоколи двофазної фіксації (2PC) не підходять для сучасних мікросервісів через їх складність і витрати на продуктивність.

Патерн Saga як рішення

Патерн Saga вирішує цю проблему, розбиваючи велику транзакцію на низку менших, незалежних транзакцій. Кожна транзакція оновлює сервіс і публікує подію для ініціації наступної транзакції. Якщо транзакція не вдається, виконуються компенсуючі транзакції для скасування змін, внесених попередніми транзакціями.

Що таке патерн Saga?

pic

Патерн Saga був вперше представлений у науковій роботі Гектора Гарсії-Моліни та Кеннета Салема в 1987 році. Він набув популярності з розвитком мікросервісних архітектур, оскільки забезпечує управління розподіленими транзакціями без необхідності використовувати традиційні протоколи двофазної фіксації.

Підходи до реалізації патерну Saga:

Хореографія:

Кожен сервіс генерує та споживає події для координації саги. Не потрібен центральний координатор.

pic

  • Цей метод добре працює для простих робочих процесів з кількома сервісами в сазі, які не потребують координації. Немає єдиної точки відмови, оскільки відповідальність розподілена, і для реалізації чи обслуговування не потрібні додаткові сервіси.
  • Але коли ваша система розростається, все стає складніше. Важко відслідковувати, які сервіси повинні слухати які команди. Кожен сервіс може залежати від інших у циклі, оскільки вони повинні обробляти команди один одного. Тестування всього разом стає дуже важким, оскільки всі сервіси повинні бути запущені для симуляції транзакції.

Оркестрація:

Центральний оркестратор керує сагами, явно викликаючи кожен крок.

pic

Чому патерн Saga став популярним?

  1. Тривалі транзакції: У мікросервісах транзакції часто охоплюють кілька сервісів і можуть тривати довго. Патерн Saga дозволяє розбивати ці транзакції на менші, керовані кроки, кожен з яких можна виконати незалежно.
  2. Патерни взаємодії: Патерн Saga підтримує як хореографію, так і оркестрацію для взаємодії. Ця гнучкість робить його легшим для реалізації і управління складними робочими процесами.
  3. Уникання блокування: Традиційні протоколи двофазної фіксації вимагають блокування ресурсів, що може призвести до проблем із продуктивністю та зниженням масштабованості. Патерн Saga уникатиме блокувань, використовуючи компенсуючі транзакції для обробки відмов, що гарантує, що ресурси не будуть зайняті без необхідності.

Реальний приклад: Використання Uber

Uber використовує патерн Saga для управління розподіленими транзакціями в своїй платформі для замовлення поїздок. Ось як це працює:

1.
Ініціація запиту на поїздку:

  • Сервіс поїздки створює запит на поїздку і публікує подію "Запит на поїздку".

2. Призначення водія:

  • Сервіс водіїв слухає подію "Запит на поїздку", призначає водія та публікує подію "Водія призначено".
  • Якщо призначення водія не вдається, виконується компенсуюча транзакція для скасування запиту на поїздку.

3. Початок поїздки:

  • Сервіс поїздки слухає подію "Водія призначено", починає поїздку та публікує подію "Поїздка почалась".
  • Якщо початок поїздки не вдається, виконується компенсуюча транзакція для скасування призначення водія.

4. Завершення поїздки:

  • Сервіс поїздки слухає подію "Поїздка почалась", завершує поїздку та публікує подію "Поїздка завершена".
  • Якщо завершення поїздки не вдається, виконується компенсуюча транзакція для повторного запуску поїздки.

Реальний приклад: Банківська сфера

У банківській сфері патерн Saga використовується для управління розподіленими транзакціями, такими як переведення грошей між рахунками. Ось як це працює:

1. Ініціація переказу:

  • Сервіс переказів ініціює переказ і публікує подію "Переказ ініційовано".

2. Дебетування рахунку:

  • Сервіс рахунків слухає подію "Переказ ініційовано", дебетує рахунок відправника і публікує подію "Дебет успішно виконано".
  • Якщо дебетування не вдається, виконується компенсуюча транзакція для скасування переказу.

3. Кредитування рахунку:

  • Сервіс рахунків слухає подію "Дебет успішно виконано", кредитує рахунок одержувача і публікує подію "Кредит успішно виконано".
  • Якщо кредитування не вдається, виконується компенсуюча транзакція для скасування дебету.

Реалізація патерну Saga в .NET

Ось простий приклад того, як можна реалізувати патерн Saga в .NET за допомогою підходу оркестрації:

public class RideSaga  
{  
 private readonly IRideService _rideService;  
 private readonly IDriverService _driverService;  

 public RideSaga(IRideService rideService, IDriverService driverService)  
 {  
 _rideService = rideService;  
 _driverService = driverService;  
 }  

 public async Task StartRideSagaAsync(RideRequest request)  
 {  
 try  
 {  
 // Крок 1: Створення запиту на поїздку  
 var ride = await _rideService.CreateRideAsync(request);  
 // Крок 2: Призначення водія  
 var driver = await _driverService.AssignDriverAsync(ride.Id);  
 // Крок 3: Початок поїздки  
 await _rideService.StartRideAsync(ride.Id);  
 // Крок 4: Завершення поїздки  
 await _rideService.CompleteRideAsync(ride.Id);  
 }  
 catch (Exception ex)  
 {  
 // Обробка помилки та виконання компенсуючих транзакцій  
 await _rideService.CancelRideAsync(request.Id);  
 await _driverService.UnassignDriverAsync(request.Id);  
 // Логування помилки  
 Console.WriteLine($"Saga не вдалася: {ex.Message}");  
 }  
 }  
}

Переваги та виклики

Переваги

  • Масштабованість: Асинхронна обробка дозволяє краще масштабувати систему.
  • Стійкість: Розбиваючи транзакції на менші кроки, система може більш ефективно справлятися з помилками.
  • Гнучкість: Підтримка як хореографії, так і оркестрації.

Виклики

  • Складність: Реалізація та управління компенсуючими транзакціями може бути складною.
  • Ніхайна узгодженість: Забезпечення в кінцевому підсумку узгодженості вимагає ретельного проектування та моніторингу.

Висновок

Патерн Saga є потужним інструментом для управління розподіленими транзакціями в мікросервісах, особливо в таких сферах, як банківська справа і замовлення поїздок, де критично важливі узгодженість і надійність даних. Розуміючи та реалізуючи цей патерн, ви можете створювати більш стійкі та масштабовані системи.

Перекладено з: Managing Distributed Transactions with the Saga Pattern

Leave a Reply

Your email address will not be published. Required fields are marked *