Dicas de desempenho para o Azure Cosmos DB Sync Java SDK v2

APLICA-SE A: NoSQL

Importante

Este não é o SDK Java mais recente para o Azure Cosmos DB! Você deve atualizar seu projeto para o Azure Cosmos DB Java SDK v4 e ler o guia de dicas de desempenho do Azure Cosmos DB Java SDK v4. Siga as instruções no guia Migrar para o Azure Cosmos DB Java SDK v4 e no guia Reator vs RxJava para atualizar.

Estas dicas de desempenho são apenas para o SDK Java v2 do Azure Cosmos DB Sync. Consulte o repositório Maven para obter mais informações.

Importante

Em 29 de fevereiro de 2024, o SDK Java do Azure Cosmos DB Sync v2.x será desativado; o SDK e todos os aplicativos que usam o SDK continuarão a funcionar; O Azure Cosmos DB simplesmente deixará de fornecer mais manutenção e suporte para este SDK. Recomendamos seguir as instruções acima para migrar para o SDK Java v4 do Azure Cosmos DB.

O Azure Cosmos DB é um banco de dados distribuído rápido e flexível que pode ser dimensionado perfeitamente com latência e taxa de transferência garantidas. Não é necessário fazer grandes alterações na arquitetura ou escrever código complexo para dimensionar seu banco de dados com o Azure Cosmos DB. Escalar para cima e para baixo é tão fácil quanto fazer uma única chamada de API. Para saber mais, consulte como provisionar a taxa de transferência do contêiner ou como provisionar a taxa de transferência do banco de dados. No entanto, como o Azure Cosmos DB é acessado por meio de chamadas de rede, há otimizações do lado do cliente que você pode fazer para atingir o desempenho máximo ao usar o SDK Java v2 do Azure Cosmos DB Sync.

Portanto, se você estiver perguntando "Como posso melhorar o desempenho do meu banco de dados?", considere as seguintes opções:

Rede

  1. Modo de conexão: Use DirectHttps

    A forma como um cliente se liga ao Azure Cosmos DB tem implicações importantes no desempenho, sobretudo em termos da latência observada do lado do cliente. Há uma definição de configuração chave disponível para configurar o cliente ConnectionPolicy – o ConnectionMode. Os dois ConnectionModes disponíveis são:

    1. Gateway (padrão)

    2. DirectHttps

      O modo de gateway é suportado em todas as plataformas SDK e é o padrão configurado. Se seu aplicativo é executado em uma rede corporativa com restrições rígidas de firewall, o Gateway é a melhor escolha, pois usa a porta HTTPS padrão e um único ponto de extremidade. A compensação de desempenho, no entanto, é que o modo Gateway envolve um salto de rede adicional sempre que os dados são lidos ou gravados no Azure Cosmos DB. Por isso, o modo DirectHttps oferece melhor desempenho devido a menos saltos de rede.

      O SDK Java v2 do Azure Cosmos DB Sync usa HTTPS como um protocolo de transporte. HTTPS usa TLS para autenticação inicial e tráfego de criptografia. Ao usar o SDK Java v2 do Azure Cosmos DB Sync, somente a porta HTTPS 443 precisa estar aberta.

      O ConnectionMode é configurado durante a construção da instância DocumentClient com o parâmetro ConnectionPolicy.

    Sincronizar Java SDK V2 (Maven com.microsoft.azure::azure-documentdb)

    public ConnectionPolicy getConnectionPolicy() {
      ConnectionPolicy policy = new ConnectionPolicy();
      policy.setConnectionMode(ConnectionMode.DirectHttps);
      policy.setMaxPoolSize(1000);
      return policy;
    }
    
    ConnectionPolicy connectionPolicy = new ConnectionPolicy();
    DocumentClient client = new DocumentClient(HOST, MASTER_KEY, connectionPolicy, null);
    

    O diagrama mostra a política de conexão do Azure Cosmos DB.

  2. Coloque clientes na mesma região do Azure para desempenho

    Quando possível, coloque todos os aplicativos que chamam o Azure Cosmos DB na mesma região do banco de dados do Azure Cosmos DB. Para uma comparação aproximada, as chamadas para o Azure Cosmos DB dentro da mesma região são concluídas dentro de 1 a 2 ms, mas a latência entre a costa oeste e leste dos EUA é >de 50 ms. Essa latência provavelmente pode variar de solicitação para solicitação, dependendo da rota tomada pela solicitação à medida que ela passa do cliente para o limite do datacenter do Azure. A menor latência possível é alcançada garantindo que o aplicativo de chamada esteja localizado na mesma região do Azure que o ponto de extremidade provisionado do Azure Cosmos DB. Para obter uma lista de regiões disponíveis, consulte Regiões do Azure.

    O diagrama mostra solicitações e respostas em duas regiões, onde os computadores se conectam a uma Conta do Azure Cosmos DB por meio de serviços de camada intermediária.

Uso do SDK

  1. Instalar o SDK mais recente

    Os SDKs do Azure Cosmos DB estão sendo constantemente aprimorados para fornecer o melhor desempenho. Para determinar as melhorias mais recentes do SDK, visite o SDK do Azure Cosmos DB.

  2. Usar um cliente singleton do Azure Cosmos DB durante o tempo de vida do seu aplicativo

    Cada instância do DocumentClient é thread-safe e executa gerenciamento de conexão eficiente e cache de endereços ao operar no Modo Direto. Para permitir um gerenciamento de conexão eficiente e um melhor desempenho por DocumentClient, é recomendável usar uma única instância de DocumentClient por AppDomain durante o tempo de vida do aplicativo.

  3. Aumente MaxPoolSize por host ao usar o modo Gateway

    As solicitações do Azure Cosmos DB são feitas por HTTPS/REST ao usar o modo Gateway e estão sujeitas ao limite de conexão padrão por nome de host ou endereço IP. Talvez seja necessário definir o MaxPoolSize para um valor mais alto (200-1000) para que a biblioteca de cliente possa utilizar várias conexões simultâneas com o Azure Cosmos DB. No SDK Java v2 do Azure Cosmos DB Sync, o valor padrão para ConnectionPolicy.getMaxPoolSize é 100. Use setMaxPoolSize para alterar o valor.

  4. Ajustando consultas paralelas para coleções particionadas

    O SDK Java do Azure Cosmos DB Sync versão 1.9.0 e superior oferece suporte a consultas paralelas, que permitem consultar uma coleção particionada em paralelo. Para obter mais informações, consulte exemplos de código relacionados ao trabalho com os SDKs. As consultas paralelas são projetadas para melhorar a latência e a taxa de transferência da consulta em relação à sua contraparte serial.

    (a) Ajustando setMaxDegreeOfParallelism: As consultas paralelas funcionam consultando várias partições em paralelo. No entanto, os dados de uma coleção particionada individual são obtidos em série em relação à consulta. Portanto, use setMaxDegreeOfParallelism para definir o número de partições que tem a chance máxima de alcançar a consulta de maior desempenho, desde que todas as outras condições do sistema permaneçam as mesmas. Se você não sabe o número de partições, você pode usar setMaxDegreeOfParallelism para definir um número alto, e o sistema escolhe o mínimo (número de partições, entrada fornecida pelo usuário) como o grau máximo de paralelismo.

    É importante notar que as consultas paralelas produzem os melhores benefícios se os dados forem distribuídos uniformemente em todas as partições em relação à consulta. Se a coleção particionada for particionada de tal forma que todos ou a maioria dos dados retornados por uma consulta estejam concentrados em algumas partições (uma partição na pior das hipóteses), o desempenho da consulta será afunilizado por essas partições.

    (b) Ajustando setMaxBufferedItemCount: A consulta paralela é projetada para pré-buscar resultados enquanto o lote atual de resultados está sendo processado pelo cliente. A pré-busca ajuda na melhoria geral da latência de uma consulta. setMaxBufferedItemCount limita o número de resultados pré-buscados. Ao definir setMaxBufferedItemCount para o número esperado de resultados retornados (ou um número maior), isso permite que a consulta receba o máximo benefício da pré-busca.

    A pré-busca funciona da mesma forma, independentemente do MaxDegreeOfParallelism, e há um único buffer para os dados de todas as partições.

  5. Implementar backoff em intervalos getRetryAfterInMilliseconds

    Durante o teste de desempenho, você deve aumentar a carga até que uma pequena taxa de solicitações seja limitada. Se limitado, o aplicativo cliente deve recuar no acelerador para o intervalo de repetição especificado pelo servidor. Respeitar o backoff garante que você passe uma quantidade mínima de tempo esperando entre as tentativas. O suporte à política de repetição está incluído na Versão 1.8.0 e superior do SDK Java de Sincronização do Azure Cosmos DB. Para obter mais informações, consulte getRetryAfterInMilliseconds.

  6. Dimensione a carga de trabalho do cliente

    Se você estiver testando em altos níveis de taxa de transferência (>50.000 RU/s), o aplicativo cliente pode se tornar o gargalo devido à máquina limitar a utilização da CPU ou da rede. Se você chegar a esse ponto, poderá continuar a impulsionar ainda mais a conta do Azure Cosmos DB dimensionando seus aplicativos cliente em vários servidores.

  7. Usar endereçamento baseado em nome

    Use endereçamento baseado em nome, onde os links têm o formato dbs/MyDatabaseId/colls/MyCollectionId/docs/MyDocumentId, em vez de SelfLinks (_self), que têm o formato dbs/<database_rid>/colls/<collection_rid>/docs/<document_rid> para evitar recuperar ResourceIds de todos os recursos usados para construir o link. Além disso, como esses recursos são recriados (possivelmente com o mesmo nome), armazená-los em cache pode não ajudar.

  8. Ajuste o tamanho da página para consultas/feeds de leitura para um melhor desempenho

    Ao executar uma leitura em massa de documentos usando a funcionalidade de feed de leitura (por exemplo, readDocuments) ou ao emitir uma consulta SQL, os resultados são retornados de forma segmentada se o conjunto de resultados for muito grande. Por padrão, os resultados são retornados em partes de 100 itens ou 1 MB, o limite atingido primeiro.

    Para reduzir o número de viagens de ida e volta de rede necessárias para recuperar todos os resultados aplicáveis, você pode aumentar o tamanho da página usando o cabeçalho de solicitação x-ms-max-item-count para até 1000. Nos casos em que você precisa exibir apenas alguns resultados, por exemplo, se a interface do usuário ou a API do aplicativo retornar apenas 10 resultados por vez, você também poderá diminuir o tamanho da página para 10 para reduzir a taxa de transferência consumida para leituras e consultas.

    Você também pode definir o tamanho da página usando o método setPageSize.

Política de Indexação

  1. Excluir os caminhos não utilizados da indexação para assegurar escritas mais rápidas

    A política de indexação do Azure Cosmos DB permite especificar quais caminhos de documento devem ser incluídos ou excluídos da indexação usando Caminhos de Indexação (setIncludedPaths e setExcludedPaths). O uso de caminhos de indexação pode oferecer melhor desempenho de gravação e menor armazenamento de índice para cenários nos quais os padrões de consulta são conhecidos de antemão, já que os custos de indexação estão diretamente correlacionados ao número de caminhos exclusivos indexados. Por exemplo, o código a seguir mostra como excluir uma seção inteira (subárvore) dos documentos da indexação usando o curinga "*".

    Sincronizar Java SDK V2 (Maven com.microsoft.azure::azure-documentdb)

    Index numberIndex = Index.Range(DataType.Number);
    numberIndex.set("precision", -1);
    indexes.add(numberIndex);
    includedPath.setIndexes(indexes);
    includedPaths.add(includedPath);
    indexingPolicy.setIncludedPaths(includedPaths);
    collectionDefinition.setIndexingPolicy(indexingPolicy);
    

    Para obter mais informações, consulte Políticas de indexação do Azure Cosmos DB.

Débito

  1. Meça e ajuste para unidades de solicitação mais baixas/segundo de uso

    O Azure Cosmos DB oferece um conjunto avançado de operações de banco de dados, incluindo consultas relacionais e hierárquicas com UDFs, procedimentos armazenados e gatilhos, todos operando nos documentos de uma coleção de banco de dados. O custo associado a cada uma destas operações varia com base na CPU, E/S e memória necessárias para concluir a operação. Em vez de pensar e gerenciar recursos de hardware, você pode pensar em uma unidade de solicitação (RU) como uma única medida para os recursos necessários para executar várias operações de banco de dados e atender a uma solicitação de aplicativo.

    A taxa de transferência é provisionada com base no número de unidades de solicitação definidas para cada contêiner. O consumo unitário de solicitação é avaliado como uma taxa por segundo. Os aplicativos que excedem a taxa unitária de solicitação provisionada para seu contêiner são limitados até que a taxa caia abaixo do nível provisionado para o contêiner. Se seu aplicativo exigir um nível mais alto de taxa de transferência, você poderá aumentar sua taxa de transferência provisionando unidades de solicitação adicionais.

    A complexidade de uma consulta afeta quantas unidades de solicitação são consumidas para uma operação. O número de predicados, a natureza dos predicados, o número de UDFs e o tamanho do conjunto de dados de origem influenciam o custo das operações de consulta.

    Para medir a sobrecarga de qualquer operação (criar, atualizar ou excluir), inspecione o cabeçalho x-ms-request-charge (ou a propriedade RequestCharge equivalente em ResourceResponse<T> ou FeedResponse<T> para medir o número de unidades de solicitação consumidas por essas operações.

    Sincronizar Java SDK V2 (Maven com.microsoft.azure::azure-documentdb)

    ResourceResponse<Document> response = client.createDocument(collectionLink, documentDefinition, null, false);
    
    response.getRequestCharge();
    

    A cobrança de solicitação retornada neste cabeçalho é uma fração da taxa de transferência provisionada. Por exemplo, se você tiver 2000 RU/s provisionados e se a consulta anterior retornar 1.000 documentos de 1KB, o custo da operação será 1000. Como tal, dentro de um segundo, o servidor honra apenas duas dessas solicitações antes de limitar as solicitações subsequentes. Para obter mais informações, consulte Unidades de solicitação e a calculadora de unidades de solicitação.

  2. Lidar com limitação de taxa / taxa de solicitação muito grande

    Quando um cliente tenta exceder a taxa de transferência reservada para uma conta, não há degradação de desempenho no servidor e nenhum uso da capacidade de taxa de transferência além do nível reservado. O servidor terminará preventivamente a solicitação com RequestRateTooLarge (código de status HTTP 429) e retornará o cabeçalho x-ms-retry-after-ms indicando a quantidade de tempo, em milissegundos, que o usuário deve aguardar antes de tentar novamente a solicitação.

        HTTP Status 429,
        Status Line: RequestRateTooLarge
        x-ms-retry-after-ms :100
    

    Todos os SDKs capturam implicitamente essa resposta, respeitam o cabeçalho retry-after especificado pelo servidor e tentam novamente a solicitação. A menos que sua conta esteja sendo acessada simultaneamente por vários clientes, a próxima tentativa será bem-sucedida.

    Se você tiver mais de um cliente operando cumulativamente acima da taxa de solicitação, a contagem de tentativas padrão atualmente definida como 9 internamente pelo cliente pode não ser suficiente; nesse caso, o cliente lança um DocumentClientException com o código de status 429 para o aplicativo. A contagem de tentativas padrão pode ser alterada usando setRetryOptions na instância ConnectionPolicy . Por padrão, o DocumentClientException com o código de status 429 é retornado após um tempo de espera cumulativo de 30 segundos se a solicitação continuar a operar acima da taxa de solicitação. Isso ocorre mesmo quando a contagem de tentativas atual é menor do que a contagem máxima de tentativas, seja o padrão de 9 ou um valor definido pelo usuário.

    Embora o comportamento de repetição automatizada ajude a melhorar a resiliência e a usabilidade para a maioria dos aplicativos, ele pode entrar em desacordo ao fazer benchmarks de desempenho, especialmente ao medir a latência. A latência observada pelo cliente aumentará se o experimento atingir o acelerador do servidor e fizer com que o SDK do cliente tente novamente. Para evitar picos de latência durante experimentos de desempenho, meça a carga retornada por cada operação e verifique se as solicitações estão operando abaixo da taxa de solicitação reservada. Para obter mais informações, consulte Unidades de solicitação.

  3. Design para documentos menores para maior taxa de transferência

    A taxa de solicitação (o custo de processamento da solicitação) de uma determinada operação está diretamente correlacionada com o tamanho do documento. As operações em documentos grandes custam mais do que as operações em documentos pequenos.

Próximos passos

Para saber mais sobre como projetar seu aplicativo para dimensionamento e alto desempenho, consulte Particionamento e dimensionamento no Azure Cosmos DB.