Mejores Prácticas para Optimizar el Rendimiento de Lectura en Conjuntos de Réplicas
Mejora las lecturas en conjuntos de réplicas de MongoDB con preferencia de lectura, preocupación de lectura, monitoreo de retraso, indexación y controles de tiempo de espera.
Mejores Prácticas para Optimizar el Rendimiento de Lectura en Conjuntos de Réplicas
Los conjuntos de réplicas de MongoDB ofrecen alta disponibilidad, pero no hacen que las lecturas sean más rápidas automáticamente. Si tu aplicación envía cada consulta al primario, utiliza índices débiles o lee de secundarios con retraso, los usuarios lo sentirán como páginas lentas y datos obsoletos.
Un buen rendimiento de lectura proviene de elegir la preferencia de lectura correcta, igualar la preocupación de lectura con la consistencia que necesitas, monitorear el retraso de replicación y corregir primero las consultas lentas.
Entendiendo la Ruta de Lectura en Conjuntos de Réplicas
En una implementación estándar de conjunto de réplicas, un miembro se designa como el primario, manejando todas las escrituras. Los miembros restantes son secundarios, que replican asincrónicamente los datos del primario. Las lecturas de la aplicación pueden dirigirse al primario o distribuirse entre los secundarios, dependiendo de la configuración.
Optimizar las lecturas significa equilibrar la necesidad de consistencia inmediata de datos (que a menudo requiere leer del primario) con el deseo de descargar tráfico del primario (leyendo de secundarios).
1. Uso Estratégico de las Preocupaciones de Lectura
Preocupación de Lectura define el grado de consistencia de datos requerido para las operaciones de lectura. Establecer una preocupación de lectura demasiado estricta cuando una más relajada es suficiente es una causa común de latencia de lectura, ya que puede forzar a la operación a esperar confirmaciones de múltiples nodos.
Preocupaciones de Lectura Disponibles
MongoDB ofrece varias preocupaciones de lectura, cada una intercambiando latencia por durabilidad/consistencia:
| Preocupación de Lectura | Descripción | Caso de Uso |
|---|---|---|
majority |
Devuelve datos confirmados como comprometidos por una mayoría de nodos votantes. Predeterminado estándar. | Lecturas de propósito general que requieren alta durabilidad. |
local |
Devuelve los datos más recientes disponibles en el miembro desde el que se lee, independientemente de la confirmación de escritura. | Lecturas que pueden tolerar algunos datos obsoletos (por ejemplo, contadores de panel). |
linearizable |
Lee del primario y refleja todas las escrituras confirmadas antes de que comenzara la lectura. Requiere readConcern: "linearizable" y preocupación de escritura mayoritaria para las escrituras relevantes. |
Lecturas raras que deben observar el último estado confirmado, como verificaciones de propiedad de bloqueo. |
Consejo de Optimización: Predeterminar a local o majority
Para lecturas no críticas (como cargar datos de configuración actualizados con poca frecuencia o resultados en caché), usa la preocupación de lectura local en secundarios. Esto evita cualquier retraso de sincronización.
Ejemplo: Establecer Preocupación de Lectura a Nivel de Sesión
// Establecer preocupación de lectura a 'local' para esta sesión específica
const session = mongoClient.startSession({ readConcern: { level: "local" } });
// Operación de búsqueda usando la sesión
db.collection('mydata').find().session(session).toArray();
Advertencia: Leer con preocupación
localen un secundario puede devolver datos obsoletos en relación con el primario.
2. Distribuir Lecturas Entre Secundarios
Por defecto, MongoDB dirige las lecturas al primario. Para escalar la capacidad de lectura, debes dirigir explícitamente las lecturas a secundarios usando configuraciones de Preferencia de Lectura.
Entendiendo la Preferencia de Lectura
La Preferencia de Lectura dicta qué miembros del conjunto de réplicas son elegibles para satisfacer solicitudes de lectura y en qué orden deben ser elegidos.
Preferencias de Lectura Comunes incluyen:
primary: (Predeterminado) Solo el primario es elegible.primaryPreferred: Intenta primero con el primario; recurre a un secundario si el primario no está disponible.secondary: Solo los secundarios son elegibles. Si no hay secundarios disponibles, la operación falla.secondaryPreferred: Prefiere secundarios; recurre al primario si no hay secundarios disponibles.nearest: Elige el miembro (primario o secundario) con la latencia de red más baja hacia el cliente.
Consejo de Optimización: Usar secondaryPreferred o nearest
Para la mayoría de las aplicaciones con muchas lecturas, usar secondaryPreferred permite distribuir la carga de consultas entre todos los secundarios disponibles, reduciendo significativamente la carga en el primario.
Si tienes servidores de aplicación distribuidos geográficamente, nearest es a menudo la mejor opción, ya que minimiza la latencia de red para el cliente, incluso si ocasionalmente golpea al primario.
Ejemplo: Conectar con secondaryPreferred
Al conectar el controlador de tu aplicación, especifica la preferencia de lectura:
const uri = "mongodb://host1,host2,host3/?replicaSet=rs0&readPreference=secondaryPreferred";
// O usando opciones de conexión en una configuración de controlador
const options = {
readPreference: "secondaryPreferred"
};
3. Gestionar la Sincronización y el Retraso de Secundarios
Si estás dirigiendo lecturas a secundarios, el rendimiento de esas lecturas depende completamente de qué tan rápido los secundarios se mantienen al día con el primario. Un retraso de replicación alto significa que los secundarios están sirviendo datos obsoletos, o si el retraso es demasiado alto, las lecturas podrían fallar o agotar el tiempo de espera.
Monitorear el Retraso de Replicación
Siempre monitorea la diferencia de optime entre el primario y los secundarios. rs.status() muestra el estado de replicación por miembro, y herramientas administradas como MongoDB Atlas, Cloud Manager u Ops Manager pueden alertar sobre el retraso.
rs.status().members.map(m => ({
name: m.name,
stateStr: m.stateStr,
optimeDate: m.optimeDate
}))
Impacto de la Preocupación de Escritura en el Rendimiento del Secundario
Aunque este artículo se centra en lecturas, configuraciones altas de preocupación de escritura pueden impactar indirectamente el rendimiento de lectura al ralentizar el primario, lo que a su vez hace que los secundarios se queden más atrás.
Por ejemplo, requerir w: "majority" significa que el cliente no recibe confirmación hasta que la escritura haya llegado a una mayoría de miembros votantes que contienen datos. Si los secundarios son lentos debido a presión de disco o red, la latencia de escritura de la aplicación puede aumentar, y esos mismos secundarios sobrecargados también pueden servir lecturas lentas.
Mejor Práctica para Preocupación de Escritura (Optimización Indirecta de Lectura): No bajes la preocupación de escritura solo para hacer que las lecturas parezcan más rápidas. Elige la preocupación de escritura basada en los requisitos de durabilidad, luego corrige la causa del retraso: discos lentos, secundarios sobrecargados, oplog subdimensionado, problemas de red o consultas que compiten con la replicación.
4. Indexación y Optimización de Consultas
Ninguna configuración puede superar una consulta mal escrita. El principio fundamental de las lecturas rápidas sigue siendo una indexación robusta.
Consideraciones Clave de Indexación
- Consultas Cubiertas: Diseña consultas que puedan ser completamente satisfechas por un índice sin recuperar documentos del disco. Estas son las lecturas más rápidas posibles.
- Alineación de Índices: Asegúrate de que los índices coincidan con los campos utilizados en tus cláusulas
find(),sort()yprojection(). - Evitar Escaneos de Colección: Siempre verifica en el perfilador de consultas que las operaciones de lectura estén usando índices (
IXSCAN) en lugar de realizar escaneos completos de colección (COLLSCAN).
Ajustar Tiempos de Espera de Consultas
Si una aplicación está golpeando un secundario con mucho retraso, la consulta podría agotar el tiempo de espera. Configura tiempos de espera razonables en tu aplicación para manejar elegantemente el retraso temporal, quizás recurriendo al primario o reintentando más tarde, en lugar de colgarse indefinidamente.
Resumen de Pasos para Optimizar Lecturas
Para lograr un rendimiento de lectura óptimo en tu conjunto de réplicas de MongoDB, sigue estos pasos accionables:
- Identificar Tipos de Lectura: Clasifica las lecturas en aquellas que necesitan datos frescos del primario y aquellas que pueden tolerar consistencia eventual de secundarios.
- Configurar Preferencia de Lectura: Establece la cadena de conexión o las opciones de sesión para usar
secondaryPreferredonearestpara la mayoría del tráfico de la aplicación. - Monitorear Retraso: Monitorea continuamente el retraso de replicación desde
rs.status(), métricas del controlador o tu plataforma de monitoreo. Si el retraso es consistentemente alto, investiga problemas de hardware secundario o de red. - Revisar Preocupaciones de Escritura: Asegúrate de que las preocupaciones de escritura no estén ralentizando indebidamente al primario, lo que priva a los secundarios de datos frescos.
- Indexar a Fondo: Verifica que todas las rutas de lectura ejecutadas con frecuencia utilicen índices eficientes.
El escalado de lectura en conjuntos de réplicas funciona mejor cuando eres honesto sobre la obsolescencia. Envía lecturas críticas para el usuario al primario cuando deben estar actualizadas, usa secundarios para análisis o paneles que puedan tener retraso, y sigue midiendo los planes de consulta y la salud de la replicación a medida que el tráfico cambia.