Escalabilidad para cargas de trabajo de gran volumen
A medida que las cargas de trabajo vectoriales aumentan más allá de lo que un único servidor de bases de datos puede controlar de forma eficaz, necesita estrategias para escalar la capacidad al administrar los costos. Azure Database for PostgreSQL proporciona varias opciones de escalado que abordan distintos aspectos del desafío de rendimiento.
Escalado vertical en Azure
El escalado vertical aumenta los recursos de proceso y memoria disponibles para el servidor de bases de datos. En el caso de las cargas de trabajo vectoriales, esto aborda directamente la naturaleza intensiva de la CPU de los cálculos de similitud y los requisitos de memoria para mantener los índices almacenados en caché.
Azure Database for PostgreSQL ofrece tres niveles de proceso con diferentes asignaciones de recursos. Cada nivel tiene como destino diferentes perfiles de carga de trabajo, lo que equilibra el costo con respecto a las funcionalidades de rendimiento. En el caso de las cargas de trabajo de búsqueda vectorial, la proporción de memoria por núcleo virtual es importante porque determina la cantidad de datos de índice que pueden permanecer almacenados en caché en la memoria.
| Nivel | vCores | Memoria por núcleo virtual | Más adecuado para |
|---|---|---|---|
| Ampliable | 1-20 | 2 GB | Desarrollo, cargas de trabajo de bajo tráfico |
| General Purpose | 2-96 | 4 GB | Cargas de trabajo de producción equilibradas |
| Memoria optimizada | 2-96 | 8 GB | Grandes conjuntos de trabajo, cargas de trabajo vectoriales |
Para el escenario de recomendación del producto con dos millones de vectores y alta simultaneidad, los niveles optimizados para memoria proporcionan la mejor opción. La memoria adicional por núcleo virtual ayuda a mantener los índices HNSW almacenados en caché, lo que reduce la E/S de disco durante las consultas.
El rendimiento de las consultas vectoriales se escala con núcleos de CPU (para cálculos de distancias en paralelo) y memoria (para el almacenamiento en caché de índices). En el caso de conjuntos de datos menores de un millón de vectores, comience con 4 a 8 vCores de uso general, supervise la presión de memoria y la tasa de aciertos de caché, y aumente la escala si el uso de CPU supera consistentemente el 70% durante la carga máxima. En el caso de los conjuntos de datos de uno a diez millones de vectores, comience con núcleos virtuales optimizados para memoria de 8 a 16 núcleos virtuales, asegúrese de que la memoria supere el tamaño del índice vectorial al menos 50%y considere la posibilidad de usar más de 32 núcleos virtuales para una alta simultaneidad (cientos de consultas simultáneas). En el caso de los conjuntos de datos de más de diez millones de vectores, normalmente se requieren más de 32 núcleos virtuales optimizados para memoria. Evalúe si las réplicas de lectura pueden distribuir la carga y considere los cambios arquitectónicos (creación de particiones, capa de almacenamiento en caché).
El escalado vertical presenta retornos decrecientes y límites definidos. Escale verticalmente (servidor más grande) cuando la latencia de una sola consulta sea demasiado alta, la presión de memoria provoque una E/S de disco excesiva o no haya alcanzado los recursos máximos del nivel. Escale horizontalmente (réplicas o almacenamiento en caché) cuando el volumen total de consultas supera lo que un servidor puede gestionar, tiene una carga de trabajo con mucha lectura con obsolescencia aceptable o alcanza los límites de escalado vertical. El escalado vertical es más sencillo de implementar y administrar. Empiece por escalar verticalmente hasta que alcance los límites o el costo se convierta en prohibitivo y agregue el escalado horizontal.
Lectura de réplicas para la distribución de consultas
Las réplicas de lectura mantienen copias de su base de datos principal que gestionan las consultas de lectura de manera independiente. En el caso de las cargas de trabajo de búsqueda vectorial que consisten principalmente en lectura de datos, las réplicas pueden multiplicar tu capacidad de consulta.
Azure Database for PostgreSQL usa la replicación de streaming física para mantener las réplicas sincronizadas con el servidor principal. Los cambios escritos en el primario se transmiten a las réplicas, que los aplican de forma asincrónica. El servidor principal controla tanto las lecturas como las escrituras, mientras que cada réplica solo controla las consultas de lectura. Puede crear hasta cinco réplicas de lectura por réplica principal y las réplicas se pueden encontrar en diferentes regiones de Azure. Cada réplica tiene su propio punto de conexión, por lo que la aplicación debe enrutar las consultas al servidor adecuado.
Dado que la replicación es asincrónica, las réplicas pueden estar ligeramente detrás de la principal. El retraso suele ser de milisegundos a segundos en condiciones normales, pero puede aumentar durante una actividad intensa de escritura en el primario, transacciones grandes o cargas masivas, congestión en la red entre regiones, o limitaciones de recursos de las réplicas. En el caso de las recomendaciones de productos, el retraso de réplica suele ser aceptable. Si se agrega un nuevo producto, su apariencia en las recomendaciones unos segundos posteriores no afecta a la experiencia del usuario. Sin embargo, si la aplicación requiere coherencia inmediata (como mostrar las preferencias recién actualizadas de un usuario), esas consultas deben ir al primario. Supervise el retraso de réplica mediante métricas de Azure Monitor o consulte la réplica directamente con SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) AS lag_seconds;.
La aplicación debe dirigir las consultas a los servidores adecuados. Entre los patrones comunes se incluyen el enrutamiento de nivel de aplicación (elegir la conexión basada en el tipo de consulta), el enrutamiento basado en DNS (mediante Azure Traffic Manager o DNS personalizado para distribuir conexiones entre réplicas) y el proxy de conexión (PgBouncer o servidores proxy similares que enrutan consultas basadas en patrones). En el escenario del motor de recomendaciones, las búsquedas de similitud de vectores son candidatas ideales para el enrutamiento de réplicas, ya que son de solo lectura y la tolerancia a una ligera obsolescencia es alta.
Las réplicas se pueden ajustar de forma independiente de la principal. En el caso de las cargas de trabajo de vectores pesados de lectura, puede usar réplicas más pequeñas si el volumen de consultas es la restricción (más réplicas, más pequeñas cada una), usar réplicas iguales o más grandes si el rendimiento de las consultas individuales importa o colocar réplicas en regiones cercanas a los usuarios para una menor latencia.
Estrategias de caché para la búsqueda de vectores
El almacenamiento en caché reduce la carga de la base de datos al atender consultas repetidas desde un almacenamiento más rápido. Las cargas de trabajo de búsqueda vectorial tienen oportunidades de almacenamiento en caché específicas.
No todos los resultados de búsqueda vectorial se benefician igualmente del almacenamiento en caché. Los mejores candidatos tienen una frecuencia de solicitud alta, tasas de cambio bajas y espacios clave limitados. Las consultas de similitud aleatoria en vectores arbitrarios tienen un espacio de consulta infinito y no se almacenan bien en caché, pero las búsquedas de elementos específicos y las recomendaciones precomputadas se almacenan eficazmente. Entre los buenos candidatos para el almacenamiento en caché se incluyen las incrustaciones de productos populares solicitadas con frecuencia, los "elementos similares" precalculados para productos destacados, las búsquedas de incrustación de usuario para personalización y las incrustaciones agregadas a nivel de categoría. Los candidatos de almacenamiento en caché deficientes incluyen consultas de similitud de vectores arbitrarias (espacio de consulta infinito), datos que cambian rápidamente (tasa de invalidación alta) y consultas con muchas combinaciones de filtros.
Azure Cache for Redis proporciona tiempos de respuesta de submilisegundos para los datos almacenados en caché. En el caso de las cargas de trabajo vectoriales, considere almacenar en caché las búsquedas de embeddings y las recomendaciones precomputadas. En el siguiente ejemplo se demuestra el almacenamiento en caché de incrustaciones de productos con un tiempo de vida (TTL) de una hora.
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
Las recomendaciones obsoletas suelen ser aceptables durante períodos cortos, pero eventualmente las memorias caché necesitan actualizarse. La estrategia de invalidación correcta depende de la rapidez con la que cambian los datos y de cómo de sensibles son los usuarios a los resultados obsoletos. La mayoría de las aplicaciones de búsqueda vectorial pueden tolerar minutos de obsolescencia, lo que hace que la expiración basada en tiempo simple sea efectiva. Establezca el TTL (tiempo de vida) en función de la obsolescencia aceptable. En el caso de las recomendaciones del producto, los 15-60 minutos suelen ser razonables. Para la invalidación controlada por eventos, borre entradas de caché específicas cuando cambien los datos subyacentes. Para la actualización en segundo plano, actualice de forma proactiva los elementos populares antes de la expiración para evitar errores de caché.
Supervisión de la capacidad y el plan de crecimiento
La supervisión proactiva le ayuda a escalar antes de que el rendimiento se degrada notablemente.
Realice un seguimiento de las métricas de nivel de base de datos a través de Azure Monitor, incluido el porcentaje de CPU (70% sostenido >indica la necesidad de escalado), el porcentaje de memoria (aproximarse a los límites provoca el intercambio), el porcentaje de E/S de almacenamiento (los valores altos sugieren un almacenamiento en caché insuficiente) y las conexiones activas (que se aproximan a max_connections indican problemas de agrupación). Realice también un seguimiento de las métricas de nivel de consulta, incluida la latencia de consulta P95/P99 para las búsquedas vectoriales, el rendimiento de las consultas (consultas por segundo) y la proporción de aciertos de caché (si se usa la caché de búferes de PostgreSQL de forma eficaz).
Configure las alertas de Azure Monitor para notificarle antes de que los problemas afecten a los usuarios. Establezca una alerta de advertencia cuando el porcentaje de CPU supere los 80% durante 5 minutos para enviar correo electrónico al equipo de operaciones. Configure una alerta crítica si el uso de memoria supera el 90% por un lapso de 5 minutos para avisar al ingeniero de guardia.
El planeamiento de capacidad eficaz requiere comprender los patrones de uso actuales y proyectar las necesidades futuras. Sin esta base, corre el riesgo de sobreaprovisionar (desperdiciar el presupuesto) o el aprovisionamiento inferior (degradar la experiencia del usuario durante el crecimiento). Establezca líneas base mediante la medición del volumen de consulta actual, la latencia y el uso de recursos durante los períodos normales y máximos. Identifique los factores de crecimiento, como el crecimiento del tamaño del catálogo, el crecimiento del usuario o los cambios de complejidad de las consultas. Modele la carga futura mediante la proyección de las necesidades de recursos en función de la tasa de crecimiento. Si su catálogo se duplica anualmente y está al 60 % del uso de CPU, planee escalar en un plazo de seis meses. Pruebe las opciones de escalado antes de necesitarlas validando el escalado vertical y la implementación de réplicas en entornos que no son de producción. Umbrales de documento que definen cuándo se debe desencadenar cada acción de escalado.
Optimización de costos
La optimización del rendimiento debe equilibrarse con las restricciones presupuestarias. Varias estrategias ayudan a controlar los costos a la vez que mantienen un rendimiento aceptable.
El aprovisionamiento excesivo desperdicia dinero mientras el aprovisionamiento inferior afecta a los usuarios. Revise periódicamente el uso de recursos. Si el uso medio de la CPU es inferior al 30%, considera reducir. Si el uso de memoria es consistentemente bajo, la opción de propósito general podría ser suficiente en lugar de la opción optimizada para memoria. Si tiene réplicas con un uso bajo, considere consolidarlas.
Azure ofrece descuentos significativos (hasta 65%) para los compromisos de capacidad reservada de un año o tres años. Si la carga de trabajo de línea base es predecible, las reservas reducen considerablemente los costos. Calcule la línea base (capacidad mínima siempre activada) y reserve esa cantidad. Utilice precios bajo demanda para la capacidad adicional sobre el nivel base.
Los costos de almacenamiento se acumulan para conjuntos de datos vectoriales grandes. Quite índices sin usar (cada índice HNSW agrega ~50% al almacenamiento vectorial). Archivar vectores antiguos que rara vez se consultan. Use la precisión adecuada (float4 frente a float8) para sus necesidades de precisión.
Los entornos que no son de producción no necesitan recursos de escalado de producción. Use el nivel Ampliable para el desarrollo. Reduzca el almacenamiento temporal cuando no esté realizando pruebas activas. Use conjuntos de datos más pequeños en no producción (ejemplos representativos, no copias completas).