Как сделать распределённую транзакцию
1️⃣ Как кратко ответить
Для реализации распределённой транзакции в Go можно использовать паттерн "Саги" или протокол двухфазного коммита (2PC). Паттерн "Саги" подходит для микросервисной архитектуры, обеспечивая компенсационные действия в случае неудачи. Протокол 2PC обеспечивает атомарность, но может быть сложным в реализации и менее устойчивым к сбоям.
2️⃣ Подробное объяснение темы
Распределённые транзакции необходимы, когда нужно обеспечить согласованность данных между несколькими системами или сервисами. Это часто встречается в микросервисной архитектуре, где каждый сервис может иметь свою базу данных.
Паттерн "Саги"
Паттерн "Саги" — это последовательность транзакций, где каждая транзакция имеет соответствующее компенсационное действие. Если одна из транзакций не удаётся, выполняются компенсационные действия для всех предыдущих успешных транзакций.
Пример использования паттерна "Саги":
Представим, что у нас есть система бронирования путешествий, состоящая из нескольких микросервисов: бронирование рейса, бронирование отеля и аренда автомобиля. Каждое из этих действий — это отдельная транзакция.
- Начало саги: Бронирование рейса.
- Компенсационное действие: Отмена бронирования рейса.
- Следующая транзакция: Бронирование отеля.
- Компенсационное действие: Отмена бронирования отеля.
- Следующая транзакция: Аренда автомобиля.
- Компенсационное действие: Отмена аренды автомобиля.
Если аренда автомобиля не удалась, выполняются компенсационные действия: отмена бронирования отеля и рейса.
Протокол двухфазного коммита (2PC)
Протокол 2PC обеспечивает атомарность транзакций в распределённых системах. Он состоит из двух фаз: подготовка и фиксация.
Пример использования 2PC:
-
Фаза подготовки:
- Координатор отправляет запрос на подготовку всем участникам транзакции.
- Каждый участник выполняет локальную транзакцию и отвечает "готов" или "отказ".
-
Фаза фиксации:
- Если все участники ответили "готов", координатор отправляет команду на фиксацию.
- Если хотя бы один участник ответил "отказ", координатор отправляет команду на откат.
Пример кода на Go:
package main
import (
"fmt"
"sync"
)
// Участник транзакции
type Participant struct {
name string
}
// Метод подготовки участника
func (p *Participant) Prepare() bool {
fmt.Printf("%s: подготовка\n", p.name)
// Логика подготовки
return true // Возвращает true, если подготовка успешна
}
// Метод фиксации участника
func (p *Participant) Commit() {
fmt.Printf("%s: фиксация\n", p.name)
// Логика фиксации
}
// Метод отката участника
func (p *Participant) Rollback() {
fmt.Printf("%s: откат\n", p.name)
// Логика отката
}
// Координатор транзакции
type Coordinator struct {
participants []*Participant
}
// Метод выполнения двухфазного коммита
func (c *Coordinator) TwoPhaseCommit() {
var wg sync.WaitGroup
prepareChan := make(chan bool, len(c.participants))
// Фаза подготовки
for _, participant := range c.participants {
wg.Add(1)
go func(p *Participant) {
defer wg.Done()
prepareChan <- p.Prepare()
}(participant)
}
wg.Wait()
close(prepareChan)
// Проверка результатов подготовки
commit := true
for result := range prepareChan {
if !result {
commit = false
break
}
}
// Фаза фиксации или отката
if commit {
for _, participant := range c.participants {
participant.Commit()
}
} else {
for _, participant := range c.participants {
participant.Rollback()
}
}
}
func main() {
// Создание участников
p1 := &Participant{name: "Участник 1"}
p2 := &Participant{name: "Участник 2"}
// Создание координатора
coordinator := &Coordinator{
participants: []*Participant{p1, p2},
}
// Выполнение двухфазного коммита
coordinator.TwoPhaseCommit()
}
- Participant: представляет участника транзакции с методами
Prepare,CommitиRollback. - Coordinator: управляет процессом двухфазного коммита, координируя участников.
- TwoPhaseCommit: метод, который выполняет две фазы: подготовку и фиксацию/откат.
Распределённые транзакции сложны в реализации и могут влиять на производительность системы. Паттерн "Саги" более гибок и устойчив к сбоям, тогда как 2PC обеспечивает строгую атомарность, но может быть менее устойчивым в случае отказов. Выбор подхода зависит от требований к согласованности и доступности системы.
🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!
Подписаться