대용량 워크로드에 대한 스케일링

Completed

벡터 워크로드가 단일 데이터베이스 서버가 효율적으로 처리할 수 있는 것 이상으로 커짐에 따라 비용을 관리하면서 용량을 조정하는 전략이 필요합니다. Azure Database for PostgreSQL은 성능 문제의 다양한 측면을 해결하는 몇 가지 크기 조정 옵션을 제공합니다.

Azure에서 수직 크기 조정

수직 크기 조정은 데이터베이스 서버에서 사용할 수 있는 컴퓨팅 및 메모리 리소스를 증가합니다. 벡터 워크로드의 경우 이는 유사성 계산의 CPU 집약적 특성과 인덱스를 캐시된 상태로 유지하기 위한 메모리 요구 사항을 직접 해결합니다.

Azure Database for PostgreSQL은 리소스 할당이 다른 세 가지 컴퓨팅 계층을 제공합니다. 각 계층은 다양한 워크로드 프로필을 대상으로 하며 성능 기능과 비용을 분산합니다. 벡터 검색 워크로드의 경우 메모리에 캐시된 상태로 유지할 수 있는 인덱스 데이터의 양을 결정하기 때문에 vCore당 메모리 비율이 중요합니다.

계층 vCores vCore 당 메모리 적합한 대상
버스트 가능 1-20 2GB 개발, 트래픽이 적은 워크로드
General Purpose 2-96 4GB 균형 잡힌 프로덕션 워크로드
메모리 최적화 2-96 8GB 대규모 작업 집합, 벡터 워크로드

2백만 개의 벡터와 높은 동시성이 있는 제품 권장 사항 시나리오의 경우 메모리 최적화 계층이 가장 적합합니다. vCore당 추가 메모리를 사용하면 HNSW 인덱스를 캐시하여 쿼리 중에 디스크 I/O를 줄일 수 있습니다.

벡터 쿼리 성능은 CPU 코어(병렬 거리 계산용) 및 메모리(인덱스 캐싱용)로 확장됩니다. 100만 개 미만의 데이터 세트의 경우 범용 4-8 vCore로 시작하고, 메모리 압력 및 캐시 적중 비율을 모니터링하고, CPU 사용률이 최대 부하 동안 지속적으로 70% 초과하는 경우 확장합니다. 1~1,000만 개의 벡터 데이터 세트의 경우 메모리 최적화 8-16 vCore로 시작하고, 메모리가 벡터 인덱스 크기를 50%초과하도록 하고, 높은 동시성(수백 개의 동시 쿼리)에 대해 32개 이상의 vCore를 고려합니다. 데이터셋이 천만 개 이상일 경우, 일반적으로 메모리 최적화된 32개 이상의 vCore가 필요합니다. 읽기 복제본이 부하를 분산할 수 있는지 여부를 평가하고 아키텍처 변경(분할, 캐싱 계층)을 고려합니다.

수직 크기 조정에는 수익 감소 및 하드 제한이 있습니다. 단일 쿼리 대기 시간이 너무 높거나, 메모리 압력으로 인해 과도한 디스크 I/O가 발생하거나, 계층의 최대 리소스에 도달하지 않은 경우 강화(더 큰 서버). 총 쿼리량이 단일 서버가 처리할 수 있는 수준을 초과하거나, 허용 가능한 부실을 감수할 수 있는 읽기 중심 워크로드가 존재하거나, 수직 확장 한도에 도달한 경우 스케일 아웃(복제본 또는 캐싱)을 수행해야 합니다. 수직 크기 조정은 구현하고 관리하는 것이 더 간단합니다. 제한에 도달하거나 비용이 엄청나게 커질 때까지 확장하여 시작한 다음, 수평 크기 조정을 추가합니다.

쿼리 배포를 위한 읽기 복제본

읽기 복제본은 읽기 쿼리를 독립적으로 처리하는 주 데이터베이스의 복사본을 유지 관리합니다. 주로 읽는 벡터 검색 워크로드의 경우 복제본이 쿼리 용량을 곱할 수 있습니다.

Azure Database for PostgreSQL은 물리적 스트리밍 복제를 사용하여 복제본을 주 서버와 동기화된 상태로 유지합니다. 주 복제본에 기록된 변경 내용은 복제본으로 스트리밍되어 비동기적으로 적용됩니다. 주 서버는 읽기 및 쓰기를 모두 처리하고 각 복제본은 읽기 쿼리만 처리합니다. 기본 데이터베이스당 최대 5개의 읽기 복제본을 만들 수 있으며, 복제본은 서로 다른 Azure 지역에 있을 수 있습니다. 각 복제본에는 자체 연결 엔드포인트가 있으므로 애플리케이션은 쿼리를 적절한 서버로 라우팅해야 합니다.

복제는 비동기이므로 복제본이 주 복제본에 약간 뒤처질 수 있습니다. 이 지연은 정상 조건에서 일반적으로 밀리초부터 초 사이에 있습니다. 그러나 기본 데이터에 대한 쓰기 작업이 많을 때, 대규모 트랜잭션 또는 대량 로딩, 지역 간 네트워크 혼잡, 혹은 복제본의 자원 제한이 있을 때는 증가할 수 있습니다. 제품 권장 사항의 경우 복제본 지연이 허용되는 경우가 많습니다. 새 제품이 추가된 후 몇 초 지나서 권장 항목에 나타나도 사용자 환경에 영향을 미치지 않습니다. 그러나 애플리케이션에 즉각적인 일관성(예: 사용자의 방금 업데이트된 기본 설정 표시)이 필요한 경우 해당 쿼리는 기본 쿼리로 이동해야 합니다. Azure Monitor 메트릭을 사용하여 복제본 지연을 모니터링하거나 SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag_seconds;를 사용하여 복제본을 직접 쿼리하세요.

애플리케이션은 쿼리를 적절한 서버로 전달해야 합니다. 일반적인 패턴에는 애플리케이션 수준 라우팅(쿼리 유형에 따라 연결 선택), DNS 기반 라우팅(Azure Traffic Manager 또는 사용자 지정 DNS를 사용하여 복제본 간에 연결 분산), 연결 프록시(패턴에 따라 쿼리를 라우팅하는 PgBouncer 또는 유사한 프록시)가 포함됩니다. 권장 엔진 시나리오의 경우 벡터 유사도 검색이 복제본 라우팅에 이상적인 선택지입니다. 읽기 전용이고 약간의 부신에 대한 허용도가 높기 때문입니다.

복제본의 크기는 주 복제본과 독립적으로 조정할 수 있습니다. 읽기가 많은 벡터 워크로드의 경우 쿼리 볼륨이 제약 조건인 경우(더 많은 복제본, 더 작은 복제본 각각), 개별 쿼리 성능이 중요한 경우 동일하거나 큰 복제본을 사용하거나, 짧은 대기 시간을 위해 사용자와 가까운 지역에 복제본을 배치하는 경우 더 작은 복제본을 사용할 수 있습니다.

캐싱은 더 빠른 스토리지에서 반복되는 쿼리를 제공하여 데이터베이스 부하를 줄입니다. 벡터 검색 워크로드에는 특정 캐싱 기회가 있습니다.

모든 벡터 검색 결과가 캐싱의 이점을 동일하게 활용하는 것은 아닙니다. 가장 적합한 후보는 요청 빈도가 높고, 변경률이 낮으며, 제한된 키 공간이 있습니다. 임의 벡터에 대한 임의 유사성 쿼리는 쿼리 공간이 무한하고 캐시가 잘 되지 않지만 특정 항목 또는 사전 계산된 권장 사항에 대한 조회는 효과적으로 캐시됩니다. 좋은 캐싱 후보에는 자주 요청되는 인기 있는 제품 임베딩, 상위 제품에 대한 사전 계산된 "유사한 항목", 개인화된 사용자 임베딩 조회 및 범주 수준 집계 임베딩이 포함됩니다. 잘못된 캐싱 후보는 임의의 벡터 유사성 쿼리(무한 쿼리 공간), 빠르게 변화하는 데이터(높은 무효화율) 및 많은 필터 조합이 있는 쿼리를 포함합니다.

Azure Cache for Redis는 캐시된 데이터에 대해 밀리초 미만의 응답 시간을 제공합니다. 벡터 워크로드의 경우 포함 조회 및 미리 계산된 권장 사항을 캐싱하는 것이 좋습니다. 다음 예제에서는 TTL이 1시간인 제품 임베딩을 캐싱하는 방법을 보여줍니다.

import redis
import json

redis_client = redis.Redis(host='your-cache.redis.cache.windows.net',
                          port=6380, ssl=True, password='your-key')

def get_product_embedding(product_id):
    cache_key = f"embedding:{product_id}"
    cached = redis_client.get(cache_key)

    if cached:
        return json.loads(cached)

    # Fetch from database
    embedding = fetch_embedding_from_db(product_id)

    # Cache for 1 hour
    redis_client.setex(cache_key, 3600, json.dumps(embedding))
    return embedding

부실한 권장 사항은 일반적으로 단기간 동안은 허용되지만, 캐시는 결국 새로 고쳐야 합니다. 올바른 무효화 전략은 데이터가 얼마나 빨리 변경되고 사용자가 오래된 결과에 얼마나 중요한지에 따라 달라집니다. 대부분의 벡터 검색 애플리케이션은 몇 분 동안 구식 상태를 허용할 수 있으므로 간단한 시간 기반 만료가 효과적입니다. 허용 가능한 부실 정도에 따라 TTL(Time to Live)을 설정하십시오. 제품 권장 사항의 경우 15-60분은 종종 합리적입니다. 이벤트 기반 무효화의 경우 기본 데이터가 변경되면 특정 캐시 항목을 지웁다. 백그라운드 새로 고침의 경우 캐시 누락을 방지하기 위해 만료 전에 인기 있는 항목을 사전에 새로 고칩니다.

용량 모니터링 및 성장 계획

사전 모니터링은 성능이 눈에 띄게 저하되기 전에 크기를 조정하는 데 도움이 됩니다.

CPU 비율(지속적인 >70%는 확장 필요성을 나타냄), 메모리 비율(한도에 도달하면 스왑 발생), 스토리지 IO 비율(높은 값은 캐싱 부족을 나타냄) 및 활성 연결(max_connections에 근접함을 나타냄)을 포함하여 Azure Monitor를 통해 데이터베이스 수준 메트릭을 추적합니다. 또한 벡터 검색에 대한 P95/P99 쿼리 대기 시간, 쿼리 처리량(초당 쿼리 수) 및 캐시 적중률(PostgreSQL의 버퍼 캐시를 효과적으로 사용하는 경우)을 포함한 쿼리 수준 메트릭을 추적합니다.

문제가 사용자에게 영향을 미치기 전에 알리도록 Azure Monitor 경고를 구성합니다. CPU 사용률이 5분 동안 80%를 초과할 때 운영 팀에 이메일을 보내도록 경고 알림을 설정합니다. 메모리 사용률이 5분 동안 90%를 초과할 때 호출 중인 엔지니어에게 페이지를 보내기 위해 중요한 경고를 설정합니다.

효과적인 용량 계획에는 현재 사용 패턴을 이해하고 향후 요구 사항을 예측해야 합니다. 이 기반이 없으면 과도하게 프로비전(예산 낭비) 또는 과소 프로비저닝(성장 중 사용자 환경 저하)의 위험이 있습니다. 정상 및 피크 기간 동안 현재 쿼리 볼륨, 대기 시간 및 리소스 사용률을 측정하여 기준을 설정합니다. 카탈로그 크기 증가, 사용자 증가 또는 쿼리 복잡성 변경과 같은 성장 동인을 식별합니다. 증가율에 따라 리소스 요구 사항을 프로젝팅하여 향후 부하를 모델링합니다. 카탈로그가 매년 두 배로 늘어나고 CPU가 60%인 경우 6개월 이내에 크기를 조정할 계획입니다. 비프로덕션 환경에서 수직 크기 조정 및 복제본 배포의 유효성을 검사하여 필요하기 전에 크기 조정 옵션을 테스트합니다. 각 크기 조정 작업이 트리거되는 시기를 정의하는 문서 임계값입니다.

비용 최적화

성능 최적화는 예산 제약 조건과 균형을 유지해야 합니다. 몇 가지 전략은 허용 가능한 성능을 유지하면서 비용을 제어하는 데 도움이 됩니다.

과잉 프로비저닝은 비용을 낭비하는 반면, 과소 프로비저닝은 사용자에게 상처를 줍니다. 정기적으로 리소스 사용률을 검토합니다. 평균 CPU가%30 미만이면 규모를 축소하는 것이 좋습니다. 메모리 사용률이 지속적으로 낮으면 메모리 최적화 대신 범용으로 충분할 수 있습니다. 사용률이 낮은 복제본이 있는 경우 통합합니다.

Azure는 1년 또는 3년 예약 용량 약정에 대해 상당한 할인(최대 65%)을 제공합니다. 기준 워크로드를 예측할 수 있는 경우 예약은 비용을 크게 절감합니다. 기준(최소 상시 사용 용량)을 계산하고 해당 금액을 예약합니다. 기준보다 높은 버스트 용량에 주문형 가격을 사용합니다.

스토리지 비용은 큰 벡터 데이터 세트에 대해 누적됩니다. 사용되지 않는 인덱스를 제거합니다(각 HNSW 인덱스는 벡터 스토리지에 최대 50개의% 추가됨). 거의 쿼리되지 않는 이전 벡터를 보관합니다. 정확도 요구 사항에 적절한 정밀도(float4 및 float8)를 사용합니다.

비프로덕션 환경에는 프로덕션 규모 리소스가 필요하지 않습니다. 개발에는 버스트 가능 티어를 사용합니다. 활성 테스트를 진행하지 않을 때 스테이징을 축소합니다. 비프로덕션(전체 복사본이 아닌 대표 샘플)에서 더 작은 데이터 세트를 사용합니다.

추가 리소스