Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Importante
No se trata de la versión de SDK de Azure Cosmos DB para Java más reciente. Debe actualizar el proyecto al SDK de Java de Azure Cosmos DB v4 y, a continuación, leer la guía de solución de problemas del SDK de Java v4 de Azure Cosmos DB. Siga las instrucciones de la guía Migración al SDK de Java de Azure Cosmos DB v4 y la guía de Reactor frente a RxJava para actualizar.
En este artículo se describe la solución de problemas solo para el SDK de Java asincrónico de Azure Cosmos DB v2. Consulte las Notas de versión del Java SDK Asíncrono v2 de Azure Cosmos DB, el repositorio de Maven y las sugerencias de rendimiento para más información.
Importante
El 31 de agosto de 2024 se retirará el SDK de Java asincrónico de Azure Cosmos DB v2.x; el SDK y todas las aplicaciones que usan el SDK seguirán funcionando; Azure Cosmos DB simplemente dejará de proporcionar más mantenimiento y soporte técnico para este SDK. Se recomienda seguir las instrucciones anteriores para migrar al SDK de Java v4 de Azure Cosmos DB.
En este artículo se tratan los problemas comunes, las soluciones alternativas, los pasos de diagnóstico y las herramientas cuando se usa el SDK asincrónico de Java con cuentas de Azure Cosmos DB para NoSQL. El SDK asincrónico de Java proporciona una representación lógica del lado cliente para acceder a Azure Cosmos DB para NoSQL. En este artículo se describen herramientas y enfoques para ayudarle si surge algún problema.
Comience con esta lista:
- Eche un vistazo a la sección Problemas y soluciones de este artículo.
- Examine el SDK, que está disponible de código abierto en GitHub. Tiene una sección de problemas que se supervisa activamente. Compruebe si encuentra algún problema similar con una solución alternativa ya registrada.
- Revise los consejos de rendimiento y siga las prácticas sugeridas.
- Lea el resto de este artículo si no encontró una solución. A continuación, abra un problema de GitHub.
Problemas comunes y soluciones alternativas
Problemas de red, error de tiempo de espera de lectura de Netty, bajo rendimiento, latencia alta
Sugerencias generales
- Asegúrese de que la aplicación se ejecuta en la misma región que la cuenta de Azure Cosmos DB.
- Compruebe el uso de cpu en el host donde se ejecuta la aplicación. Si el uso de CPU es del 90 % o más, ejecute la aplicación en un host con una configuración superior. O bien, puede distribuir la carga en más máquinas.
Regulación de velocidad de conexión
La limitación de la conexión puede producirse debido a un límite de conexión en un equipo host o el agotamiento de puertos SNAT (PAT) de Azure.
Límite de conexión en un equipo host
Algunos sistemas Linux, como Red Hat, tienen un límite superior en el número total de archivos abiertos. Los sockets en Linux se implementan como archivos, por lo que este número limita también el número total de conexiones. Ejecute el siguiente comando.
ulimit -a
El número máximo permitido de archivos abiertos, que se identifican como "nofile", debe ser al menos el doble del tamaño del grupo de conexiones. Para obtener más información, consulte Sugerencias de rendimiento.
Agotamiento de puertos SNAT (PAT) de Azure
Si la aplicación se implementa en Azure Virtual Machines sin una dirección IP pública, de forma predeterminada, los puertos SNAT de Azure establecen conexiones a cualquier punto de conexión fuera de la máquina virtual. El número de conexiones permitidas desde la máquina virtual hasta el punto de conexión de Azure Cosmos DB está limitado por la configuración de Azure SNAT.
Los puertos SNAT de Azure solo se usan cuando la máquina virtual tiene una dirección IP privada y un proceso de la máquina virtual intenta conectarse a una dirección IP pública. Hay dos soluciones alternativas para evitar la limitación de SNAT de Azure:
Agregue el punto de conexión de servicio de Azure Cosmos DB a la subred de la red virtual de Azure Virtual Machines. Para obtener más información, consulte puntos de conexión de servicio de red virtual de Azure.
Cuando se habilita el punto de conexión de servicio, las solicitudes ya no se envían desde una dirección IP pública a Azure Cosmos DB. En su lugar, se envían la red virtual y la identidad de la subred. Este cambio puede producir caídas de firewall si solo se permiten direcciones IP públicas. Si usa un firewall, cuando se habilite el punto de conexión de servicio, agregue una subred al firewall mediante las ACL de Virtual Network.
Asigne una dirección IP pública a la máquina virtual de Azure.
No se puede acceder al servicio: firewall
ConnectTimeoutException indica que el SDK no puede llegar al servicio.
Puede obtener un error similar al siguiente al usar el modo directo:
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]
Si tiene un firewall en ejecución en la máquina de la aplicación, abra el intervalo de puertos de 10 000 a 20 000, utilizados por el modo directo. Siga también el límite de conexión en un equipo host.
Proxy HTTP
Si usa un Proxy HTTP, asegúrese de que pueda admitir el número de conexiones configuradas en el SDK de ConnectionPolicy.
En caso contrario, se encontrará con problemas de conexión.
Patrón de codificación inválido: Bloqueo del hilo de E/S de Netty
El SDK usa la biblioteca de E/S de Netty para comunicarse con Azure Cosmos DB. El SDK tiene APIs asincrónicas y usa las APIs de IO sin bloqueo de Netty. El trabajo de E/S del SDK se realiza en subprocesos de E/S de Netty. El número de subprocesos de Netty I/O está configurado para que sea el mismo que el número de núcleos de CPU de la máquina de la aplicación.
Los subprocesos de E/S de Netty están diseñados para usarse solo para el trabajo de E/S de Netty sin bloqueo. El SDK devuelve el resultado de la invocación de API en uno de los subprocesos de E/S de Netty al código de la aplicación. Si la aplicación realiza una operación de larga duración después de recibir resultados en el subproceso de Netty, es posible que el SDK no tenga suficientes subprocesos de E/S para realizar su trabajo interno de E/S. Esta codificación de aplicaciones puede dar lugar a un rendimiento bajo, una latencia alta y io.netty.handler.timeout.ReadTimeoutException errores. La solución alternativa consiste en cambiar el subproceso cuando sabe que la operación tarda tiempo.
Por ejemplo, eche un vistazo al siguiente fragmento de código. Es posible que pueda realizar un trabajo de larga duración en el subproceso de Netty que tarde más de unos milisegundos. Si es así, finalmente podría alcanzar un estado en el que no haya ningún subproceso de E/S de Netty presente para procesar el trabajo de E/S. Como resultado, obtendrá un error ReadTimeoutException.
SDK de Java asincrónico V2 (Maven com.microsoft.azure::azure-cosmosdb)
@Test
public void badCodeWithReadTimeoutException() throws Exception {
int requestTimeoutInSeconds = 10;
ConnectionPolicy policy = new ConnectionPolicy();
policy.setRequestTimeoutInMillis(requestTimeoutInSeconds * 1000);
AsyncDocumentClient testClient = new AsyncDocumentClient.Builder()
.withServiceEndpoint(TestConfigurations.HOST)
.withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY)
.withConnectionPolicy(policy)
.build();
int numberOfCpuCores = Runtime.getRuntime().availableProcessors();
int numberOfConcurrentWork = numberOfCpuCores + 1;
CountDownLatch latch = new CountDownLatch(numberOfConcurrentWork);
AtomicInteger failureCount = new AtomicInteger();
for (int i = 0; i < numberOfConcurrentWork; i++) {
Document docDefinition = getDocumentDefinition();
Observable<ResourceResponse<Document>> createObservable = testClient
.createDocument(getCollectionLink(), docDefinition, null, false);
createObservable.subscribe(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) {
}
},
exception -> {
//It will be io.netty.handler.timeout.ReadTimeoutException.
exception.printStackTrace();
failureCount.incrementAndGet();
latch.countDown();
},
() -> {
latch.countDown();
});
}
latch.await();
assertThat(failureCount.get()).isGreaterThan(0);
}
La solución alternativa es cambiar el hilo en el que se realiza el trabajo que lleva tiempo. Defina una instancia singleton del planificador para su aplicación.
SDK de Java asincrónico V2 (Maven com.microsoft.azure::azure-cosmosdb)
// Have a singleton instance of an executor and a scheduler.
ExecutorService ex = Executors.newFixedThreadPool(30);
Scheduler customScheduler = rx.schedulers.Schedulers.from(ex);
Es posible que tenga que realizar trabajos que requieren tiempo, por ejemplo, trabajos computacionalmente intensivos o de bloqueo de E/S. En este caso, cambie el hilo a un trabajador proporcionado por customScheduler mediante la API de .observeOn(customScheduler).
SDK de Java asincrónico V2 (Maven com.microsoft.azure::azure-cosmosdb)
Observable<ResourceResponse<Document>> createObservable = client
.createDocument(getCollectionLink(), docDefinition, null, false);
createObservable
.observeOn(customScheduler) // Switches the thread.
.subscribe(
// ...
);
Mediante observeOn(customScheduler), libera el subproceso de E/S de Netty y cambia a su propio subproceso personalizado proporcionado por el planificador personalizado.
Esta modificación resuelve el problema. Ya no obtendrás un io.netty.handler.timeout.ReadTimeoutException error.
Problema de agotamiento del grupo de conexiones
PoolExhaustedException es un error del lado cliente. Este error indica que la carga de trabajo de la aplicación es mayor que la que puede servir el grupo de conexiones del SDK. Aumente el tamaño del grupo de conexiones o distribuya la carga en varias aplicaciones.
Tasa de solicitudes demasiado grande
Este error es un error del lado servidor. Indica que ha consumido el rendimiento aprovisionado. Vuelva a intentarlo más tarde. Si recibe este error a menudo, considere un aumento en la capacidad de procesamiento de la colección.
Error al conectarse al emulador de Azure Cosmos DB
El certificado HTTPS del emulador de Azure Cosmos DB está autofirmado. Para que el SDK funcione con el emulador, importe el certificado del emulador en una instancia de Java TrustStore. Para más información, consulte Exportación de certificados del emulador de Azure Cosmos DB.
Problemas de conflicto de dependencias
Exception in thread "main" java.lang.NoSuchMethodError: rx.Observable.toSingle()Lrx/Single;
La excepción anterior sugiere que tiene una dependencia en una versión anterior de RxJava lib (por ejemplo, 1.2.2). Nuestro SDK se basa en RxJava 1.3.8, que tiene API no disponibles en la versión anterior de RxJava.
La solución alternativa para estos problemas es identificar qué otra dependencia trae RxJava-1.2.2 y excluir la dependencia transitiva sobre RxJava-1.2.2, y permitir que el SDK de CosmosDB proporcione la versión más reciente.
Para identificar qué biblioteca incluye RxJava-1.2.2, ejecute el siguiente comando junto al archivo pom.xml del proyecto:
mvn dependency:tree
Para obtener más información, consulte la guía del árbol de dependencias de Maven.
Una vez que identifique de cuál otra dependencia de su proyecto RxJava-1.2.2 es una dependencia transitiva, puede modificar la dependencia de esa biblioteca en su archivo pom y excluir la dependencia transitiva de RxJava.
<dependency>
<groupId>${groupid-of-lib-which-brings-in-rxjava1.2.2}</groupId>
<artifactId>${artifactId-of-lib-which-brings-in-rxjava1.2.2}</artifactId>
<version>${version-of-lib-which-brings-in-rxjava1.2.2}</version>
<exclusions>
<exclusion>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
</exclusion>
</exclusions>
</dependency>
Para obtener más información, consulte la guía de dependencias transitivas de exclusión.
Habilitación del registro del SDK de cliente
El SDK asincrónico de Java usa SLF4j como fachada de registro que admite el registro en marcos de registro populares, como log4j y logback.
Por ejemplo, si desea usar log4j como marco de registro, agregue las siguientes bibliotecas en la ruta de clases de 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>
Agregue también una configuración log4j.
# this is a sample log4j configuration
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1
log4j.category.com.microsoft.azure.cosmosdb=DEBUG
#log4j.category.io.netty=INFO
#log4j.category.io.reactivex=INFO
# 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 obtener más información, consulte el manual de registro de sfl4j.
Estadísticas de red del sistema operativo
Ejecute el comando netstat para obtener una idea del número de conexiones en estados como ESTABLISHED y CLOSE_WAIT.
En Linux, puede ejecutar el siguiente comando.
netstat -nap
Filtre el resultado para mostrar solo las conexiones al punto de conexión de Azure Cosmos DB.
El número de conexiones al punto de conexión de Azure Cosmos DB en el estado ESTABLISHED no puede ser mayor que el tamaño configurado del grupo de conexiones.
Muchas conexiones al punto de conexión de Azure Cosmos DB pueden estar en estado CLOSE_WAIT . Puede haber más de 1000. Un número alto indica que las conexiones se establecen y se interrumpen rápidamente. Esta situación puede causar problemas. Para obtener más información, consulte la sección Problemas comunes y soluciones alternativas .