스프링 클라우드를 사용하여 티켓 판매 플랫폼 인 마이크로 서비스 시스템을 구현하고 있습니다. 시나리오에는 zuul 프록시, eureka 레지스트리 및 3 개의 서비스, 즉 사용자 서비스, 주문 서비스 및 티켓 서비스가 있습니다. 서비스는 feign 선언적 REST 클라이언트를 사용하여 서로 통신합니다.스프링 클라우드 아키텍트를 기반으로 hystrix fallback으로 분산 트랜잭션을 구현하는 방법
지금 티켓을 구입하는 기능이 주요 과정은 다음과 같습니다 :
1. 주문 서비스를 위해
2. 주문 서비스 상태를 보류로 주문 엔티티를 생성 만들 수있는 요청을 받아들입니다.
3. 사용자 지불을 처리하기 위해 주문 서비스 호출 사용자 서비스.
4. 사용자 티켓을 업데이트하기 위해 서비스 호출 티켓 서비스를 주문하십시오.
5. 주문 서비스가 주문 항목을 FINISHED로 업데이트합니다.
그리고 트랜잭션을 구현하는 데 Hystrix Fallback
을 사용하고 싶습니다. 예를 들어 지불 프로세스가 완료되었지만 티켓 이동 중에 오류가 발생했습니다. 사용자 지불 및 주문 상태를 복원하는 방법. 사용자 지불은 다른 서비스에 있기 때문에.
다음은 현재 해결 방법입니다. 적절한 것인지 잘 모르겠습니다. 아니면 더 좋은 방법이있을 수 있습니다. 처음에는
의 OrderResource :
@RestController
@RequestMapping("/api/order")
public class OrderResource {
@HystrixCommand(fallbackMethod = "createFallback")
@PostMapping(value = "/")
public Order create(@RequestBody Order order) {
return orderService.create(order);
}
private Order createFallback(Order order) {
return orderService.createFallback(order);
}
}
그런는 OrderService : 여기
@Service
public class OrderService {
@Transactional
public Order create(Order order) {
order.setStatus("PENDING");
order = orderRepository.save(order);
UserPayDTO payDTO = new UserPayDTO();
userCompositeService.payForOrder(payDTO);
order.setStatus("PAID");
order = orderRepository.save(order);
ticketCompositeService.moveTickets(ticketIds, currentUserId);
order.setStatus("FINISHED");
order = orderRepository.save(order);
return order;
}
@Transactional
public Order createFallback(Order order) {
// order is the object processed in create(), there is Transaction in create(), so saving order will be rollback,
// but the order instance still exist.
if (order.getId() == null) { // order not saved even.
return null;
}
UserPayDTO payDTO = new UserPayDTO();
try {
if (order.getStatus() == "FINISHED") { // order finished, must be paid and ticket moved
userCompositeService.payForOrderFallback(payDTO);
ticketCompositeService.moveTicketsFallback(getTicketIdList(order.getTicketIds()), currentUserId);
} else if (order.getStatus() == "PAID") { // is paid, but not sure whether has error during ticket movement.
userCompositeService.payForOrderFallback(payDTO);
ticketCompositeService.moveTicketsFallback(getTicketIdList(order.getTicketIds()), currentUserId);
} else if (order.getStatus() == "PENDING") { // maybe have error during payment.
userCompositeService.payForOrderFallback(payDTO);
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
order.setStatus("FAILED");
orderRepository.save(order); // order saving is rollbacked during create(), I save it here to trace the failed orders.
return order;
}
}
몇 가지 주요 포인트는
fallback
기능,OrderResource.create(order)
방법@HystrixCommand
사용.- 생성시 오류가 발생하는 경우 인스턴스가
OrderResource.create(order)
에서 사용되며 대체 기능으로 다시 사용됩니다. 이 지속성은order
이지만 롤백됩니다. 그러나이 인스턴스의 데이터는 계속 실행을 확인하는 데 사용될 수 있습니다. - 그래서 어떤 서비스 요청이 있는지 확인하기 위해 'PENDING', 'PAID', 'FINISHED'상태를 사용합니다.
ticketCompositeService
및userCompositeService
은 거짓 클라이언트입니다. feign 클라이언트 메소드payForOrder()
의 경우 fallback을위한 다른 메소드payForOrderFallback()
이 있습니다.- 폴백 메서드를 여러 번 호출 할 수 있어야합니다.
ticketCompositeService
및userCompositeService
전화에try/catch
을 추가하면 주문이 'FAILED'상태로 저장됩니다.
이 솔루션은 대부분의 경우 작동 할 수 있습니다. 단, 대체 기능에서 userCompositeService.payForOrderFallback(payDTO);
에 오류가 있으면 다음 복합 서비스 호출이 호출되지 않습니다.
또 다른 문제는 너무 복잡하다고 생각합니다.
그래서이 시나리오에서 어떻게 dist 트랜잭션을 적절하고 효과적으로 구현해야합니까? 어떤 제안이나 조언이 도움이 될 것입니다. 감사.
Event Sourcing + CQRS 기술을 시도해야합니다 (https://stackoverflow.com/questions/44114755/how-to-do-2-phase-commit-between-two-micro-servicesspring-boot) – sathees