본문으로 건너뛰기

[Open WebUI] 텔레메트리에서 효율적인 COUNT 쿼리로 커넥션 풀 고갈 방지

PR #20542 - fix: use efficient COUNT queries in telemetry metrics to prevent connection pool exhaustion

들어가며

Open WebUI v0.7.0 이후, 특히 AWS Aurora와 같은 고지연 네트워크 데이터베이스를 사용하는 PostgreSQL 배포에서 커넥션 풀 고갈 문제가 보고되었습니다. OpenTelemetry의 PeriodicExportingMetricReader가 10초마다 실행하는 텔레메트리 콜백에서, 단순히 레코드 수를 세기 위해 전체 테이블을 메모리에 로드하고 있었습니다.

핵심 코드 분석

Before

def observe_total_registered_users(
    options: metrics.CallbackOptions,
) -> Sequence[metrics.Observation]:
    return [
        metrics.Observation(
            value=len(Users.get_users()["users"]),
        )
    ]

get_users()는 모든 사용자 레코드를 DB에서 조회하여 파이썬 객체로 역직렬화한 후, 리스트 길이만 셉니다.

After

def observe_total_registered_users(
    options: metrics.CallbackOptions,
) -> Sequence[metrics.Observation]:
    # IMPORTANT: Use get_num_users() for efficient COUNT(*) query.
    # Do NOT use len(get_users()["users"]) - it loads ALL user records into memory,
    # causing connection pool exhaustion on high-latency databases (e.g., Aurora).
    return [
        metrics.Observation(
            value=Users.get_num_users() or 0,
        )
    ]

이미 코드베이스에 존재하던 get_num_users() 메서드를 사용하여 SELECT COUNT(*)만 실행합니다.

왜 이게 좋은가

  1. 커넥션 점유 시간 극적 감소: Aurora에서 500ms+가 소요되던 전체 로드가 5-10ms의 COUNT 쿼리로 변경됩니다.
  2. 풀 고갈 방지: 10초마다 긴 커넥션 점유가 동시 요청과 겹치면서 QueuePool limit reached 에러를 유발하던 문제가 해결됩니다.
  3. 이미 존재하는 API 활용: 새로운 메서드를 만들 필요 없이, 기존의 get_num_users()를 사용합니다.
  4. 메모리 사용량 감소: 전체 사용자 객체를 메모리에 올리지 않으므로, 대규모 배포에서 메모리 효율이 크게 개선됩니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글