본문으로 건너뛰기

Streaming Inference (Kafka × Feast × KServe)

GenD 의 Streaming Inference 는 Kafka 토픽에 흐르는 이벤트를 받아 Feast online store 에서 피처를 조회하고, KServe inference endpoint 를 호출해 추론 결과를 다시 Kafka sink 토픽 (또는 DLQ) 으로 흘려보내는 상시 가동 추론 워커 입니다.

본 가이드는 M1 마일스톤 (Epic #1084) 의 운영 가능 기능을 다룹니다. M2 (API/UI + KEDA 오토스케일 + lineage emit) 와 M3 (Flink + GPU + exactly-once) 는 후속 가이드에서 다룹니다.

핵심 결정

항목선택근거
스트리밍 엔진Bytewax 0.21 (Python native)GenD 코드베이스가 Python 중심 (Dagster/FastAPI/Feast/SDK). JVM 운영 부담 회피. M3 에서 Flink 옵션 추가.
모델 호출 패턴Pattern B — 외부 KServe HTTP 호출Gap 2 의 canary/blue-green/A-B traffic split 그대로 재사용. 워커는 endpoint 만 알면 됨. 모델 메모리/GPU 분리.
KServe 프로토콜HTTP v1 (TFServing-compatible) + v2 (OIP) 양쪽 지원M1 은 HTTP REST. gRPC 는 M3 에서 throughput 측정 후 도입.
Feast online storeRedis 7.2 (infra/redis-feast/)StatefulSet 2Gi RWO + AOF + NetworkPolicy egress-deny. M2 에서 Sentinel 3-replica.
Kafka 클라이언트kafka-python (pure Python)Alpine 호환, librdkafka 의존성 회피. M2 throughput 측정 후 confluent-kafka 전환 검토.
Delivery 보증At-least-once (idempotent producer + offset auto-commit)M1. M3 에서 Flink 2PC sink 로 exactly-once.

데이터 흐름

M1 scope

구현됨

  • apps/streaming/ 신규 Python 워크스페이스 (gend-pipelines 와 별개)
    • config.pyGEND_STREAMING_* Pydantic settings (24 keys).
    • clients/feast_online_client.py — Redis hmget + freshness TTL 검사.
    • clients/kserve_inference_client.py — v1/v2 inference protocol + 재시도 + circuit breaker.
    • clients/kafka_producer.py — kafka-python idempotent producer (sink + DLQ 공유).
    • bytewax_jobs/anomaly_detection.py — 7-step dataflow (parse → Feast → predict → 분류 → sink/DLQ).
    • lineage_emitter.py/api/v1/lineage/streaming POST (M1 silent — 라우터 M2).
    • dead_letter.py — 표준 DLQ envelope (schema_version: 1).
    • metrics.py — Prometheus 6종 (latency / errors / feast lookup / stale / dlq / processed).
  • infra/redis-feast/ — Feast online Redis StatefulSet (2Gi RWO, USER 999, NetworkPolicy 3종).
  • infra/streaming/bytewax-base/ — Bytewax worker Deployment (replicas 1, image gend/gend-streaming:0.1.0).
  • apps/streaming/Dockerfile — Python 3.12-slim multi-stage, non-root UID 1000.
  • 회귀 가드:
    • apps/streaming/tests/test_anomaly_detection_local.py (8 시나리오, Bytewax in-process).
    • apps/streaming/tests/test_kserve_inference_client.py (8 시나리오, respx mock).
    • apps/streaming/tests/test_feast_online_client.py (5 시나리오, fakeredis).
    • scripts/test_streaming_manifest_renders.py (17 단언, kustomize render + 보안 posture).

미구현 — M2 (3-4주)

  • DB 모델 streaming_job / streaming_job_run + Alembic migration.
  • routers/streaming_jobs.py 8개 endpoint (CRUD + start/stop + metrics + dlq + replay).
  • KEDA ScaledObject (Kafka consumer lag trigger, replicas 1-N).
  • lineage_emitter 라우터 활성화 + UI lineage 그래프 노드 (kafka_topic / kserve_endpoint / streaming_job).
  • UI StreamingJobsPage + StreamingJobDetailPage + StreamingJobCreateDialog + streamingStore.
  • Grafana dashboard infra/grafana/dashboards/streaming.json.
  • Redis Sentinel 3-replica 전환 (infra/redis-feast/ overlay).

미구현 — M3 (5-6주)

  • Flink 1.20 (옵션, Bytewax 와 공존) — flink-kubernetes-operator + FlinkDeployment CRD.
  • KServe gRPC (latency 단축 — M1 HTTP 대비 P99 -20% 예상).
  • GPU 노드 KServe 할당.
  • Exactly-once delivery (Flink 2PC sink + Kafka EOS v2).
  • Edge inference (단말 KServe — 별도 Epic).

환경 의존성

컴포넌트상태 (M1)비고
Kafka 3-broker KRaft운영 (infra/kafka/)source / sink / DLQ 토픽 사전 생성 필요 (feedback_otel_kafka_prereq)
Kafka Connect + Debezium운영 (infra/kafka/connect.yaml)source-db.public.operating_event 토픽 자동 생성됨
Redis (Feast online)본 PR 추가 (infra/redis-feast/)M1 single replica. 실제 배포는 별도 ops PR.
Feast registry (SQL on PG)정의됨 (pipelines/feast/feature_store.yaml)M1 은 수동 feast materialize 1회 (Dagster sensor 는 Gap 3)
KServe RawDeployment운영 (#1082 M1)워커는 GEND_STREAMING_KSERVE_ENDPOINT 로 base URL 만 주입. 실제 모델 (anomaly-lng) 등록은 별도 절차.
gend-api /api/v1/lineage/streaming미존재 (M2 추가)M1 워커는 silent fallback — 404 발생해도 로그만 남기고 계속 처리.

Fallback 동작

  • Redis 미배포 → 워커가 Feast lookup 시 feast_unreachable 에러로 모든 이벤트를 DLQ 로 보냄. KServe 는 호출되지 않음. 워커 자체는 정상 동작 유지 (back-pressure 회피).
  • KServe endpoint 미배포kserve_timeout 또는 connection refused → 5xx 처리 → DLQ. circuit breaker 가 5회 연속 실패 후 30초간 fast-fail. 쿨다운 후 자동 복구.
  • lineage API 미배포LineageEmitter.emit_static()False 반환 + debug 로그. 워커 부트는 막지 않음.

운영

로컬 (Kind)

# 1. 이미지 빌드 + Kind 로드
docker build -t gend/gend-streaming:0.1.0 -f apps/streaming/Dockerfile apps/streaming
kind load docker-image gend/gend-streaming:0.1.0 --name gend-local

# 2. Redis (Feast online) 배포
kubectl apply -k infra/redis-feast/

# 3. Bytewax worker 배포
kubectl apply -k infra/streaming/bytewax-base/

# 4. 메트릭 확인
kubectl -n gend port-forward svc/gend-streaming-anomaly 9090:9090
curl localhost:9090/metrics | grep gend_streaming

AKS prod (별도 ops PR)

# ACR push (operations 팀 절차)
docker tag gend/gend-streaming:0.1.0 genosprodacr.azurecr.io/gend-streaming:0.1.0
docker push genosprodacr.azurecr.io/gend-streaming:0.1.0

# ACR-prefixed manifest 패치 후 apply
kubectl --context aks-genos-prod apply -k infra/redis-feast/
kubectl --context aks-genos-prod apply -k infra/streaming/bytewax-base/
kubectl --context aks-genos-prod set image \
deployment/gend-streaming-anomaly \
bytewax=genosprodacr.azurecr.io/gend-streaming:0.1.0 \
-n gend

메트릭

메트릭라벨설명
gend_streaming_inference_latency_secondsjob, model, statusKServe 호출 latency (Histogram, 5ms-5s)
gend_streaming_inference_errors_totaljob, model, error_typetimeout / 4xx / 5xx / circuit_open / malformed_response
gend_streaming_feast_lookup_latency_secondsjob, feature_viewRedis hmget latency
gend_streaming_feast_stale_totaljob, feature_viewTTL 초과 카운트
gend_streaming_dlq_totaljob, reasonDLQ 진입 사유별 카운트
gend_streaming_processed_totaljob, sink성공적으로 sink 된 이벤트 카운트

P99 latency budget: < 200ms (Feast 2-5ms + KServe 30-80ms + 워커 5ms).

보안 가드

  • Non-root: Redis StatefulSet UID 999, Bytewax Deployment UID 1000 (numeric).
  • readOnlyRootFilesystem: 양쪽 모두. /tmp 만 emptyDir 256Mi.
  • NetworkPolicy: Redis 는 ingress allow-list (gend-api / dagster / gend-streaming / prometheus) + egress DNS only.
  • HMAC / JWT: M1 미적용 (M2 ContextGateway 통합 시 적용). 현재는 namespace 내부 ClusterIP 통신만.
  • DLQ 가시성: 모든 실패 envelope 에 feast_lookup_result 포함 — PII 가 들어갈 수 있으므로 M2 에서 PII 마스킹 통과 후 DLQ 기록.

한계 (M1 명시)

  • 단일 모델 하드코딩GEND_STREAMING_MODEL_NAME env 만 받음. 다중 모델 동시 운영은 별도 Deployment 복제.
  • 단일 source topicGEND_STREAMING_SOURCE_TOPIC env 1개. fan-in / multi-topic 은 M2.
  • 자동 오토스케일 없음 — replicas: 1 고정. lag 폭증 시 수동 kubectl scale. M2 KEDA.
  • lineage emit silent/api/v1/lineage/streaming 라우터 부재로 emit 비활성 (GEND_STREAMING_LINEAGE_EMIT_ENABLED=false).
  • In-process bytewax Kafka source 미주입bytewax-kafka extras 또는 bytewax.connectors.kafka 의존성을 운영자가 별도로 추가해 build_flow(source=...) 로 주입해야 본격 가동. M1 배포 manifest 는 빈 source 로 부팅만 보장.

관련 문서