Configure um teste de carga para o endpoint de pesquisa vetorial.
Esta página fornece orientações, exemplos de código e um exemplo de Notebook para teste de carga do endpoint de busca vetorial. Os testes de carga ajudam a compreender o desempenho e a prontidão para produção de um endpoint de pesquisa vetorial antes de sua implantação em produção. Os testes de carga podem fornecer informações sobre:
- Latência em diferentes níveis de escala
- Taxa de transferência, limites e gargalos (requisições por segundo, detalhamento da latência)
- Taxas de erro sob carga sustentada
- utilização de recursos e planejamento de capacidade
Para obter mais informações sobre testes de carga e conceitos relacionados, consulte Teste de carga para endpoint de serviço.
Requisitos
Antes de iniciar estes passos, você deve ter um endpoint de pesquisa de vetor implantado e uma entidade de serviço com permissões Can Query no endpoint. Consulte a etapa 1: Configurar autenticação de entidade de serviço.
Baixe e importe uma cópia dos seguintes arquivos e do Notebook de exemplo para seu workspace Databricks :
- entrada.JSON. Este é um exemplo do arquivo
input.jsonque especifica a carga útil que é enviada por todas as conexões concorrentes ao seu endpoint. Você pode ter vários arquivos, se necessário. Se você usar o Notebook de exemplo, este arquivo será gerado automaticamente a partir da tabela de entrada fornecida. - fast_vs_load_test_async_load.py. Este script é usado pelo Notebook de exemplo para autenticação e processamento de dados.
- O seguinte exemplo de Notebook executa os testes de carga. Para obter o melhor desempenho, execute este Notebook em um cluster com um grande número de núcleos e muita memória. A memória é necessária para consultas com embeddings pré-gerados, pois os embeddings geralmente consomem muita memória.
Exemplo de caderno e guia rápido
Utilize o seguinte exemplo de Notebook para começar. Inclui todos os passos para executar um teste de carga. Você precisa inserir alguns parâmetros, como segredos do Databricks, o nome do endpoint e assim por diante.
Teste de carga de gafanhotos Notebook
Framework de teste de carga: Locust
Locust é uma estrutura de teste de carga de código aberto que permite fazer o seguinte:
- Variar o número de conexões de clientes concorrentes
- Controle a velocidade com que as conexões são criadas.
- Meça o desempenho endpoint ao longo do teste.
- Detecta e utiliza automaticamente todos os núcleos de CPU disponíveis.
O Notebook de exemplo usa o sinalizador --processes -1 para detectar automaticamente os núcleos da CPU e utilizá-los totalmente.
Se o Locust estiver com gargalo na CPU, uma mensagem aparecerá na saída.
o passo 1: Configurar autenticação de entidade de serviço
Para testes de desempenho em condições semelhantes às de produção, utilize sempre a autenticação de entidade de serviço OAuth. Entidade de serviço oferece tempo de resposta até 100ms mais rápido e limites de taxa de requisição mais altos em comparação com tokens de acesso pessoal (PATs).
Criar e configurar entidade de serviço
-
Crie uma entidade de serviço do Databricks. Para obter instruções, consulte Adicionar entidade de serviço à sua account.
-
Conceder permissões:
- Acesse a página do seu endpoint de pesquisa vetorial.
- Clique em Permissões .
- Conceda à entidade de serviço permissões de "Pode consultar" .
-
Criar segredo OAuth.
- Acesse a página de detalhes da entidade de serviço.
- Clique na guia Segredos .
- Clique em Gerar segredo .
- Defina o período de validade (recomenda-se 365 dias para testes de longa duração).
- Copie imediatamente o ID do cliente e a chave secreta .
-
Armazene suas credenciais com segurança.
- Criar um Escopo Secreto Databricks . Para obter instruções, consulte o tutorial: Criar e usar um segredo Databricks.
- Conforme mostrado no exemplo de código a seguir, armazene o ID do cliente da entidade de serviço como
service_principal_client_ide armazene o segredo OAuth comoservice_principal_client_secret.
Python# In a Databricks notebook
dbutils.secrets.put("load-test-auth", "service_principal_client_id", "<CLIENT_ID>")
dbutils.secrets.put("load-test-auth", "service_principal_client_secret", "<SECRET>")
a etapa 2: Configure seu teste de carga
ConfiguraçãoNotebook
Na sua cópia do Notebook de exemplo, configure estes parâmetros:
Parâmetro | Descrição | Valor recomendado |
|---|---|---|
| Nome do seu endpointde pesquisa vetorial | Nome do seu endpoint |
| Nome completo do índice ( | Seu nome de índice |
| duração para cada teste de carga individual | 300-600 segundos (5-10 minutos) |
| Prefixo para arquivos de saída CSV |
|
| Nome do seu Escopo Secreto Databricks | Nome do seu escopo |
Por que 5 a 10 minutos?
A duração mínima do teste, de 5 minutos, é fundamental.
- As consultas iniciais podem incluir custos indiretos de cold-começar.
- O ponto final precisa de tempo para atingir um desempenho estável.
- O dimensionamento automático do endpoint do modelo de serviço (se ativado) leva algum tempo para ser implementado.
- Testes curtos não detectam o comportamento de limitação de velocidade sob carga sustentada.
A tabela a seguir mostra a duração recomendada dos testes, dependendo do seu objetivo.
Tipo de teste | Teste | Objetivos do teste |
|---|---|---|
Teste rápido de fumaça | 2-3 minutos | Verificar funcionalidades básicas |
Linha de base de desempenho | 5 a 10 minutos | Métricas confiáveis de estado estacionário |
Teste de estresse | 15 a 30 minutos | Identificar o esgotamento de recursos |
Testes de resistência | 1 a 4 horas | Degradação, estabilidade de latência |
o passo 3. Projete seu conjunto de consultas
Sempre que possível, o conjunto de consultas deve refletir o tráfego de produção esperado da forma mais precisa possível. Especificamente, você deve tentar corresponder à distribuição esperada de consultas em termos de conteúdo, complexidade e diversidade.
-
Use consultas realistas. Não utilize textos aleatórios como "consulta de teste 1234".
-
A distribuição do tráfego de produção deve ser compatível com a previsão. Se você espera 80% de consultas comuns, 15% de consultas de frequência média e 5% de consultas pouco frequentes, seu conjunto de consultas deve refletir essa distribuição.
-
Escolha um tipo de consulta que corresponda ao que você espera ver em produção. Por exemplo, se você espera que as consultas de produção usem pesquisa híbrida ou filtros, você também deve usá-los em seu conjunto de consultas.
Exemplo de consulta usando filtros:
JSON{
"query_text": "wireless headphones",
"num_results": 10,
"filters": { "brand": "Sony", "noise_canceling": true }
}Exemplo de consulta usando pesquisa híbrida:
JSON{
"query_text": "best noise canceling headphones for travel",
"query_type": "hybrid",
"num_results": 10
}
Diversidade de consultas e armazenamento em cache
O endpoint de pesquisa vetorial armazena em cache vários tipos de resultados de consulta para melhorar o desempenho. Esse armazenamento em cache pode afetar os resultados dos testes de carga. Por essa razão, é importante prestar atenção à diversidade do conjunto de consultas. Por exemplo, se você enviar repetidamente o mesmo conjunto de consultas, estará testando o cache, e não o desempenho real da pesquisa.
Usar: | Quando: | Exemplo |
|---|---|---|
Consultas idênticas ou poucas consultas |
| Um widget de recomendação de produtos que exibe "itens em alta" - a mesma consulta executada milhares de vezes por hora. |
Diversas perguntas |
| Uma ferramenta de busca em comércio eletrônico onde cada usuário digita um tipo diferente de produto ao pesquisar. |
Para obter recomendações adicionais, consulte o Resumo das melhores práticas.
Opções para criar um conjunto de consultas
A aba de código mostra três opções para criar um conjunto diversificado de consultas. Não existe uma solução única que sirva para todos. Escolha aquela que funcionar melhor para você.
- (Recomendado) Amostragem aleatória da tabela de entrada do índice. Este é um bom ponto de partida geral.
- Amostragem a partir de logs de produção. Este é um bom ponto de partida se você tiver logs de produção. Lembre-se de que as consultas geralmente mudam com o tempo, portanto, refresh o conjunto de testes regularmente para mantê-lo atualizado.
- Geração de consultas sintéticas. Isso é útil se você não tiver logs de produção ou se estiver usando filtros complexos.
- Random sampling from input table
- Sample from production logs
- Synthetic queries
O código a seguir gera exemplos de consultas aleatórias da sua tabela de entrada de índice.
import pandas as pd
import random
# Read the index input table
input_table = spark.table("catalog.schema.index_input_table").toPandas()
# Sample random rows
n_samples = 1000
if len(input_table) < n_samples:
print(f"Warning: Only {len(input_table)} rows available, using all")
sample_queries = input_table
else:
sample_queries = input_table.sample(n=n_samples, random_state=42)
# Extract the text column (adjust column name as needed)
queries = sample_queries['text_column'].tolist()
# Create query payloads
query_payloads = [{"query_text": q, "num_results": 10} for q in queries]
# Save to input.json
pd.DataFrame(query_payloads).to_json("input.json", orient="records", lines=True)
print(f"Created {len(query_payloads)} diverse queries from index input table")
O código a seguir é um exemplo proporcional de consultas de produção.
# Sample proportionally from production queries
production_queries = pd.read_csv("queries.csv")
# Take stratified sample maintaining frequency distribution
def create_test_set(df, n_queries=1000):
# Group by frequency buckets
df['frequency'] = df.groupby('query_text')['query_text'].transform('count')
# Stratified sample
high_freq = df[df['frequency'] > 100].sample(n=200) # 20%
med_freq = df[df['frequency'].between(10, 100)].sample(n=300) # 30%
low_freq = df[df['frequency'] < 10].sample(n=500) # 50%
return pd.concat([high_freq, med_freq, low_freq])
test_queries = create_test_set(production_queries)
test_queries.to_json("input.json", orient="records", lines=True)
Se você ainda não possui logs de produção, pode gerar consultas sintéticas diversificadas.
# Generate diverse queries programmatically
import random
# Define query templates and variations
templates = [
"find {product} under ${price}",
"best {product} for {use_case}",
"{adjective} {product} recommendations",
"compare {product1} and {product2}",
]
products = ["laptop", "headphones", "monitor", "keyboard", "mouse", "webcam", "speaker"]
prices = ["500", "1000", "1500", "2000"]
use_cases = ["gaming", "work", "travel", "home office", "students"]
adjectives = ["affordable", "premium", "budget", "professional", "portable"]
diverse_queries = []
for _ in range(1000):
template = random.choice(templates)
query = template.format(
product=random.choice(products),
product1=random.choice(products),
product2=random.choice(products),
price=random.choice(prices),
use_case=random.choice(use_cases),
adjective=random.choice(adjectives)
)
diverse_queries.append(query)
print(f"Generated {len(set(diverse_queries))} unique queries")
o passo 4. Teste sua carga útil
Antes de executar o teste de carga completo, valide sua carga útil:
- No workspace Databricks , navegue até o seu endpoint de pesquisa vetorial.
- Na barra lateral esquerda, clique em Servir .
- Selecione seu endpoint.
- Clique em Usar → Consultar .
- Cole o conteúdo
input.jsonna caixa de consulta. - Verifique se o endpoint retorna os resultados esperados.
Isso garante que seu teste de carga medirá consultas realistas, e não respostas de erro.
o passo 5. execução do teste de carga
Teste de aquecimento inicial (30 segundos)
O Notebook executa inicialmente um teste de 30 segundos que realiza as seguintes tarefas:
- Confirma se o endpoint está online e respondendo.
- Aquece quaisquer caches
- Valida a autenticação
Os resultados deste teste de aquecimento incluem arremessos acima da cabeça a frio, portanto não devem ser usados para métricas de desempenho.
Série principal de testes de carga
O Notebook executa uma série de testes com aumento progressivo da concorrência de clientes:
- começar: Baixa simultaneidade (por exemplo, 5 clientes simultâneos)
- Nível intermediário: Concorrência média (por exemplo, 10, 20 ou 50 clientes)
- Fim: alta simultaneidade (por exemplo, mais de 100 clientes)
Cada execução de teste para o locust_run_time configurado (5-10 minutos recomendados).
O que o Notebook mede
O Notebook mede e reporta o seguinte:
Latência média:
- P50 (mediana): Metade das consultas são mais rápidas do que isso.
- P95: 95% das consultas são mais rápidas do que isso. Esta é uma métrica key SLA .
- P99: 99% das consultas são mais rápidas do que isso.
- Máximo: Latência no pior caso.
Taxa de transferência métricas:
- RPS (solicitações por segundo): Consultas bem-sucedidas por segundo.
- Total de consultas: Número de consultas concluídas.
- Taxa de sucesso: Percentagem de consultas bem-sucedidas.
Erros:
- Falhas de consulta por tipo
- Mensagens de exceção
- Contagem de tempo limite
o passo 6. Interpretar resultados
A tabela a seguir mostra as metas para um bom desempenho:
Métrica | Destino | Comentário |
|---|---|---|
Latência P95 | < 500ms | A maioria das consultas é rápida. |
Latência P99 | < 1s | Desempenho razoável em consultas de cauda longa |
Taxa de sucesso | > 99,5% | Baixa taxa de falha |
Latência ao longo do tempo | Estável | Nenhuma degradação foi observada durante o teste. |
Queries por segundo | Atinge a meta | O endpoint consegue lidar com o tráfego esperado. |
Os seguintes resultados indicam um desempenho insatisfatório:
- P95 > 1s. Indica que as consultas são muito lentas para uso em tempo real.
- P99 > 3s. A latência em consultas de cauda longa prejudicará a experiência do usuário.
- Taxa de sucesso < 99%. Fracassos em excesso.
- Aumento da latência. Indica esgotamento de recursos ou vazamento de memória.
- Erros limitantes da taxa (429). Indica que é necessária uma maior capacidade endpoint .
Equilíbrio entre RPS e latência
O RPS máximo não é o ponto ideal para a Taxa de transferência de produção. A latência aumenta de forma não linear à medida que você se aproxima da Taxa de transferência máxima. Operar com a taxa máxima de requisições por segundo (RPS) geralmente resulta em uma latência de 2 a 5 vezes maior em comparação com a operação a 60-70% da capacidade máxima.
O exemplo a seguir mostra como analisar os resultados para encontrar o ponto de operação ideal.
- O RPS máximo é de 480 com 150 clientes simultâneos.
- O ponto de operação ideal é de 310 RPS com 50 clientes simultâneos (65% da capacidade).
- A penalidade de latência no máximo: P95 é 4,3 vezes maior (1,5s vs. 350ms)
- Neste exemplo, a recomendação é dimensionar o endpoint para uma capacidade de 480 RPS e operar a aproximadamente 310 RPS.
Concorrência | P50 | P95 | P99 | RPS | Sucesso | Capacidade |
|---|---|---|---|---|---|---|
5 | 80ms | 120ms | 150ms | 45 | 100% | 10% |
10 | 85ms | 140ms | 180ms | 88 | 100% | 20% |
20 | 95ms | 180ms | 250ms | 165 | 99,8% | 35% |
50 | 150ms | 350ms | 500ms | 310 | 99,2% | 65% ← Ponto ideal |
100 | 250ms | 800ms | 1,2s | 420 | 97,5% | 90% ⚠️ Quase no máximo |
150 | 450ms | 1,5s | 2,5s | 480 | 95,0% | 100% ❌ RPS máximo |
Operar na rotação máxima por segundo pode levar aos seguintes problemas:
- Degradação da latência. No exemplo, o P95 leva 350ms com 65% da capacidade, mas 1,5s com 100% da capacidade.
- Sem espaço para acomodar picos ou aumentos repentinos de tráfego. Com a capacidade em 100%, qualquer pico de demanda causa um tempo limite de inatividade. Com 65% da capacidade, um aumento de 50% no tráfego pode ser gerenciado sem problemas.
- Aumento das taxas de erro. No exemplo, a taxa de sucesso é de 99,2% com 65% da capacidade, mas de 95,0% — uma taxa de falha de 5% — com 100% da capacidade.
- Risco de esgotamento de recursos. Em condições de carga máxima, as filas aumentam, a pressão sobre a memória aumenta, o pool de conexões começa a saturar e o tempo de recuperação após incidentes aumenta.
A tabela a seguir mostra os pontos de operação recomendados para diferentes casos de uso.
Caso de uso | Capacidade alvo | Justificativa |
|---|---|---|
Sensível à latência (busca, bate-papo) | 50-60% do máximo | Priorize baixa latência P95/P99 |
Equilibrado (recomendações) | 60-70% do máximo | Bom equilíbrio entre custo e latência. |
Custo otimizado (trabalho em lote) | 70-80% do máximo | Latência mais alta aceitável |
Não recomendado | > 85% do máximo | Picos de latência, sem capacidade de burst. |
Funções auxiliares para calcular o ponto de operação e o tamanho endpoint .
- Find the optimal point
- Size recommendation formula
O código a seguir representa graficamente a relação entre QPS e latência P95. No gráfico, procure o ponto onde a curva começa a se inclinar acentuadamente para cima. Este é o ponto de operação ideal.
import matplotlib.pyplot as plt
# Plot QPS vs. P95 latency
qps_values = [45, 88, 165, 310, 420, 480]
p95_latency = [120, 140, 180, 350, 800, 1500]
plt.plot(qps_values, p95_latency, marker='o')
plt.axvline(x=310, color='green', linestyle='--', label='Optimal (65% capacity)')
plt.axvline(x=480, color='red', linestyle='--', label='Maximum (100% capacity)')
plt.xlabel('Queries Per Second (QPS)')
plt.ylabel('P95 Latency (ms)')
plt.title('QPS vs. Latency: Finding the Sweet Spot')
plt.legend()
plt.grid(True)
plt.show()
def calculate_endpoint_size(target_qps, optimal_capacity_percent=0.65):
"""
Calculate required endpoint capacity
Args:
target_qps: Your expected peak production QPS
optimal_capacity_percent: Target utilization (default 65%)
Returns:
Required maximum endpoint QPS
"""
required_max_qps = target_qps / optimal_capacity_percent
# Add 20% safety margin for unexpected bursts
recommended_max_qps = required_max_qps * 1.2
return {
"target_production_qps": target_qps,
"operate_at_capacity": f"{optimal_capacity_percent*100:.0f}%",
"required_max_qps": required_max_qps,
"recommended_max_qps": recommended_max_qps,
"burst_capacity": f"{(1 - optimal_capacity_percent)*100:.0f}% headroom"
}
# Example
result = calculate_endpoint_size(target_qps=200)
print(f"Target production QPS: {result['target_production_qps']}")
print(f"Size endpoint for: {result['recommended_max_qps']:.0f} QPS")
print(f"Operate at: {result['operate_at_capacity']}")
print(f"Available burst capacity: {result['burst_capacity']}")
# Output:
# Target production QPS: 200
# Size endpoint for: 369 QPS
# Operate at: 65%
# Available burst capacity: 35% headroom
o passo 7: Dimensionar seu endpoint
Siga a recomendação do Notebook.
Após analisar os resultados, o Notebook solicita que você:
- Selecione a linha que melhor atenda aos seus requisitos de latência.
- Insira o RPS desejado para sua aplicação.
Em seguida, o Notebook exibe um tamanho endpoint recomendado. Ele calcula a capacidade necessária com base no seguinte:
- Seu RPS alvo
- Latência observada em diferentes níveis de concorrência
- Limite de taxa de sucesso
- Margem de segurança (normalmente 2 vezes a carga máxima esperada)
Considerações sobre escala
Ponto final padrão:
- Aumentar a escala automaticamente para suportar o tamanho do índice.
- escalar manualmente para suportar Taxa de transferência
- Reduzir automaticamente a escala quando os índices forem excluídos.
- Reduzir manualmente a escala para diminuir a capacidade
Ponto final otimizado para armazenamento:
- Aumentar a escala automaticamente para suportar o tamanho do índice.
- Reduzir automaticamente a escala quando os índices forem excluídos.
o passo 8: Validar configuração final
Após atualizar a configuração do seu endpoint:
- Aguarde até que o endpoint esteja pronto. Isso pode levar vários minutos.
- execução do teste de validação final no Notebook.
- Confirme se o desempenho atende às suas necessidades:
- RPS ≥ meta Taxa de transferência
- A latência P95 atende ao SLA.
- Taxa de sucesso > 99,5%
- Nenhum erro sustentado
Se a validação falhar, tente o seguinte:
- Aumentar a capacidade endpoint
- Otimizar a complexidade da consulta
- Analise o desempenho do filtro
- Verifique a configuração endpoint de incorporação
Quando refazer o teste
Para manter a visibilidade do desempenho, é uma boa ideia executar testes de carga de referência trimestralmente. Você também deve realizar novos testes ao fazer qualquer uma das seguintes alterações:
- Alterar padrões ou complexidade de consulta
- Atualize o índice de pesquisa vetorial
- Modificar configurações de filtro
- Espere aumentos significativos no tráfego
- implantado novo recurso ou otimizações
- Alterar de tipos de endpoint padrão para tipos de endpoint otimizados para armazenamento
Resumo das melhores práticas
Configuração de teste
-
Testes de execução com duração mínima de 5 minutos sob carga máxima.
-
Use OAuth entidade de serviço para autenticação.
-
Crie cargas úteis de consulta realistas que correspondam às consultas de produção esperadas.
-
Teste com filtros e parâmetros semelhantes aos de produção.
-
Inclua um período de aquecimento antes de realizar a medição.
-
Teste em múltiplos níveis de concorrência.
-
Monitore as latências P95/P99, não apenas as médias.
-
Teste o desempenho com e sem cache.
Python# Conservative approach: Size endpoint for UNCACHED performance
uncached_results = run_load_test(diverse_queries, duration=600)
endpoint_size = calculate_capacity(uncached_results, target_rps=500)
# Then verify cached performance is even better
cached_results = run_load_test(repetitive_queries, duration=300)
print(f"Cached P95: {cached_results['p95']}ms (bonus performance)")
Projeto do conjunto de consultas
- Ajuste a diversidade das suas consultas de teste à distribuição real do tráfego (consultas frequentes e raras).
- Utilize consultas reais extraídas de logs (anonimizados).
- Inclua diferentes níveis de complexidade de consulta.
- Teste cenários com e sem cache e acompanhe os resultados separadamente.
- Teste com as combinações de filtros esperadas.
- Utilize os mesmos parâmetros que você usará em produção. Por exemplo, se você usa pesquisa híbrida em produção, inclua consultas de pesquisa híbrida. Use um parâmetro
num_resultssemelhante ao da produção. - Não utilize consultas que nunca serão executadas em produção.
Otimização de desempenho
Se a latência estiver muito alta, tente o seguinte:
- Use OAuth entidade de serviço (não PATs) - melhoria de 100ms
- Reduzir
num_results- Buscar 100 resultados é mais lento do que buscar 10 - Otimizar filtros - Filtros complexos ou excessivamente restritivos tornam as consultas mais lentas.
- Verifique endpoint de incorporação — certifique-se de que não esteja dimensionado para zero ou que tenha largura de banda suficiente.
Se você estiver atingindo os limites de taxa, tente o seguinte:
- Aumente a capacidade endpoint - expanda seu endpoint
- Implemente a limitação de taxa no lado do cliente ou distribua as consultas ao longo do tempo.
- Utilize o agrupamento de conexões - Reutilize conexões
- Adicionar lógica de repetição - Usar recuo exponencial (já faz parte do SDK do Python)