[내일배움캠프 TIL, Day 39] 2차 프로젝트 최종 회고 : KPT 방식으로 돌아보기

2차 프로젝트 최종 발표

  • KPT 회고
  • Order Service : 주문/결제/임시주문(Draft)을 담당한 핵심 도메인
  • SAGA Orchestration : 분산 트랜잭션 정합성 보장을 위한 보상 트랜잭션 패턴
  • Manus AI 부하 테스트 : AI 에이전트를 활용한 자율형 시스템 검증

🎤 프로젝트 최종 발표를 마치며

약 3주간의 B2B 물류 플랫폼 프로젝트를 오늘 프로젝트 발표회까지 해서 마무리됐다.
기술 구현과 더불어 팀리더로서 발표 자료 구성·스크립트 작성까지 겸했는데, 돌아보면 기술적으로도 운영적으로도 배운 것이 많았던 프로젝트였다.

내가 담당한 Order Service는 주문(Order), 결제(Payment), 임시주문(Draft) 세 도메인과 함께 전체 비즈니스 흐름에서 다른 마이크로서비스와 연동이 가장 많은 서비스였다.
예시로 주문 생성 로직이 경우, Company → Hub → Delivery 순으로 FeignClient를 연쇄 호출하며, 실패 시 역방향 보상 트랜잭션을 발동하는 SAGA 패턴의 중심이 되는 서비스였다.


Order Service 완성도 돌아보기

잘 구현한 부분

  • SAGA Orchestration : ArrayDeque 기반 보상 스택으로 재고 예약 → 배송 생성 → 실패 시 역방향 복원까지 흐름 구현. 재고 예약이 성공한 뒤 배송 생성이 실패하면 자동으로 재고가 원복된다.
  • Draft(임시 주문) 설계 : 장바구니 개념의 임시 주문을 별도 도메인으로 분리해 주문 생성과 명확히 책임을 구분했다.
  • 낙관적 락 : @Version 필드로 재고 차감 시 동시성 이슈를 방어했다.
  • FeignErrorDecoder : HubClient, CompanyClient 등 클라이언트별 에러를 상수로 분기해 클래스명 변경에도 안전한 구조로 구현했다.

아쉬운 부분

발표 자료에는 Hub 서비스 관점의 출고 프로세스 SAGA 사례를 위주로 설명했다.
Order 서비스 자체의 SAGA 설계 고민 — 왜 Choreography가 아닌 Orchestration을 선택했는지, 보상 스택의 실제 코드 구조, 보상 실패 시 수동 복구 로그를 남기는 판단 — 은 내 선택으로 제외했다. 시간 제약상 어쩔 수 없는 선택이었지만 설계적으로 고민을 많이 했었는데, 어필을 못한 부분은 개인적인 아쉬움으로 남는다.

발표에 대한 아쉬움과 별개로 보상 스택이 JVM 메모리에만 존재해서, 서비스 재시작 시 미완료 SAGA를 재개할 방법이 없다는 구조적 한계도 인지하고 있다.
Outbox 패턴이나 SAGA 상태 영속화 부분까지는 미처 도달하지 못하고, 파이널 프로젝트를 시작하기 전까지 추가로 충분한 학습을 통해 다음에 반영할 수 있도록 과제로 남겨놓게 되어 아쉽다.


발표 준비 과정

발표도 내가 맡은 주요 역할 중 하나였다.

30장이 넘어가는 분량에 8분 발표 시간에 맞추기 위해 슬라이드 구조를 전면 재검토해야 했다. 고민했던 결정 중 한 가지는 Port-Adapter 슬라이드를 제외한 것이었다.
헥사고날 개념 설명에 시간이 많이 필요한 반면, 핵심 메시지인 서비스 간 결합도 낮추기는 OpenFeign·ArchUnit 슬라이드에서 충분히 전달 가능하다고 판단했다.

대신 시스템 검증 섹션을 독립 섹션으로 분리해 Manus AI 부하 테스트 결과에 무게를 실었다. 이 부분에서 해당 테스트를 진행해준 팀원과 의견도 많이 나누고 수정도 거쳐처, 최종적으로는 해당 부분이 인상적이었다는 피드백을 받기도 했다.
기술적 의사결정을 나열하고 끝내는 게 아니라, “이렇게 설계한 시스템이 실제로 검증됐다”는 흐름으로 마무리되니 발표 구조가 훨씬 유기적으로 연결될 수 있었던 점이 좋았다고 생각한다.


Manus AI 부하 테스트와 실제 버그 수정

시스템 검증 과정에서 뜻밖의 수확이 있었다.

Manus AI가 외부 샌드박스에서 실제 운영 서버로 k6 부하를 발생시키는 과정에서 503 COMPANY_SERVICE_UNAVAILABLE 에러가 발견됐다.
분석해보니 FeignClient가 Eureka를 통해 서비스를 직접 호출할 때 Gateway가 주입하는 X-Gateway-Secret 헤더가 없어서 각 서비스의 CustomPreAuthFilter에서 차단되는 구조적 문제였다.

수정 방향은 두 가지였다.

  1. 각 서비스에 GatewayFeignInterceptor를 추가해 Feign 요청에 X-Gateway-Secret 헤더를 자동 주입
  2. company/delivery/operations-service SecurityConfig에 /api/v1/internal/** permitAll 추가

수정·배포 후 재테스트에서 SAGA 주문 생성이 정상 작동하는 것까지 확인했다.
통합 테스트 코드만으로는 이런 인프라·네트워크 레이어의 문제를 잡기 어렵다는 것을 실감했다.


KPT 회고

Keep (유지할 점)

  • 시스템 강제화 전략 : Checkstyle, ArchUnit, Flyway를 빌드 단계에 묶어 컨벤션과 아키텍처 구조를 시스템이 강제하게 만든 접근이 협업 일관성을 실질적으로 높여줬다. 다음 프로젝트에서도 초기부터 세팅하고 싶다.

  • 도메인 간 결합도에 대한 깊은 고민 : Order Service 내부에는 Order, Payment, Draft라는 세 도메인이 공존하는데, 같은 마이크로서비스 안에 있다고 해서 직접 참조를 허용하면 도메인 간 강결합이 생긴다.
    이를 해결하기 위해 두 가지 방향을 검토했다. 하나는 Port-Adapter(헥사고날) 패턴을 각 도메인 경계에 완전히 적용하는 것이고, 다른 하나는 Spring의 ApplicationEventPublisher를 활용해 도메인 이벤트로 간접 위임하는 것이었다.
    최종적으로는 Spring 이벤트 방식을 선택했다. OrderWriter가 주문 저장 후 OrderCreatedEvent를 발행하면, PaymentEventHandler가 수신해 결제를 처리한다. 발행자와 같은 트랜잭션에서 실행되기 때문에 결제 실패 시 주문도 함께 롤백되는 원자성이 보장된다. 헥사고날을 추가 도입하면 유연성은 높아지지만 구현 복잡도와 일정을 감안해 이 구조가 현실적으로 최선이라 판단했다.
    덕분에 OrderServicePaymentService를 직접 알지 못하고, Payment 도메인은 Order 도메인의 내부 구현에 의존하지 않는 구조를 완성했다.

  • 문서화 : docs 패키지에 서비스 명세, 보안 아키텍처, 데이터 명세 등을 체계적으로 정리했고, Flyway 기준으로 지속적으로 문서와 소스코드를 싱크 맞추는 습관도 좋았다.

  • 발표 구조 조율 : 기술적 깊이와 시간 제약 사이에서 무엇을 남기고 무엇을 덜어낼지 판단하는 경험. 팀원이 공들인 슬라이드를 빼는 결정이 쉽진 않았지만, 발표 흐름을 위한 합리적인 조율이었다고 생각한다. 그래도 결과적으로는 잘 해주었다는 한마디 들을 수 있어서, 그것만으로 충분히 가치있는 겅험이었다고 생각한다.

Problem (문제점/아쉬운 점)

  • SAGA 상태 영속화 미구현 : 보상 스택이 JVM 메모리에만 존재해 서비스 재시작 시 미완료 SAGA를 재개할 방법이 없다. 운영 환경에서는 명백한 리스크다.

  • 서비스 간 인증 흐름을 설계 단계에서 놓침 : X-Gateway-Secret 헤더 기반 내부 통신 인증 설계를 초기에 잡지 못해, 배포 후 부하 테스트에서야 문제가 드러났다. 서비스 간 통신 설계 시 인증 흐름도 함께 고려해야 한다는 교훈이다.

Try (개선할 점/시도할 것)

  • SAGA 고도화 — Kafka 기반 비동기 전환 : 이번 SAGA 구현은 구현 난이도와 일정을 고려해 FeignClient 동기 체인 기반의 오케스트레이션 전략으로 통일했다. 그러나 Choreography + Kafka 조합으로 전환하면 서비스 간 결합을 더 낮추고, 실패 복구도 더 견고하게 설계할 수 있었을 것이다. Outbox 패턴과 함께 Kafka를 도입하는 방향을 학습하고 다음 기회에 적용해보고 싶다.

  • MSA 시스템 안정성 검증 도구 학습 : 발표를 보니 Zipkin 분산 트레이싱을 통해 서비스 간 호출 흐름 전체를 시각화하거나, 다양한 방법으로 시스템 취약점을 사전에 파악하고 개선하는 팀들이 있었다. 팀원이 Manus AI를 활용한 부하 테스트를 진행해줬기에 인프라 버그를 발견할 수 있었지만, 그것이 아니었다면 시스템 안정성 검증이 많이 부족했을 것이다. Zipkin 트레이싱 연동, Prometheus + Grafana 모니터링, k6 파이프라인화 등 MSA 시스템을 다양한 방법으로 관찰하고 검증하는 방법을 폭넓게 학습해야겠다.

  • 설계 단계에서 통신 흐름 명세화 : 서비스 간 어떤 헤더가 오가는지, 내부 API 인증은 어떻게 처리되는지를 ERD·API 명세와 함께 초기 설계 산출물로 포함시킬 것이다.


#내일배움캠프 #단기Java #TIL #SpringBoot #MSA #SAGA #OrderService #프로젝트회고 #KPT회고

Categories:

Updated:

Leave a comment