IT & Engineering
Cómo logramos una mejora de rendimiento de 30x en las preferencias de lectura de MongoDB
Ya sabes lo que dicen… cuanto más redundante eres, más redundante eres.
Los conjuntos de réplicas son procesos de bases de datos que proporcionan una alta disponibilidad y reducen las conmutaciones por error del servidor mediante la redundancia. Son la base de los despliegues de producción y no están pensados para ser herramientas independientes que mejoren tu tiempo de respuesta y tus métricas de rendimiento. En Mailgun, notamos tiempos de respuesta altos en uno de nuestros nodos que soporta estos procesos. Odiamos ir lentos, especialmente cuando no tiene sentido. Así que nos propusimos solucionarlo.
Tiempos de respuesta anormales: búsqueda de la causa raíz
Ya en 2021, notamos algunos problemas de rendimiento extraños en nuestros tiempos de respuesta para USW2. ¿Por qué lo sacamos a relucir ahora? Bueno, todavía nos beneficiamos de las actualizaciones que hicimos y queremos compartirlo contigo.
Lo primero que notamos fue que nuestro servicio de límite de velocidad (basado en Gubernator) mostraba tiempos de respuesta constantes de 150 ms para nuestros procesos en USW2. Curiosamente, el mismo código promediaba unos 5 ms en el percentil 99 de las solicitudes. Esta latencia era particularmente extraña, ya que promediamos un tiempo de respuesta de unos 2 ms en el percentil 50. Por lo tanto, había algo que realmente necesitábamos investigar.
Nuestro punto de partida fue comparar las métricas entre USW2 y USW1. Añadimos algunas métricas adicionales para registrar cuánto se tardaba en obtener las definiciones de los límites de velocidad de MongoDB (cuando fallaba la caché), lo que nos permitió entender mejor lo que estaba pasando.

El gráfico resultante confirmó la tendencia de 150 ms en USW2, pero también mostró tiempos de respuesta de 2 a 5 ms de MongoDB en USE1. Esto aisló el problema y confirmó que pasaba algo con la configuración de MongoDB que afectaba a USW2 de forma específica.
Rendimiento de MongoDB: información de la documentación
Así que el “Paso 1: localizar el problema” estaba completado.
A continuación, nos sumergimos de lleno en la documentación de MongoDB. El momento de iluminación llegó una vez que entendimos la topología principal de MongoDB y descubrimos las preferencias de lectura predeterminadas de MongoDB. Los clientes de MongoDB prefieren la instancia principal de un clúster al realizar lecturas. No siempre es agradable cuando tu base de datos tiene favoritos.

En la configuración predeterminada del cliente de MongoDB, el cliente en USW2 estaba haciendo una lectura entre regiones hacia el nodo principal en USE1. Los valores predeterminados de MongoDB están configurados para que las operaciones lean desde los miembros secundarios, a menos que el conjunto tenga un único nodo principal.
Su documentación indicaba que si usábamos readPreference=secondaryPreferred en nuestro cliente de MongoDB, podríamos conectarnos a los nodos locales de MongoDB en lugar de solo al principal (USE1).

Perfecto. Esta estructuración nos permitiría optimizar el rendimiento, ya que distribuye las lecturas en varios servidores secundarios donde cada servidor responde a menos solicitudes de lectura. Pensamos que actualizar nuestras preferencias de lectura resolvería el problema, pero nunca es tan sencillo, ¿verdad? A veces la situación es un auténtico caos en el clúster (juego de palabras intencionado).
Resolución de problemas del cliente de MongoDB de Golang
De verdad pensábamos que lo habíamos clavado con esas preferencias de lectura, pero ahora no podíamos conectarnos al clúster usando la URI:
mongodb://mongo-main-n01-us-east-1.postgun.com:27017,mongo-main-n02-us-eas t-1.postgun.com:27017,mongo-main-n03-us-east-1.postgun.com:27017/?tlsCerti ficateKeyFile=/etc/mailgun/ssl/mongo.pem&tlsCAFile=/etc/mailgun/ssl/mongo ca.crt&replicaSet=main&readPreference=secondary&readPreferenceTags=dc:use1 &readPreferenceTags=dc:usw2
Resulta que estábamos usando una versión más antigua del cliente de MongoDB (go.mongodb.org/mongo-driver v1.0.2) que no era compatible con nuestras opciones de TLS. Una vez que nos dimos cuenta de eso, por fin pudimos desplegar y ver si la actualización de nuestras preferencias de lectura tenía algún impacto después de la actualización a go.mongodb.org/mongo-driver v1.7.3 y de solucionar un pequeño problema de formato de URI con nuestro marco:
PIP-1477: URIWithOptions() now correctly injects a '/' after host list by thrawn01 · Pull Request #92 · mailgun/holster
Mejora del rendimiento de MongoDB
Esto por fin funcionó. El efecto fue espectacular y dio como resultado una mejora de ~30x (tiempo de respuesta de 5 a 10 ms en el percentil 99) en el rendimiento de lectura para USW2. Nada mal.

Nuestra solución comenzó con una investigación de las tasas de obtención para aislar el servidor afectado y nos llevó a optimizar nuestra lógica de preferencias de lectura basándonos en la documentación del cliente de MongoDB. En última instancia, descubrimos que esto también era un problema de versión y que necesitábamos actualizar nuestro controlador Go de MongoDB para conectarnos correctamente a la URI del clúster y mejorar nuestro tiempo de respuesta.
Cómo seguimos optimizando
Diagnosticar la causa raíz es parte del camino del equipo de desarrollo, y la resolución de problemas de rendimiento se hace capa por capa. Si experimentas una latencia similar en tus métricas, empieza por evaluar tus servidores, los servicios de limitación de velocidad, y no olvides comprobar las funciones compatibles de la versión de tu controlador de Mongo.
Investigaciones y actualizaciones como esta son la forma en que trabajamos para crear un mejor sistema general y experiencia de usuario. Por lo tanto, si quieres recibir más información de nuestro equipo de ingeniería, asegúrate de suscribirte para no perderte las próximas historias e información de operaciones.