es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Impacto en el rendimiento al migrar del controlador Java Rx de MongoDB al controlador de transmisión reactiva.

Estamos tratando de actualizar el antiguo controlador de Mongo basado en RxJava mongodb-driver-rx (v1.5.0) al nuevo mongodb-driver-reactivestreams (v1.13.1), no el más nuevo debido a las dependencias, pero sí mucho más nuevo. El antiguo RxJava ha sido descontinuado durante años. Todo funciona correctamente con el nuevo controlador, pero bajo carga elevada el rendimiento es demasiado afectado y no podemos explicar por qué.

Algunos antecedentes sobre nuestra aplicación:

Nuestra aplicación (Java) se ejecuta en AWS EC2 (en momentos de máxima actividad alrededor de 30 instancias m5.xlarge) y se basa en un stack Vertx y RxJava. Estamos ejecutando un clúster de Mongo (m5.12xlarge) con 1 primario y 2 secundarios. El número típico de conexiones simultáneas a Mongo durante los momentos de máxima actividad es de unos pocos miles. Tenemos una prueba de carga basada en gatling que generalmente se ejecuta durante 1 hora con 60 instancias de AWS EC2, 1 Mongo primario y 2 secundarios como en producción y con 100k usuarios simultáneos.

Algunas observaciones:

  • Microbenchmarking un simple fragmento de código de prueba de integración (que hace algunas operaciones comunes de db) no indica una diferencia de rendimiento significativa entre el controlador antiguo y el nuevo.
  • Con el antiguo controlador estamos viendo un buen rendimiento en general en la prueba de carga, tiempo de respuesta promedio de 20ms y tiempo de respuesta de 200ms dentro del percentil 99%.
  • Con el nuevo controlador, ejecutando la misma prueba de carga, las cosas explotan (más de 2000ms de tiempo de respuesta promedio y finalmente más del 60% de solicitudes fallidas debido a que las colas de espera se llenan).
  • Si ejecutamos la prueba de carga con solo 1 instancia de EC2 y 1.6k usuarios simultáneos (que es la misma carga por instancia), no hay una diferencia de rendimiento significativa entre el controlador antiguo y el nuevo, y las cosas funcionan relativamente sin problemas.

Configuración del controlador de MongoDB:

clusterSettings = "{hosts=[localhost:27017], mode=MULTIPLE, requiredClusterType=UNKNOWN, requiredReplicaSetName='null', serverSelector='LatencyMinimizingServerSelector{acceptableLatencyDifference=15 ms}', clusterListeners='[]', serverSelectionTimeout='30000 ms', localThreshold='30000 ms&##39;, maxWaitQueueSize=500, description='null'}"
connectionPoolSettings = "ConnectionPoolSettings{maxSize=100, minSize=0, maxWaitQueueSize=50000, maxWaitTimeMS=5000, maxConnectionLifeTimeMS=0, maxConnectionIdleTimeMS=300000, maintenanceInitialDelayMS=0, maintenanceFrequencyMS=60000, connectionPoolListeners=[]}"
heartbeatSocketSettings = "SocketSettings{connectTimeoutMS=10000, readTimeoutMS=10000, keepAlive=true, receiveBufferSize=0, sendBufferSize=0}"
readPreference = "primary"
serverSettings = "ServerSettings{heartbeatFrequencyMS=10000, minHeartbeatFrequencyMS=500, serverListeners='[]', serverMonitorListeners='[]'}"
socketSettings = "SocketSettings{connectTimeoutMS=10000, readTimeoutMS=0, keepAlive=true, receiveBufferSize=0, sendBufferSize=0}"
sslSettings = "SslSettings{enabled=false, invalidHostNameAllowed=true, context=null}"
writeConcern = "WriteConcern{w=null, wTimeout=null ms, fsync=null, journal=null"

Cosas que hemos intentado:
(todas sin éxito)

  • Cambiar la versión de la base de datos de Mongo (actualmente estamos en 3.6, pero también hemos probado 4.0);
  • Agregar un programador basado en RxJava de Vertx alrededor de cada operación de la base de datos (hemos probado Schedulers.io() y RxHelper.scheduler(vertx));
  • Configurando los ajustes de Mongo con una AsynchronousSocketChannelStreamFactoryFactory que contiene un AsynchronousChannelGroup con un pool de hilos fijo de tamaño 100;
  • Configurando los ajustes de Mongo con una NettyStreamFactoryFactory que contiene un NioEventLoopGroup;
  • Jugando con el máximo de la piscina de conexiones Mongo por instancia (varía de 100 a 500).

Cosas que no nos pueden ayudar por ahora:
(sabemos que estas, algunas están en nuestra hoja de ruta, pero serían demasiado consumidoras de tiempo por ahora)

  • Mejor gestión de índices (ya hemos optimizado esto, no hay consultas que utilicen un collscan ineficiente)
  • Dividiendo la aplicación en servicios más pequeños
  • Aliviar la carga en Mongo empleando en memoria caché del JVM (Guava) o caché remoto (Redis) – Ya hacemos esto hasta cierto punto
  • Deshacerse de Vertx a favor de, por ejemplo, Spring Boot

Parece que es algún tipo de problema de agrupamiento o de subprocesamiento, pero no podemos localizar el problema exacto, y esto también es muy difícil de perfilar.

¿Algún pensamiento sobre lo que puede estar causando el problema y cómo solucionarlo?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Posibles causas de problemas de rendimiento con el nuevo controlador de MongoDB

    Según la información proporcionada, hay algunas posibles causas de los problemas de rendimiento experimentados con el nuevo controlador de MongoDB:

    • Pooling de conexiones: El tamaño máximo del grupo de conexiones está configurado en 100, lo que puede convertirse en un cuello de botella en condiciones de alta carga. Bajo carga alta, abrir y cerrar conexiones puede causar una gran sobrecarga. Esto debería aumentarse a un valor más alto y monitoreado para asegurarse de que los límites de conexión no abrumen a MongoDB.
    • Modelo de subprocesos/threading: El controlador de Java de MongoDB ejecuta solicitudes de forma asíncrona mediante un grupo de subprocesos. Bajo cargas altas, el grupo de subprocesos podría verse abrumado, lo que llevaría a mayores tiempos de espera. Este problema puede abordarse configurando un servicio de ejecución personalizado para que lo use el controlador.
    • Incompatibilidad de versión de MongoDB: El nuevo controlador puede no ser compatible con la versión existente de MongoDB, lo que lleva a tiempos de respuesta más lentos u otros problemas. Se recomienda validar que la versión de MongoDB utilizada con el nuevo controlador sea compatible.
    • Balanceo de carga: La aplicación actualmente se ejecuta en 30 instancias de AWS EC2, pero la prueba de carga solo se ejecuta en 60 instancias. Bajo carga alta, podría haber problemas de balanceo de carga que no se observen en condiciones de carga más bajas.
    • Configuraciones del controlador de MongoDB: Las configuraciones utilizadas para el nuevo controlador pueden no ser óptimas, lo que lleva a tiempos de respuesta más lentos. Se recomienda revisar las configuraciones utilizadas y validar su eficacia en condiciones de alta carga.

    Posibles soluciones para mejorar el rendimiento

    Según la información proporcionada, las siguientes soluciones podrían ayudar a mejorar el rendimiento:

    • Aumentar el tamaño del grupo de conexiones: Aumentar el tamaño máximo del grupo de conexiones para garantizar que los límites de conexión no abrumen a MongoDB bajo carga alta.
    • Configurar un grupo de subprocesos personalizado: Configurar un grupo de subprocesos personalizado para que lo use el controlador de MongoDB, lo que podría ayudar a evitar la sobrecarga del grupo de subprocesos predeterminado del controlador.
    • Actualización de la versión de MongoDB: Actualizar a una versión más nueva de MongoDB compatible para garantizar que el nuevo controlador esté mejor optimizado para la base de datos.
    • Seguir las mejores prácticas de equilibrio de carga: Asegurarse de que se implementen prácticas adecuadas de equilibrio de carga por la aplicación en todas las instancias de AWS EC2.
    • Optimizar la configuración del controlador: Revisar y optimizar la configuración del controlador de MongoDB para garantizar su eficacia en condiciones de alta carga. Las configuraciones utilizadas deben ajustarse según las pruebas observadas y la carga objetivo.
    • Escala horizontal: La escalabilidad horizontal puede ayudar a aliviar los problemas de rendimiento, asegurando que los recursos se puedan utilizar de manera eficiente para procesar solicitudes de aplicaciones de alta carga.

    Vale la pena señalar que la solución de problemas de problemas de rendimiento puede ser desafiante, especialmente en sistemas complejos con múltiples dependencias. El perfilado y la prueba de la aplicación pueden ayudar a identificar áreas específicas para la optimización, pero esto también puede ser un gran desafío para los sistemas que operan con cargas altas.

Comments are closed.