본문으로 건너뛰기

[feast] Feast 온라인 서빙 성능 최적화: 불필요한 오버헤드 제거하기

PR 링크: feast-dev/feast#6854 상태: Merged | 변경: +39 / -8

들어가며

최근 Feast v0.61.0에서 v0.65.0으로 업데이트한 사용자들 사이에서 /get-online-features 엔드포인트의 p99 레이턴시가 80ms에서 200ms로 급증하는 성능 회귀(Regression) 현상이 보고되었습니다. 이 문제는 온라인 서빙의 핫패스(Hot-path)에 추가된 불필요한 연산들이 원인이었습니다. 본 글에서는 Feast가 어떻게 이 오버헤드를 제거하고 성능을 복구했는지 분석합니다.

코드 분석

1. utils.py: 상태 추적의 O(N) 복잡도 개선

기존 코드에서는 피처 상태 행렬(feat_statuses)을 모두 생성한 후, 다시 전체를 순회하며 PRESENT 상태를 카운트했습니다. 이는 데이터 규모가 커질수록 성능에 악영향을 줍니다.

Before:

_present = sum(s == PRESENT for row in feat_statuses for s in row)

After:

# 루프 내부에서 즉시 카운트
_present_count += 1

데이터를 할당하는 기존 루프 내에서 카운터를 증가시킴으로써, 별도의 순회 없이 O(1)의 추가 비용으로 상태를 집계하도록 변경되었습니다.

2. feature_server.py: 감사 로깅(Audit Logging)의 조건부 실행

감사 로깅 기능이 비활성화되어 있음에도 불구하고, 모든 요청마다 time.monotonic() 호출, 보안 매니저 확인, 피처 리스트 파싱 등의 무거운 작업이 수행되고 있었습니다.

Before:

# 항상 실행되는 finally 블록
finally:
    audit_latency_ms = time.monotonic() * 1000 - audit_start_ms
    _emit_online_audit(...)

After:

# 설정 확인 후 조기 종료(Early-exit)
if feast_metrics._config.audit_logging:
    audit_latency_ms = time.monotonic() * 1000 - audit_start_ms
    _emit_online_audit(...)

feast_metrics._config.audit_logging 플래그를 확인하는 가드(Guard)를 추가하여, 로깅이 필요 없는 환경에서는 불필요한 시스템 호출을 완전히 차단했습니다.

왜 이게 좋은가

이번 최적화는 '핫패스에서의 불필요한 연산 최소화'라는 성능 최적화의 기본 원칙을 충실히 따랐습니다.

  1. 알고리즘 효율성: 전체 행렬을 다시 스캔하는 O(N) 연산을 루프 내 누적 방식인 O(1)로 변경하여 데이터 크기에 따른 레이턴시 증가를 방지했습니다.
  2. 조건부 실행: 기본적으로 비활성화된 기능(Audit Logging)이 활성화된 기능의 성능을 저해하지 않도록 가드 절을 추가했습니다. 이는 마이크로서비스 아키텍처에서 흔히 발생하는 '설정 오버헤드'를 제거하는 좋은 패턴입니다.

결과적으로, 불필요한 CPU 사이클 낭비를 막아 p99 레이턴시를 이전 수준으로 회복시켰습니다. 성능 최적화 시에는 항상 '실제 비즈니스 로직에 꼭 필요한 코드인가?'를 자문해야 한다는 교훈을 줍니다.

⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.

댓글

관련 포스트

PR Analysis 의 다른글