Skip to content

About

이상 결제 탐지 플랫폼 · Python/FastAPI scorer + Spring Boot pipeline (Kafka·MySQL Outbox SKIP LOCKED·Redis·Resilience4j)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

payment-anomaly-platform

이커머스 결제 이벤트 스트림에서 실시간으로 피처를 뽑아 이상 거래를 스코어링하고, 임계 초과 건을 검토/보상 흐름으로 넘기는 플랫폼.

백엔드 강점(이벤트 파이프라인, Transactional Outbox, 멱등성, 보상 트랜잭션) 위에 ML 서빙 레이어를 얹은 구조다. 규칙 기반 탐지가 못 잡는 패턴을 학습 기반으로 보완한다.

이 레포는 학습·포트폴리오 목적이다. 모든 데이터는 합성이며 실제 결제 정보를 포함하지 않는다.


아키텍처 한눈에

flowchart LR
    subgraph pipeline["pipeline (Spring Boot)"]
        K[결제 이벤트 Kafka] --> FC[실시간 피처 계산]
        FC --> CALL[스코어 요청]
        CALL --> DEC{스코어 >= 임계값?}
        DEC -->|No| PASS[정상 통과]
        DEC -->|Yes| OB[(Transactional Outbox)]
        OB --> RELAY[Outbox Relay]
        RELAY --> REVIEW[검토/보상 큐]
    end
    subgraph scorer["scorer (Python FastAPI)"]
        API[POST /score] --> MODEL[이상 탐지 모델]
    end
    CALL --> API
    MODEL --> CALL
Loading

두 서비스로 분리한다. 언어 경계는 모델 파일이다.

서비스 스택 책임 대응 트랙
pipeline/ Spring Boot, Kafka 이벤트 수집, 피처 계산, Outbox, 스코어 요청, 트리거 백엔드 · 스트리밍
scorer/ Python, FastAPI, scikit-learn 모델 학습·평가·서빙·드리프트 감시 ML serving · MLOps

왜 이 구조인가 (핵심 결정)

각 결정의 배경과 트레이드오프는 docs/decisions/에 있다.


로컬 실행

# 1. 인프라 (kafka, redis, mysql)
docker compose up -d

# 2. scorer: 합성 데이터 -> 학습 -> 서빙
cd scorer
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python -m src.features --generate
python -m src.train
uvicorn src.serve:app --reload --port 8001

# 3. pipeline: Spring Boot 기동
cd ../pipeline
./gradlew bootRun

구축 순서 (깊이 우선)

  1. scorer 완성: features → train → evaluate → serve → batch → monitor. 실행·테스트·HTTP 계약 검증 완료
  2. pipeline 슬라이스 1: Kafka consumer → 피처 계산 → scorer 호출 → 판정 → Outbox. EmbeddedKafka 통합 테스트 2건 통과 (JDK 21, Gradle 8.10.2, BUILD SUCCESSFUL)
  3. pipeline 슬라이스 2: 인메모리 seam을 실구현으로 교체. JPA Transactional Outbox + SELECT FOR UPDATE SKIP LOCKED(실제 MySQL 8, READ COMMITTED로 갭 락 회피), Resilience4j CircuitBreaker, Redis 피처 상태(실제 Redis). Testcontainers로 검증, 9 tests passed
  4. Outbox Relay 실제 Kafka 발행 + @Scheduled 주기 배출(READY→PUBLISHED/FAILED 상태 기계), 컨슈머 poison pill 방어(DefaultErrorHandler+DLT), 피처 누적 eventId 멱등. Testcontainers/EmbeddedKafka로 검증
  5. 관측성: actuator + micrometer로 /actuator/prometheus 노출. 판정 분포·이상 스코어 분포·scorer 호출 지연·Outbox 발행 결과·DLT park를 도메인 메트릭으로 심고, resilience4j 서킷브레이커 상태를 함께 노출. 실제 Testcontainers/EmbeddedKafka 흐름에서 카운터·타이머 증가를 단언
  6. 각 단계 docs/decisions/ 결정 기록 → 블로그 초안 2편(정확도 함정 · SKIP LOCKED 검증)

프로파일: 기본(운영)은 JPA + Redis 구현, inmemory 프로파일은 인메모리 구현(배선 테스트용).

검증 절차와 실측 결과는 VERIFICATION.md 참고.

scorer 검증 결과 (기준선)

  • 평가: PR-AUC 0.829, 임계값을 올릴수록 precision↑ recall↓ 트레이드오프 확인
  • 배치 스코어링: 5000건 → PASS 4714 / REVIEW 128 / HOLD 158
  • 드리프트: 동일 분포는 오탐 0, drift=1.0 데이터는 6개 중 5개 피처를 DRIFT로 감지 후 재학습 권장
  • 테스트: 6 passed

기술 스택

Java · Spring Boot · Spring Kafka · Spring Data JPA · MySQL · Redis · Resilience4j · Micrometer/Prometheus Python · FastAPI · scikit-learn · pandas

관측성

pipeline은 spring-boot-starter-actuator + micrometer-registry-prometheus로 /actuator/prometheus를 스크레이프 포맷으로 연다. 심은 도메인 메트릭은 다음과 같다(태그는 전부 유한 집합만 쓴다. eventId 같은 고유값은 카디널리티 폭발을 막기 위해 태그로 넣지 않는다).

메트릭 타입 태그 의미
payment_decision_total Counter decision=PASS/REVIEW/HOLD 판정 분포(트리거 건수)
payment_anomaly_score DistributionSummary (SLO 버킷 0.5·0.8) 이상 스코어 분포. 판정 임계에 버킷을 맞춰 검토·홀드 구간 비율을 바로 읽는다. NaN(scorer 불가)은 제외
payment_scorer_call_seconds Timer outcome=success/error scorer 호출 지연·오류율. SLO 버킷을 RestClient 타임아웃(800ms)에 맞춤
payment_outbox_publish_total Counter result=success/retry/failed Outbox 발행 상태 기계 결과
payment_dlt_park_total Counter reason=deserialization/listener 컨슈머 poison pill DLT park
resilience4j_circuitbreaker_state Gauge name=scorer 서킷 상태(resilience4j-micrometer 자동 노출)

알려진 태그 조합은 시작 시 0으로 선등록해, 대시보드가 "데이터 없음"과 "값이 0"을 구분할 수 있게 한다. Kafka · Docker · GitHub Actions

About

이상 결제 탐지 플랫폼 · Python/FastAPI scorer + Spring Boot pipeline (Kafka·MySQL Outbox SKIP LOCKED·Redis·Resilience4j)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages