Skip to Content
Software ArchitecturePluggable Publisher에서 공유 파이프라인까지
🏗️ Software Architecture2026년 1월 15일

Pluggable Publisher에서 공유 파이프라인까지

#identity-platform#audit-event#design-pattern#sns#eventbridge#spring
Identity Platform · Series 3 · Audit Event Architecture9 / 15Software Architecture
인터페이스 분리 → HTTP vs Kafka vs 공유 파이프라인 선택 → SNS→SQS→EventBridge Pipes 최종 아키텍처.

왜 인터페이스가 필요했나

Audit Event 시스템을 만들면서 가장 먼저 부딪힌 사실은 전송 방식이 오래 고정되지 않는다는 점이었다. 로그로만 남기던 단계가 있었고, HTTP로 직접 보내던 단계가 있었고, 나중에는 비동기 파이프라인으로 옮겨 갔다.

그리고 이 감사 이벤트 모듈은 처음부터 공통 라이브러리로 분리할 계획이었다. 같은 플랫폼의 다른 서비스들도 동일한 감사 이벤트를 발행해야 했기 때문에, 전송 방식을 라이브러리가 강제하는 것이 아니라 각 애플리케이션이 자신의 환경에 맞게 설정할 수 있는 구조여야 했다.

계층책임
비즈니스 로직어떤 이벤트가 발생했는지 결정
발행 인터페이스이벤트를 외부로 내보내는 공통 규격 정의
구현체실제 전송 방식 수행

아래 코드는 실제 구현을 그대로 옮긴 것이 아니라, 당시 구조를 설명하기 위한 개념 예시다.

java
conceptual/AuditEventPublisher.java
public interface AuditEventPublisher { PublishResult publish(AuditEvent<?> event); }
java
conceptual/NoOpAuditEventPublisher.java
@ConditionalOnProperty(name = "audit.sns.enabled", havingValue = "false") public class NoOpAuditEventPublisher implements AuditEventPublisher { @Override public PublishResult publish(AuditEvent<?> event) { return PublishResult.skipped(); } }

@ConditionalOnProperty로 구현체를 선택하게 만든 덕분에, application.yml 설정 한 줄로 발행 방식을 전환할 수 있었다. 라이브러리를 사용하는 각 서비스는 자신의 환경에 맞는 설정값만 넣으면 된다.

Phase 2: 왜 HTTP를 먼저 택했나

첫 연동 시점의 최우선 목표는 빠르게 이벤트를 NSP3에 보내는 것이었다. 공유 파이프라인은 아직 설계 전이었고, Kafka Native는 인프라 준비가 필요했다. HTTP Ingress는 NSP3가 이미 제공하고 있었고, OAuth 인증만 붙이면 바로 사용할 수 있었다.

하지만 운영하면서 문제가 드러났다:

  • OAuth 토큰 관리, HTTP 클라이언트 설정, 재시도 로직이 들어가면서 NspHttpPublisher 코드가 무거워졌다
  • NSP3 endpoint가 느려지면 감사 이벤트 발행 자체가 실패했다
  • 같은 방식을 다른 서비스에도 적용하려면 동일한 코드를 반복 구현해야 했다

Phase 3: 왜 공유 파이프라인이었나

세 가지 선택지가 있었다:

방식장점단점
HTTP Ingress낮은 진입 장벽NSP3 가용성에 직접 의존, 서비스 측 인증/재시도 코드 필요
Kafka Native높은 처리량, 비동기서비스별 SASL/SSL 설정, VPC 피어링 필요
공유 파이프라인서비스는 SNS publish만, Kafka를 몰라도 됨파이프라인 운영/모니터링 필요

관리 플랫폼의 감사 이벤트는 초당 수만 건이 아니라 하루 수천 건 수준이었다. 처리량보다 서비스 확장 시 구현 비용을 줄이는 것이 핵심이었다.

기준Phase 2 (HTTP)Phase 3 (공유 파이프라인)
최우선구현 속도재사용성 (공유 인프라)
서비스 복잡도OAuth + HTTP 클라이언트 + 재시도SNS publish 한 줄
다른 서비스 확장서비스마다 구현 반복같은 파이프라인 재사용
외부 장애 영향서비스에 직접 전파SQS 버퍼링으로 완화

최종 아키텍처

이 파이프라인은 직접 설계한 아키텍처다. 핵심 설계 원칙은 책임 분리였다. 서비스는 정해진 형식으로 SNS에 이벤트를 발행하기만 하면 된다. 그 이후 — 데이터를 변환하고, 다양한 sink로 라우팅하는 것 — 는 전부 파이프라인 인프라의 책임이다.

pluggable 구조 덕분에 Phase 3 전환은 구현체 교체로 끝났다:

  • 제거: OAuth 토큰 관리, HTTP 클라이언트 설정, retry/circuit breaker
  • 추가: SnsPublisher (AWS SDK 기반 SNS 토픽 발행), 비동기 발행을 위한 managed executor with MDC propagation
  • 유지: AuditEventPublisher 인터페이스, 이벤트 데이터 모델, 구조화 로깅 경로, 비즈니스 코드 전체

NoOp → NspHttp → Sns, 세 번의 전환에서 비즈니스 코드 변경은 0줄이었다.

트레이드오프

  • 인터페이스를 너무 일찍 일반화하면 불필요한 추상화가 될 수 있다 — 이 경우에는 전송 방식이 이미 바뀌고 있었기에 선택이 분명했다
  • 공유 파이프라인의 운영 주체와 모니터링 책임이 명확해야 한다
  • SNS → SQS → EventBridge Pipes → NSP3 사이의 각 단계가 새로운 실패 지점이 된다
  • 설정으로 행동이 갈리는 구조는 운영 문서화가 부족하면 오히려 헷갈릴 수 있다

좋은 추상화는 이론으로 증명되는 게 아니라, 실제 변경을 견디는지로 드러난다. 동기 결합을 줄인 대신 파이프라인 운영이라는 새로운 책임이 생겼지만, 이벤트는 더 이상 개별 서비스의 부가 기능이 아니라 여러 서비스가 같은 기준으로 쓸 수 있는 공유 인프라가 됐다.

다음 글에서는 이 파이프라인을 통해 NSP3 Kafka에 도달한 감사 이벤트 데이터를, Databricks 메달리온 아키텍처로 어떻게 정제하고 활용했는지 이어서 본다.

Last updated on