티스토리 뷰

앞서 우리가 학습한 Transaction, Lock, Index, Cache 등은 모두 비즈니스 로직을 처리하는 데에 있어 중요한 Database의 부하를 줄이고, 속도 및 성능을 향상시키기 위함이었습니다. 그런데 Lock의 범위 뿐 아니라 무분별한 비즈니스 로직과 트랜잭션의 규모 또한 우리가 예측하지 못한 문제를 발생시킬 수 있습니다.

 

 

어떤 문제로 이어질 수 있을까?

 

- 다수의 SlowRead 작업으로 인해 요청 처리에 영향을 줄 수 있음

- Transaction 범위 내에서 Lock을 사용하고 있을 경우, 해당 자원에 접근하는 다른 요청의 대기 혹은 데드락 상황을 유발할 수 있음

- 긴 생명 주기의 Transaction의 경우, 오랜 시간은 소요되나 후속 작업에 의해 전체 트랜잭션이 실패할 수 있음

 

향해 99

 

 

- DB 외적인 작업의 실패가 Transaction의 범위로 전파되어 전체 비즈니스 로직이 rollback되는 문제 

  - 만약, externalAPI가 실패하더라도 우리의 비즈니스는 정상적으로 성공시켜도 되는 요구사항이라면?

- externalAPI의 타임아웃으로 트랜잭션을 롤백시켰으나, external 서비스에서는 사실 정상적으로 처리 되었을 때 무결성을 잃게 되는 문제

 

위 문제들을 어떻게 해결할 수 있을까 고민해보세요.

 

 

Event 기반 흐름제어

- Event를 발행 및 구독하는 모델링을 통해 코드의 강항 결합을 분리함

- Event에 의해 본인의 관심사만 수행하도록 하여 비즈니스 로직간의 의존을 느슨하게 함

 

활용 방안

- 비대해진 트랜잭션 내의 각 작업을 작은 단위의 트랙잭션으로 분리할 수 있음

- 특정 작업이 완료되었을 떄, 후속 작업이 이벤트에 의해 triger되도록 구성함으로써 과도하게 많은 비즈니스 로직을 알고 있을 필요 없음

- 트랜잭션 내에서 외부 API 호출(e.g. DB 작업 등)의 실패나 수행이 주요 비즈니스 로직 (트랜잭션)에 영향을 주지 않도록 구성할 수 있음

향해99

 

동작 순서

1. service1 수행

2. service1 완료 이벤트 발행

3. service1 완료 이벤트에 대한 리스너가 본인의 비즈니스(service2_1 & service2_2) 수행

 

주의할 점

- 각 작업의 논리적 의존이나 관계를 잘 파악해야 함

- 만약 이벤트에 의해 파생된 작업이 실패하였을 때, 원본 작업 또한 실패 처리를 해야한다면 이를 위한 처리가 필요함 (keyword : 보상 트랜잭션, SAGA 패턴)

- 이벤트에 의해 각 작업이 영향을 주고 있는지, 혹은 이벤트가 발생하면 안되는 상황에서 이벤트가 발행되고 있지는 않은지 등

 

향해 99

java 이벤트 예시

// 이벤트 객체
public class PaymentSuccessEvent {
    private final String orderKey;
    private final String paymentKey;

    public PaymentSuccessEvent(String orderKey, String paymentKey) {
        this.orderKey = orderKey;
        this.paymentKey = paymentKey;
    }

    public String getOrderKey() {
        return orderKey;
    }

    public String getPaymentKey() {
        return paymentKey;
    }
}
// 이벤트 발행서비스
@Component
public class PaymentEventPublisher {
    private final ApplicationEventPublisher applicationEventPublisher;

    public PaymentEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void success(PaymentSuccessEvent event) {
        applicationEventPublisher.publishEvent(event);
    }
}
// 이벤트 구독서비스
@Component
public class PaymentEventListener {
    private final DataPlatformSendService sendService;

    public PaymentEventListener(DataPlatformSendService sendService) {
        this.sendService = sendService;
    }
		// 비동기로 이벤트 발행주체의 트랜잭션이 커밋된 후에 수행한다.
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void paymentSuccessHandler(PaymentSuccessEvent event) {
        // (4) 주문 정보 전달
        PaymentSuccessPayload payload = new PaymentSuccessPayload(event);
        sendService.send(payload);
    }
}
// 비즈니스 로직
@Service
public class PaymentService {
    private final RequestValidator requestValidator;
    private final UserService userService;
    private final OrderService orderService;
    private final PaymentRepository paymentRepository;
    private final PaymentEventPublisher eventPublisher;

    public PaymentService(RequestValidator requestValidator, UserService userService, OrderService orderService, PaymentRepository paymentRepository, PaymentEventPublisher eventPublisher) {
        this.requestValidator = requestValidator;
        this.userService = userService;
        this.orderService = orderService;
        this.paymentRepository = paymentRepository;
        this.eventPublisher = eventPublisher;
    }

    @Transactional
    public void pay(PaymentRequest request) {
        // (1) 결제 요청 검증
        requestValidator.validate(request);
        // (2) 유저 포인트 차감
        User user = userService.getWithLock(request.getUserId());
        orderService.check(request.getOrderKey(), user.getId());
        user.usePoint(request.getAmount());
        // (3) 결제 정보 저장
        Payment payment = paymentRepository.save(new Payment(request));
        // 결제 성공 이벤트 발행
        eventPublisher.success(new PaymentSuccessEvent(payment.getOrderKey(), payment.getKey()));
    }
}

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함