Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Importante
Este artigo aborda a solução de problemas somente para o SDK do Java v4 do Azure Cosmos DB. Consulte as notas de versão do SDK do Java v4 do Azure Cosmos DB, o repositório Maven e as dicas de desempenho para obter mais informações. Se você estiver usando uma versão mais antiga do que a v4, consulte o guia Migrar para o SDK do Java v4 do Azure Cosmos DB para obter ajuda com a atualização para a v4.
Este artigo aborda problemas comuns, soluções alternativas, etapas de diagnóstico e ferramentas ao usar o SDK do Java do Azure Cosmos DB v4 com o Azure Cosmos DB para contas NoSQL. O SDK do Java v4 do Azure Cosmos DB fornece representação lógica do lado do cliente para acessar o Azure Cosmos DB para NoSQL. Este artigo descreve as ferramentas e as abordagens para ajudá-lo se você tiver algum problema.
Comece com esta lista:
- Dê uma olhada na seção Problemas comuns e soluções alternativas neste artigo.
- Examine o SDK do Java no repositório central do Azure Cosmos DB, que está disponível no GitHub. Ele tem uma seção de problemas que é monitorada ativamente. Verifique se você encontrar algum problema semelhante com uma solução alternativa já arquivada. Uma dica útil é filtrar problemas pela
*cosmos:v4-item*marca. - Examine as dicas de desempenho do SDK do Java v4 do Azure Cosmos DB e siga as práticas sugeridas.
- Leia o restante deste artigo, se você não encontrou uma solução. Em seguida, registre um problema no GitHub. Se houver uma opção para adicionar tags ao problema no GitHub, adicione uma tag
*cosmos:v4-item*.
Capturar o diagnóstico
As respostas de Banco de Dados, Contêiner, Item e Consulta no SDK do Java V4 têm uma propriedade Diagnostics. Ela registra todas as informações relacionadas à solicitação única, incluindo se houve novas tentativas ou quaisquer falhas temporárias.
O Diagnóstico é retornado como uma cadeia de caracteres. A cadeia de caracteres muda com cada versão à medida que é aprimorada para melhor solucionar problemas de diferentes cenários. Com cada versão do SDK, a cadeia de caracteres pode quebrar seu formato. Não analise a cadeia de caracteres para evitar alterações interruptivas.
O exemplo de código a seguir mostra como ler logs de diagnóstico usando o SDK do Java V4:
Importante
Recomendamos validar a versão mínima recomendada do SDK do Java V4 e garantir que você esteja usando essa versão ou superior. Você pode verificar a versão recomendada aqui.
Operações de banco de dados
CosmosDatabaseResponse databaseResponse = client.createDatabaseIfNotExists(databaseName);
CosmosDiagnostics diagnostics = databaseResponse.getDiagnostics();
logger.info("Create database diagnostics : {}", diagnostics);
Operações de contêiner
CosmosContainerResponse containerResponse = database.createContainerIfNotExists(containerProperties,
throughputProperties);
CosmosDiagnostics diagnostics = containerResponse.getDiagnostics();
logger.info("Create container diagnostics : {}", diagnostics);
Operações de item
// Write Item
CosmosItemResponse<Family> item = container.createItem(family, new PartitionKey(family.getLastName()),
new CosmosItemRequestOptions());
CosmosDiagnostics diagnostics = item.getDiagnostics();
logger.info("Create item diagnostics : {}", diagnostics);
// Read Item
CosmosItemResponse<Family> familyCosmosItemResponse = container.readItem(documentId,
new PartitionKey(documentLastName), Family.class);
CosmosDiagnostics diagnostics = familyCosmosItemResponse.getDiagnostics();
logger.info("Read item diagnostics : {}", diagnostics);
Operações de consulta
String sql = "SELECT * FROM c WHERE c.lastName = 'Witherspoon'";
CosmosPagedIterable<Family> filteredFamilies = container.queryItems(sql, new CosmosQueryRequestOptions(),
Family.class);
// Add handler to capture diagnostics
filteredFamilies = filteredFamilies.handle(familyFeedResponse -> {
logger.info("Query Item diagnostics through handle : {}",
familyFeedResponse.getCosmosDiagnostics());
});
// Or capture diagnostics through iterableByPage() APIs.
filteredFamilies.iterableByPage().forEach(familyFeedResponse -> {
logger.info("Query item diagnostics through iterableByPage : {}",
familyFeedResponse.getCosmosDiagnostics());
});
Exceções do Azure Cosmos DB
try {
CosmosItemResponse<Family> familyCosmosItemResponse = container.readItem(documentId,
new PartitionKey(documentLastName), Family.class);
} catch (CosmosException ex) {
CosmosDiagnostics diagnostics = ex.getDiagnostics();
logger.error("Read item failure diagnostics : {}", diagnostics);
}
Registrando diagnósticos em log
As versões do SDK Java V4 v4.43.0 e posteriores suportam o registro automático de diagnósticos do Cosmos para todas as solicitações ou erros se atenderem a determinados critérios. Os desenvolvedores de aplicativos podem definir limites para latência (para operações pontuais (criar, ler, substituir, upsert, patch) ou operações não pontuais (consulta, feed de alterações, em massa e em lote)), carga da solicitação e tamanho da carga útil. Se as solicitações excederem esses limites definidos, o diagnóstico do cosmos para essas solicitações será emitido automaticamente.
Por padrão, o SDK do Java v4 registra esses diagnósticos automaticamente em um formato específico. No entanto, isso pode ser alterado implementando CosmosDiagnosticsHandler a interface e fornecendo seu próprio Manipulador de Diagnóstico personalizado.
Esses CosmosDiagnosticsThresholds e CosmosDiagnosticsHandler podem ser usados no objeto CosmosClientTelemetryConfig, que deve ser passado em CosmosClientBuilder ao criar um cliente assíncrono ou síncrono.
OBSERVAÇÃO: esses limites de diagnóstico são aplicados em diferentes tipos de diagnóstico, incluindo registro em log, rastreamento e telemetria do cliente.
Os exemplos de código a seguir mostram como definir limites de diagnóstico, agente de diagnóstico personalizado e usá-los por meio da configuração de telemetria do cliente:
Definindo limites de diagnóstico personalizados
// Create diagnostics threshold
CosmosDiagnosticsThresholds cosmosDiagnosticsThresholds = new CosmosDiagnosticsThresholds();
// These thresholds are for demo purposes
// NOTE: Do not use the same thresholds for production
cosmosDiagnosticsThresholds.setPayloadSizeThreshold(100_00);
cosmosDiagnosticsThresholds.setPointOperationLatencyThreshold(Duration.ofSeconds(1));
cosmosDiagnosticsThresholds.setNonPointOperationLatencyThreshold(Duration.ofSeconds(5));
cosmosDiagnosticsThresholds.setRequestChargeThreshold(100f);
Definindo o manipulador de Diagnósticos personalizado
// By default, DEFAULT_LOGGING_HANDLER can be used
CosmosDiagnosticsHandler cosmosDiagnosticsHandler = CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER;
// App developers can also define their own diagnostics handler
cosmosDiagnosticsHandler = new CosmosDiagnosticsHandler() {
@Override
public void handleDiagnostics(CosmosDiagnosticsContext diagnosticsContext, Context traceContext) {
logger.info("This is custom diagnostics handler: {}", diagnosticsContext.toJson());
}
};
Definindo CosmosClientTelemetryConfig
// Create Client Telemetry Config
CosmosClientTelemetryConfig cosmosClientTelemetryConfig =
new CosmosClientTelemetryConfig();
cosmosClientTelemetryConfig.diagnosticsHandler(cosmosDiagnosticsHandler);
cosmosClientTelemetryConfig.diagnosticsThresholds(cosmosDiagnosticsThresholds);
// Create sync client
CosmosClient client = new CosmosClientBuilder()
.endpoint(AccountSettings.HOST)
.key(AccountSettings.MASTER_KEY)
.clientTelemetryConfig(cosmosClientTelemetryConfig)
.buildClient();
Design de tentativa novamente
Confira nosso guia para obter diretrizes sobre como criar aplicativos resilientes com SDKs do Azure Cosmos DB e para saber qual é a semântica de repetição do SDK.
Problemas comuns e soluções alternativas
Verificar as métricas do portal
Verificar as métricas do portal ajuda a determinar se é um problema do lado do cliente ou se há um problema com o serviço. Por exemplo, se as métricas contêm uma alta taxa de solicitações com taxa limitada (código de status HTTP 429), o que significa que a solicitação está sendo limitada, verifique a seção Taxa de solicitação muito alta.
Problemas de rede, falha de tempo limite de leitura do Netty, baixa taxa de transferência, alta latência
Sugestões gerais
Para obter o melhor desempenho:
- Verifique se o aplicativo está em execução na mesma região que sua conta do Azure Cosmos DB.
- Verifique o uso da CPU no host em que o aplicativo está sendo executado. Se o uso da CPU for de 50% ou mais, execute seu aplicativo em um host com uma configuração mais alta. Ou você pode distribuir a carga em mais computadores.
- Se você estiver executando seu aplicativo no Serviço de Kubernetes do Azure, poderá usar o Azure Monitor para monitorar a utilização da CPU.
Limitação de conexão
A limitação de conexão pode acontecer devido a um limite de conexão em um computador host ou ao esgotamento da porta do Azure SNAT (PAT).
Limite de conexão em um computador host
Alguns sistemas Linux, como o Red Hat, têm um limite superior no número total de arquivos abertos. Soquetes no Linux são implementados como arquivos, portanto, esse número também limita o número total de conexões. Execute o comando a seguir.
ulimit -a
O número máximo de arquivos abertos permitidos, identificados como "nofile", precisa ser pelo menos o dobro do tamanho do pool de conexões. Para obter mais informações, consulte as dicas de desempenho do SDK do Java v4 do Azure Cosmos DB.
Esgotamento da porta do Azure SNAT (PAT)
Se seu aplicativo for implantado em Máquinas Virtuais do Azure sem um endereço IP público, por padrão, as portas SNAT do Azure estabelecerão conexões com qualquer ponto de extremidade fora da VM. O número de conexões permitidas da VM para o ponto de extremidade do Azure Cosmos DB é limitado pela configuração do Azure SNAT.
As portas SNAT do Azure são usadas somente quando sua VM tem um endereço IP privado e um processo da VM tenta se conectar a um endereço IP público. Há duas soluções alternativas para evitar a limitação do SNAT do Azure:
Adicione seu ponto de extremidade de serviço do Azure Cosmos DB para a sub-rede da sua rede virtual de Máquinas Virtuais do Azure. Para saber mais, consulte pontos de extremidade de serviço de Rede Virtual do Microsoft Azure.
Quando o endpoint do serviço está habilitado, as solicitações não são mais enviadas de um IP público para o Azure Cosmos DB. Em vez disso, a rede virtual e a identidade de sub-rede são enviadas. Essa alteração poderá resultar em quedas de firewall se apenas IPs públicos forem permitidos. Se você usar um firewall, ao habilitar o ponto de extremidade de serviço, adicione uma sub-rede ao firewall usando as ACLs de Rede Virtual.
Atribua um IP público à VM do Azure.
Não é possível acessar o Serviço – firewall
ConnectTimeoutException indica que o SDK não pode acessar o serviço.
Você pode obter uma falha semelhante à seguinte ao usar o modo direto:
GoneException{error=null, resourceAddress='https://cdb-ms-prod-westus-fd4.documents.azure.com:14940/apps/e41242a5-2d71-5acb-2e00-5e5f744b12de/services/d8aa21a5-340b-21d4-b1a2-4a5333e7ed8a/partitions/ed028254-b613-4c2a-bf3c-14bd5eb64500/replicas/131298754052060051p//', statusCode=410, message=Message: The requested resource is no longer available at the server., getCauseInfo=[class: class io.netty.channel.ConnectTimeoutException, message: connection timed out: cdb-ms-prod-westus-fd4.documents.azure.com/101.13.12.5:14940]
Se você tiver um firewall em execução no computador do aplicativo, abra o intervalo de portas de 10.000 a 20.000, que são usados pelo modo direto. Siga também o limite de conexão em um computador host.
UnknownHostException
UnknownHostException significa que a estrutura Java não consegue resolver a entrada DNS do ponto de extremidade do Azure Cosmos DB no computador afetado. Você deve verificar se o computador pode resolver a entrada DNS ou se há algum software de resolução DNS personalizado (como VPN ou proxy ou uma solução personalizada) e se ele contém a configuração certa do ponto de extremidade DNS que o erro está indicando que não pode ser resolvido. Se o erro for constante, você poderá verificar a resolução DNS do computador com o comando curl para o ponto de extremidade descrito no erro.
Proxy HTTP
Se você usar um proxy HTTP, certifique-se que pode suportar o número de conexões configuradas no SDK ConnectionPolicy.
Caso contrário, você enfrentará problemas de conexão.
Padrão de codificação inválido: Bloquear o thread de E/S do Netty
O SDK usa a biblioteca de E/S do Netty para se comunicar com o Azure Cosmos DB. O SDK tem uma API Assíncrona e usa APIs de E/S não desbloqueadas do Netty. O trabalho de E/S do SDK é executado em threads do IO Netty. O número de threads do IO Netty é configurado para ser o mesmo que o número de núcleos de CPU do computador de aplicativo.
As threads de E/S do Netty devem ser usadas apenas para o trabalho de E/S não bloqueante do Netty. O SDK retorna o resultado da invocação de API em um dos threads de E/S do Netty para o código do aplicativo. Se o aplicativo executar uma operação de longa duração depois de receber resultados no thread do Netty, o SDK poderá não ter threads de E/S suficientes para executar seu trabalho de E/S interno. Essa codificação de aplicativo pode resultar em baixa taxa de transferência, alta latência e io.netty.handler.timeout.ReadTimeoutException falhas. A solução alternativa é alternar o thread quando você souber que a operação leva tempo.
Por exemplo, dê uma olhada no snippet de código a seguir, que adiciona itens a um contêiner (procure aqui diretrizes sobre como configurar o banco de dados e o contêiner). Você pode executar uma tarefa prolongada que dure mais do que alguns milissegundos na thread Netty. Em caso afirmativo, você poderá entrar em um estado em que nenhum thread de E/S do Netty está presente para realizar operações de E/S. Como resultado, você obtém uma falha de ReadTimeoutException.
API assíncrona do SDK do Java V4 (Maven com.azure::azure-cosmos)
//Bad code with read timeout exception
int requestTimeoutInSeconds = 10;
/* ... */
AtomicInteger failureCount = new AtomicInteger();
// Max number of concurrent item inserts is # CPU cores + 1
Flux<Family> familyPub =
Flux.just(Families.getAndersenFamilyItem(), Families.getAndersenFamilyItem(), Families.getJohnsonFamilyItem());
familyPub.flatMap(family -> {
return container.createItem(family);
}).flatMap(r -> {
try {
// Time-consuming work is, for example,
// writing to a file, computationally heavy work, or just sleep.
// Basically, it's anything that takes more than a few milliseconds.
// Doing such operations on the IO Netty thread
// without a proper scheduler will cause problems.
// The subscriber will get a ReadTimeoutException failure.
TimeUnit.SECONDS.sleep(2 * requestTimeoutInSeconds);
} catch (Exception e) {
}
return Mono.empty();
}).doOnError(Exception.class, exception -> {
failureCount.incrementAndGet();
}).blockLast();
assert(failureCount.get() > 0);
A solução alternativa é alterar o thread no qual você executa um trabalho que leva tempo. Defina uma instância singleton do agendador para seu aplicativo.
API assíncrona do SDK do Java V4 (Maven com.azure::azure-cosmos)
// Have a singleton instance of an executor and a scheduler.
ExecutorService ex = Executors.newFixedThreadPool(30);
Scheduler customScheduler = Schedulers.fromExecutor(ex);
Talvez seja necessário fazer um trabalho que leve tempo, por exemplo, trabalho computacionalmente pesado ou bloqueio de E/S. Nesse caso, alterne o thread para um worker fornecido pelo seu customScheduler usando a API .publishOn(customScheduler).
API assíncrona do SDK do Java V4 (Maven com.azure::azure-cosmos)
container.createItem(family)
.publishOn(customScheduler) // Switches the thread.
.subscribe(
// ...
);
Ao usar publishOn(customScheduler), você libera o thread de E/S do Netty e alterna para seu próprio thread personalizado fornecido pelo agendador personalizado. Essa modificação resolve o problema. Você não terá mais um io.netty.handler.timeout.ReadTimeoutException fracasso.
Taxa de solicitações muito alta
Essa falha é uma falha no lado do servidor. Indica que você consumiu sua taxa de transferência provisionada. Tente novamente mais tarde. Se você encontrar esse erro com frequência, considere aumentar a capacidade de processamento da coleção.
Implementar o retrocesso em intervalos de getRetryAfterInMilliseconds
Durante o teste de desempenho, você deve aumentar a carga até que uma pequena porcentagem de solicitações seja sufocada. Se limitado, o aplicativo cliente deverá recuar para o intervalo de repetição especificado pelo servidor. Respeitar o backoff garante que você passe o mínimo de tempo aguardando entre tentativas.
Tratamento de erros da cadeia reativa do SDK do Java
O tratamento de erros do SDK java do Azure Cosmos DB é importante quando se trata da lógica do aplicativo do cliente. Há diferentes mecanismos de tratamento de erros fornecidos pela estrutura de núcleo de reator que podem ser usados em cenários diferentes. Recomendamos que os clientes entendam detalhadamente esses operadores de tratamento de erros e usem os que se ajustam melhor aos seus cenários lógicos de repetição.
Importante
Não recomendamos usar onErrorContinue() o operador, pois ele não tem suporte em todos os cenários.
Observe que onErrorContinue() é um operador especializado que pode tornar o comportamento de sua cadeia reativa pouco claro. Ele opera em operadores upstream, não em downstream; requer suporte de operador específico para funcionar, e o escopo pode facilmente se propagar upstream para o código da biblioteca que não o antecipou, resultando em comportamento não intencional. Consulte a documentação de onErrorContinue() para obter mais informações sobre este operador especial.
Falha ao conectar-se ao Emulador do Azure Cosmos DB
O certificado HTTPS do Emulador do Azure Cosmos DB é autoassinado. Para que o SDK trabalhe com o emulador, importe o certificado do emulador para um Java TrustStore. Para obter mais informações, consulte Exportar certificados do Emulador do Azure Cosmos DB.
Problemas de conflito de dependência
O SDK Java do Azure Cosmos DB importa muitas dependências; em geral, se a árvore de dependência do seu projeto incluir uma versão mais antiga de um artefato do qual o SDK Java do Azure Cosmos DB depende, isso pode resultar em erros inesperados ao executar seu aplicativo. Se você estiver depurando por que seu aplicativo lança inesperadamente uma exceção, é uma boa ideia conferir novamente se sua árvore de dependências não está acidentalmente trazendo uma versão mais antiga de uma ou mais das dependências do Java SDK do Azure Cosmos DB.
A solução alternativa para esse problema é identificar qual das dependências do projeto traz a versão antiga e excluir a dependência transitiva dessa versão mais antiga e permitir que o SDK do Java do Azure Cosmos DB traga a versão mais recente.
Para identificar qual das dependências do seu projeto traz uma versão mais antiga de algo de que o SDK Java do Azure Cosmos DB depende, execute o seguinte comando no arquivo pom.xml do seu projeto:
mvn dependency:tree
Para obter mais informações, consulte o guia da árvore de dependência do maven.
Depois de saber qual dependência do seu projeto depende de uma versão mais antiga, você pode modificar a dependência dessa lib no arquivo pom e excluir a dependência transitiva, seguindo o exemplo abaixo (que pressupõe que o reator-núcleo é a dependência desatualizada):
<dependency>
<groupId>${groupid-of-lib-which-brings-in-reactor}</groupId>
<artifactId>${artifactId-of-lib-which-brings-in-reactor}</artifactId>
<version>${version-of-lib-which-brings-in-reactor}</version>
<exclusions>
<exclusion>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</exclusion>
</exclusions>
</dependency>
Para obter mais informações, consulte o guia excluir dependência transitiva.
Habilitar o registro em log do SDK do cliente
O SDK Java v4 do Azure Cosmos DB usa o SLF4j como a fachada de registro que dá suporte ao registro em frameworks de registro populares, como log4j e logback.
Por exemplo, se você quiser usar log4j como a estrutura de log, adicione as seguintes libs em seu classpath Java.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
Adicione também uma configuração do log4j.
# this is a sample log4j configuration
# Set root logger level to INFO and its only appender to A1.
log4j.rootLogger=INFO, A1
log4j.category.com.azure.cosmos=INFO
#log4j.category.io.netty=OFF
#log4j.category.io.projectreactor=OFF
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n
Para obter mais informações, consulte o manual de log sfl4j.
Estatísticas de rede do sistema operacional
Execute o comando netstat para ter uma noção de quantas conexões estão em estados como ESTABLISHED e CLOSE_WAIT.
No Linux, você pode executar o comando a seguir.
netstat -nap
No Windows, você pode executar o mesmo comando com diferentes sinalizadores de argumento:
netstat -abn
Filtre o resultado somente para conexões com o endpoint do Azure Cosmos DB.
O número de conexões com o ponto de extremidade do Azure Cosmos DB no estado ESTABLISHED não pode ser maior do que o tamanho do pool de conexões configurado.
Muitas conexões com o endpoint do Azure Cosmos DB podem estar no estado CLOSE_WAIT. Pode haver mais de 1.000. Um número alto indica que as conexões são estabelecidas e interrompidas rapidamente. Essa situação potencialmente causa problemas. Para obter mais informações, consulte a seção Problemas comuns e soluções alternativas .
Problemas comuns de consulta
As métricas de consulta ajudam a determinar onde a consulta está passando a maior parte do tempo. Nas métricas de consulta, você pode ver quanto está sendo gasto no back-end em comparação com o cliente. Saiba mais sobre o guia de desempenho da consulta.
Próximas etapas
- Saiba mais sobre as diretrizes de desempenho para o SDK do Java v4
- Saiba mais sobre as práticas recomendadas para o SDK do Java v4