¿Cómo configurar el controlador MongoDB Java MongoOptions para uso en producción?

100

He estado buscando en la web las mejores prácticas para configurar MongoOptions para el controlador Java de MongoDB y no he encontrado mucho más que la API. Esta búsqueda comenzó después de que me encontré con el error "com.mongodb.DBPortPool $ SemaphoresOut: Sin semáforos para obtener una conexión de base de datos" y al aumentar las conexiones / multiplicador pude resolver ese problema. Estoy buscando enlaces o sus mejores prácticas para configurar estas opciones para producción.

Las opciones para el controlador 2.4 incluyen: http://api.mongodb.org/java/2.4/com/mongodb/MongoOptions.html

  • autoConnectRetry
  • connectionsPerHost
  • connectTimeout
  • maxWaitTime
  • socketTimeout
  • threadsAllowedToBlockForConnectionMultiplier

Los conductores más nuevos tienen más opciones y también me interesaría saber sobre ellas.

Dan Polites
fuente

Respuestas:

160

Actualizado a 2.9:

  • autoConnectRetry simplemente significa que el controlador intentará automáticamente volver a conectarse a los servidores después de desconexiones inesperadas. En entornos de producción, normalmente desea que este ajuste sea verdadero.

  • connectionsPerHost es la cantidad de conexiones físicas que una sola instancia de Mongo (es singleton, por lo que generalmente tiene una por aplicación) puede establecer en un proceso mongod / mongos. En el momento de escribir este artículo, el controlador java establecerá esta cantidad de conexiones eventualmente, incluso si el rendimiento real de la consulta es bajo (en el orden de las palabras, verá que la estadística "conn" en mongostat aumenta hasta alcanzar este número por servidor de aplicaciones).

    No es necesario establecer este valor superior a 100 en la mayoría de los casos, pero esta configuración es una de esas cosas de "probar y ver". Tenga en cuenta que deberá asegurarse de establecer este valor lo suficientemente bajo para que la cantidad total de conexiones a su servidor no exceda

    db.serverStatus().connections.available

    En producción, actualmente tenemos esto en 40.

  • connectTimeout . Como el nombre sugiere una cantidad de milisegundos, el controlador esperará antes de que se cancele un intento de conexión. Establezca el tiempo de espera en algo largo (15-30 segundos) a menos que exista una posibilidad realista y esperada de que esto se interponga en el camino de intentos de conexión exitosos. Normalmente, si un intento de conexión tarda más de un par de segundos, su infraestructura de red no es capaz de lograr un alto rendimiento.

  • maxWaitTime . Número de ms que un hilo esperará hasta que una conexión esté disponible en el grupo de conexiones y genera una excepción si esto no sucede a tiempo. Mantener predeterminado.

  • socketTimeout . Valor de tiempo de espera de socket estándar. Establecer en 60 segundos (60000).

  • threadsAllowedToBlockForConnectionMultiplier . Multiplicador de connectionsPerHost que indica la cantidad de subprocesos que pueden esperar a que las conexiones estén disponibles si el grupo está agotado actualmente. Esta es la configuración que causará la excepción "com.mongodb.DBPortPool $ SemaphoresOut: Fuera de semáforos para obtener conexión de base de datos". Lanzará esta excepción una vez que esta cola de subprocesos exceda el valor de threadsAllowedToBlockForConnectionMultiplier. Por ejemplo, si connectionsPerHost es 10 y este valor es 5, se pueden bloquear hasta 50 subprocesos antes de que se lance la excepción antes mencionada.

    Si espera grandes picos en el rendimiento que podrían causar grandes colas, aumente temporalmente este valor. Lo tenemos en 1500 en este momento exactamente por esa razón. Si la carga de su consulta supera constantemente al servidor, debería mejorar su situación de hardware / escalado en consecuencia.

  • readPreference . (ACTUALIZADO, 2.8+) Se utiliza para determinar la preferencia de lectura predeterminada y reemplaza "slaveOk". Configure una ReadPreference a través de uno de los métodos de fábrica de clases. Puede encontrar una descripción completa de las configuraciones más comunes al final de esta publicación.

  • w . (ACTUALIZADO, 2.6+) Este valor determina la "seguridad" de la escritura. Cuando este valor es -1, la escritura no informará ningún error independientemente de los errores de la red o la base de datos. WriteConcern.NONE es el WriteConcern predefinido apropiado para esto. Si w es 0, los errores de red harán que la escritura falle, pero los errores de mongo no. Esto se conoce normalmente como escrituras de "disparar y olvidar" y se debe utilizar cuando el rendimiento es más importante que la coherencia y la durabilidad. Utilice WriteConcern.NORMAL para este modo.

    Si establece w en 1 o más, la escritura se considera segura. Las escrituras seguras realizan la escritura y la siguen mediante una solicitud al servidor para asegurarse de que la escritura se realizó correctamente o recuperar un valor de error si no lo hizo (en otras palabras, envía un comando getLastError () después de escribir). Tenga en cuenta que hasta que se complete este comando getLastError (), la conexión está reservada. Como resultado de eso y del comando adicional, el rendimiento será significativamente más bajo que las escrituras con w <= 0. Con un valor de aw de exactamente 1, MongoDB garantiza que la escritura se realizó correctamente (o falló verificablemente) en la instancia a la que envió la escritura.

    En el caso de los conjuntos de réplicas, puede usar valores más altos para w que le digan a MongoDB que envíe la escritura a al menos "w" miembros del conjunto de réplicas antes de regresar (o más exactamente, espere la replicación de su escritura a "w" miembros ). También puede establecer w en la cadena "mayoría" que le dice a MongoDB que realice la escritura en la mayoría de los miembros del conjunto de réplicas (WriteConcern.MAJORITY). Por lo general, debe establecer esto en 1 a menos que necesite un rendimiento bruto (-1 o 0) o escrituras replicadas (> 1). Los valores superiores a 1 tienen un impacto considerable en el rendimiento de escritura.

  • fsync . Opción de durabilidad que obliga a mongo a descargarse en el disco después de cada escritura cuando está habilitada. Nunca he tenido problemas de durabilidad relacionados con una acumulación de escritura, por lo que tenemos esto en falso (el predeterminado) en producción.

  • j * (NUEVO 2.7+) *. Booleano que, cuando se establece en true, obliga a MongoDB a esperar una confirmación exitosa del grupo de diario antes de regresar. Si ha habilitado el registro en diario, puede habilitarlo para una mayor durabilidad. Consulte http://www.mongodb.org/display/DOCS/Journaling para ver qué le ofrece el diario (y por lo tanto, por qué es posible que desee habilitar esta marca).

ReadPreference La clase ReadPreference le permite configurar a qué instancias de mongod se enrutan las consultas si está trabajando con conjuntos de réplicas. Las siguientes opciones están disponibles :

  • ReadPreference.primary () : todas las lecturas van al miembro principal de repset únicamente. Use esto si necesita que todas las consultas devuelvan datos consistentes (los escritos más recientemente). Este es el predeterminado.

  • ReadPreference.primaryPreferred () : todas las lecturas van al miembro primario de repset si es posible, pero pueden consultar miembros secundarios si el nodo primario no está disponible. Como tal, si el primario deja de estar disponible, las lecturas eventualmente se vuelven consistentes, pero solo si el primario no está disponible.

  • ReadPreference.secondary () : todas las lecturas van a los miembros de repset secundarios y el miembro principal se usa solo para escrituras. Use esto solo si puede vivir con lecturas eventualmente consistentes. Se pueden usar miembros de repset adicionales para ampliar el rendimiento de lectura, aunque existen límites para la cantidad de miembros (votantes) que puede tener un repset.

  • ReadPreference.secondaryPreferred () : todas las lecturas van a los miembros de repset secundarios si alguno de ellos está disponible. El miembro principal se utiliza exclusivamente para escrituras a menos que todos los miembros secundarios no estén disponibles. Aparte del respaldo al miembro principal para las lecturas, esto es lo mismo que ReadPreference.secondary ().

  • ReadPreference.nearest () : las lecturas van al miembro de repset más cercano disponible para el cliente de la base de datos. Úselo solo si finalmente se aceptan lecturas consistentes. El miembro más cercano es el miembro con la latencia más baja entre el cliente y los distintos miembros de repset. Dado que los miembros ocupados eventualmente tendrán latencias más altas, esto también debería equilibrar automáticamente la carga de lectura, aunque en mi experiencia, el secundario (Preferido) parece hacerlo mejor si las latencias de los miembros son relativamente consistentes.

Nota: Todo lo anterior tiene versiones habilitadas para etiquetas del mismo método que devuelven instancias de TaggableReadPreference en su lugar. Puede encontrar una descripción completa de las etiquetas de conjuntos de réplicas aquí: Etiquetas de conjuntos de réplicas

Remon van Vliet
fuente
6
¿No es peligroso dejar socketTimeout y connectTimeout por defecto (infinito)? Si una conexión se cuelga por algún motivo, su aplicación (o al menos ese hilo) se bloqueará para siempre. ¿No deberían configurarse como muy, muy altos (algo así como 30 segundos para la conexión, 2 minutos para el enchufe)?
Idris Mokhtarzada
Idris, muy cierto. En mi publicación asumí erróneamente que MongoOptions tenía nuestros valores predeterminados. Nuestra capa Mongo ORM tiene estos en 15 segundos y 1 minuto respectivamente y mientras escribía asumí que estos eran los valores predeterminados. Los tiempos de espera infinitos son definitivamente una mala idea. Gracias por el aviso, lo arreglé en la publicación
Remon van Vliet
la opción "slaveOk" ahora está en desuso, si desea que el equivalente a esto sea verdadero, haga: mongoOptions.readPreference = ReadPreference.secondaryPreferred ();
Gubatron
Buena respuesta, pero su definición de threadsAllowedToBlockForConnectionMultiplier es incorrecta (multiplicador de palabras clave). Según los documentos: "multiplicador para connectionsPerHost para el número de subprocesos que pueden bloquear si connectionsPerHost es 10, y threadsAllowedToBlockForConnectionMultiplier es 5, entonces 50 subprocesos pueden bloquear más que eso y se lanzará una excepción"
Tyler Zale
3
Parece una respuesta bastante popular. Si alguien está interesado en que actualice esto para reflejar los cambios en el controlador más reciente, hágamelo saber
Remon van Vliet