>Java >java지도 시간 >여러 서비스에 걸친 트랜잭션 작업. 광기에 대한 방법.

여러 서비스에 걸친 트랜잭션 작업. 광기에 대한 방법.

Mary-Kate Olsen
Mary-Kate Olsen원래의
2024-11-17 00:21:03782검색

Transactional Operations Across Multiple Services. A Method To The Madness.

마이크로서비스 환경에서 팀이 처리해야 하는 많은 복잡성 중 하나는 트랜잭션입니다. 여러 마이크로서비스에 걸쳐 있는 트랜잭션. 트랜잭션이 일반적으로 단일 데이터베이스와 @Transactional
으로 관리되는 모놀리식 애플리케이션과 달리 참고로 마이크로서비스에서는 각 서비스에 자체 데이터베이스가 있는 경우가 많아 분산 트랜잭션이 더 복잡해집니다. Spring Boot에서 이러한 분산 트랜잭션을 효과적으로 처리하는 방법에 대한 가이드는 다음과 같습니다.

먼저 거래가 무엇인지에 대한 동의부터 시작하겠습니다.

트랜잭션은 컴퓨팅 또는 데이터베이스 환경에서 분할할 수 없는 단일 작업으로 처리되는 작업 단위입니다. 이는 모두 함께 성공하거나 함께 실패해야 하는 일련의 작업 또는 단계를 나타내며, 예상치 못한 이벤트(정전 또는 네트워크 장애 등)가 발생하는 경우에도 데이터 일관성과 무결성을 보장합니다.

데이터베이스 컨텍스트에서 트랜잭션에는 레코드 생성, 업데이트 또는 삭제와 같은 여러 쿼리가 포함될 수 있습니다. 트랜잭션은 일반적으로 ACID 속성으로 알려진 네 가지 필수 속성을 따릅니다.

아. 원자성- 트랜잭션 내의 모든 작업은 단일 단위로 처리됩니다. 모든 작업이 성공하거나 아무 작업도 수행되지 않습니다.

ㄴ. 일관성 - 트랜잭션은 시스템을 유효한 상태에서 다른 상태로 가져와 데이터 유효성을 유지합니다.

ㄷ. 격리 - 트랜잭션은 격리되어 실행됩니다. 즉, 중간 상태가 다른 트랜잭션에 표시되지 않습니다.

디. 내구성 - 트랜잭션이 커밋되면 해당 변경 사항은 영구적이며 시스템 충돌에도 살아남습니다.


단편소설

분주한 전자상거래 앱에서 고객 Alice가 새 노트북, 액세서리 및 특급 배송을 주문한다고 상상해 보세요. 그녀의 주문이 OrderSagaOrchestrator가 관리하는 시스템을 통해 어떻게 흘러가는지에 대한 비하인드 스토리는 다음과 같습니다.

분주한 전자상거래 앱에서 고객 Alice가 새 노트북, 액세서리 및 특급 배송을 주문한다고 상상해 보세요. 그녀의 주문이 OrderSagaOrchestrator가 관리하는 시스템을 통해 어떻게 흘러가는지에 대한 비하인드 스토리는 다음과 같습니다.

앨리스는 결제 및 배송 정보를 입력한 후 '지금 주문'을 클릭합니다. 이 작업은 그녀의 주문이 처음부터 끝까지 올바르게 처리되도록 세심하게 조율된 일련의 거래인 사가(saga)라는 프로세스를 시작합니다.

1단계: 결제 처리
Saga 오케스트레이터는 먼저 PaymentService를 확인하여 Alice의 계정에서 필요한 금액을 공제하기 위한 호출을 시작합니다. PaymentService.processPayment() 메소드가 호출되고 Alice의 결제가 승인됩니다.

2단계: 재고 예약
결제가 성공하면 오케스트레이터는 InventoryService로 이동하여 Alice를 위한 특정 노트북 모델과 액세서리를 예약합니다. 주문이 처리되는 동안 재고가 매진되거나 다른 고객에게 전달되지 않도록 하려면 이 예약 단계가 중요합니다.

3단계: 배송 시작
인벤토리가 성공적으로 예약된 후 Saga 조정자는 ShippingService에 연락합니다. 여기서 ShippingService.initiateShipping()은 물류를 시작하여 품목이 포장되어 Alice의 주소로 배송될 준비가 되었는지 확인합니다.

실패 처리: 보상 논리

그러나 분산 환경에서는 어떤 단계에서든 문제가 발생할 수 있습니다. 물류 오류로 인해 배송이 시작되지 않거나, 재고 불일치로 인해 실제로 재고를 처리할 수 없는 경우에는 어떻게 되나요? 오케스트레이터는 보상 전략을 준비합니다.

예외가 발생하면 오케스트레이터는 보상 트랜잭션을 시작하여 전체 프로세스를 롤백하므로 Alice가 받지 못할 항목에 대해서는 비용이 청구되지 않습니다.

3.1. 배송 취소 - 오케스트레이터가 ShippingService.cancelShipping()을 호출하여 배송을 중지합니다.

3.2. Release Inventory - 그런 다음 InventoryService.releaseInventory()를 트리거하여 다른 고객이 구매할 수 있도록 Alice의 예약된 항목을 해제합니다.

3.3. Refund Payment - 마지막으로 PaymentService.refund()를 호출하여 Alice의 결제 금액을 환불하고 주문에 대한 비용이 청구되지 않도록 합니다.

결국 이 조직화된 이야기는 Alice의 경험이 원활하고 일관되게 이루어지도록 보장하며, 문제가 발생하더라도 시스템의 무결성을 유지하는 방식으로 해결됩니다. 이것이 바로 마이크로서비스의 분산 트랜잭션과 보상 로직의 마법입니다.


이제 트랜잭션이 무엇인지 알고 이것이 유용할 수 있는 실제 시나리오를 이해했으므로 분산 환경에서 이 작업을 수행하는 방법을 살펴보겠습니다.

이 문제를 해결하기 위해 팀이 활용하는 주요 접근 방식이 있습니다

1. SAGA 패턴: 마이크로서비스 아키텍처에서 분산 트랜잭션을 처리하는 데 가장 널리 사용되는 패턴 중 하나는 Saga 패턴입니다. 무용담은 각 서비스가 독립적으로 실행되는 일련의 로컬 트랜잭션입니다. 무용담의 각 단계는 무용담이 실패할 경우 이를 취소하는 작업으로 보상됩니다.

Saga 패턴은 두 가지 주요 방법으로 구현할 수 있습니다.

  1. 아. 안무 기반 SAGA: 트랜잭션에 관련된 각 서비스는 이벤트를 수신하고 트랜잭션을 수행합니다. 완료되면 사가의 다음 단계를 트리거하는 이벤트를 내보냅니다. 단계가 실패하면 이전 단계를 실행 취소하는 보상 이벤트가 트리거됩니다.

  2. ㄴ. 오케스트레이션 기반 SAGA: 중앙 집중식 서비스(사가 오케스트레이터)가 사가의 단계를 조정합니다. 작업 순서를 결정하고, 장애 발생 시 보상을 관리합니다.

2. 2단계 커밋(2PC): 모놀리식 시스템에서 일반적으로 사용되지만 2단계 커밋 프로토콜은 Atomikos 또는 Bitronix와 같은 분산 트랜잭션 관리자를 사용하여 분산 시스템 전체에서 사용할 수 있습니다. 그러나 이 접근 방식은 대기 시간이 길고 내결함성이 낮기 때문에 마이크로서비스 컨텍스트 내에서 몇 가지 제한 사항이 있기 때문에 권장하지 않습니다. 내가 당신이라면 일반적으로 Saga 패턴을 선호하여 이 접근 방식을 피할 것입니다.

3. 이벤트 중심 아키텍처: 서비스가 이벤트를 통해 통신하는 이벤트 중심 접근 방식을 사용하는 것은 분산 트랜잭션을 처리하는 데 특히 적합합니다. 이 접근 방식은 Saga 패턴과 잘 맞습니다. 각 서비스는 트랜잭션을 독립적으로 수행한 다음 이벤트를 내보내 다른 서비스에 결과를 알립니다. 이러한 이벤트는 Apache Kafka, RabbitMQ 또는 기타 메시지 브로커를 사용하여 처리할 수 있습니다.

이제 이것이 코드에서 어떻게 작동하는지 살펴보겠습니다.

Saga 패턴에는 여러 가지 유형이 있지만 이 기사에서는 Spring Boot에서 오케스트레이션 기반 Saga 패턴을 구현해 보겠습니다.

1단계: Saga Orchestrator 정의:
여기서는 트랜잭션 조정을 담당하는 오케스트레이터 역할을 하는 간단한 서비스를 만들어 보겠습니다.

이 서비스는 각 서비스를 올바른 순서로 호출하고 필요한 경우 보상 거래를 처리하여 이야기의 흐름을 정의합니다.

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private ShippingService shippingService;

    public void createOrderSaga(Order order) {
        try {
            paymentService.processPayment(order.getPaymentDetails());
            inventoryService.reserveInventory(order.getItems());
            shippingService.initiateShipping(order.getShippingDetails());
        } catch (Exception e) {
            // Compensation logic
            shippingService.cancelShipping(order.getShippingId());
            inventoryService.releaseInventory(order.getItems());
            paymentService.refund(order.getPaymentId());
        }
    }
}

STEP 2: 서비스별 지역 거래 및 보상 방법 생성:

각 서비스에는 해당 단계를 완료하기 위한 트랜잭션과 필요한 경우 이를 보상하기 위한 트랜잭션이 있어야 합니다. 일반적인 구조는 다음과 같습니다.

@Service
public class PaymentService {

    @Transactional
    public void processPayment(PaymentDetails details) {
        // Perform payment logic
    }

    @Transactional
    public void refund(String paymentId) {
        // Perform refund logic
    }
}

3단계: 이벤트 기반 통신(선택 사항, 안무용): 각 서비스는 다른 사용자에게 트랜잭션 결과를 알리는 이벤트를 내보낼 수 있습니다.

public class PaymentService {

    private final ApplicationEventPublisher eventPublisher;

    public PaymentService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void processPayment(PaymentDetails details) {
        // Process payment
        eventPublisher.publishEvent(new PaymentProcessedEvent(this, details));
    }
}

4단계: 데이터 일관성을 보장하기 위한 조치를 취하세요. 멱등성 검사를 사용하여 사가의 각 단계가 한 번만 실행되는지 확인하세요. 이는 네트워크 장애나 재시도로 인해 중복 요청이 발생할 수 있는 분산 시스템에서 중요합니다.

5단계: 신뢰성을 위해 메시지 브로커 사용: 이벤트를 사용하여 사가를 관리하는 경우 RabbitMq의 Kafka와 같은 메시지 브로커는 다음을 제공합니다. 내구성이 뛰어나며 서비스를 일시적으로 사용할 수 없는 경우 이벤트를 버퍼링할 수 있습니다.

6단계: 오류 처리 및 재시도: 오케스트레이터와 개별 서비스에 오류 처리 및 재시도 논리를 통합하여 일시적인 오류를 처리합니다. Spring Retry는 구성 가능한 정책 내에서 실패한 작업을 자동으로 재시도할 수 있으므로 여기서 유용합니다.

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private ShippingService shippingService;

    public void createOrderSaga(Order order) {
        try {
            paymentService.processPayment(order.getPaymentDetails());
            inventoryService.reserveInventory(order.getItems());
            shippingService.initiateShipping(order.getShippingDetails());
        } catch (Exception e) {
            // Compensation logic
            shippingService.cancelShipping(order.getShippingId());
            inventoryService.releaseInventory(order.getItems());
            paymentService.refund(order.getPaymentId());
        }
    }
}

결론

마이크로서비스의 분산 트랜잭션은 어렵지만 Saga(특히 오케스트레이션 포함) 및 이벤트 기반 통신과 같은 패턴을 사용하면 안정적이고 확장 가능한 솔루션을 얻을 수 있습니다.

Spring Boot는 트랜잭션 관리, 이벤트 게시 및 메시지 브로커와의 통합을 지원하여 이를 더 쉽게 만듭니다.

결국 이 조직화된 이야기는 Alice의 경험이 원활하고 일관되게 이루어지도록 보장하며, 문제가 발생하더라도 시스템의 무결성을 유지하는 방식으로 해결됩니다. 이것이 바로 마이크로서비스의 분산 트랜잭션과 보상 로직의 마법입니다.

위 내용은 여러 서비스에 걸친 트랜잭션 작업. 광기에 대한 방법.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.