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()
yRxHelper.scheduler(vertx)
); - Configurando los ajustes de Mongo con una
AsynchronousSocketChannelStreamFactoryFactory
que contiene unAsynchronousChannelGroup
con un pool de hilos fijo de tamaño 100; - Configurando los ajustes de Mongo con una
NettyStreamFactoryFactory
que contiene unNioEventLoopGroup
; - 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?
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:
Posibles soluciones para mejorar el rendimiento
Según la información proporcionada, las siguientes soluciones podrían ayudar a mejorar el rendimiento:
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.