Mongoose: No vuelva a conectarse después de la desconexión

Creado en 26 oct. 2016  ·  47Comentarios  ·  Fuente: Automattic/mongoose

Después de actualizar de 4.4.11 a> = 4.6.1, obtenemos desconexiones aleatorias y la mangosta nunca se vuelve a conectar.

versión mangosta: 4.6.5
versión mongodb: 3.2.9

Esta es la forma en que creo las conexiones:

    var uri = 'mongodb://USENAME:PASSWORD<strong i="9">@host1</strong>:port1,host2:port2/database?authSource=admin';

    var options = {};
    options.server = {
      auto_reconnect: true,
      poolSize: 5,
      socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 },
      reconnectTries: 3000
    };

    options.replset = {
      auto_reconnect: true,
      poolSize: 5,
      socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 },
      reconnectTries: 3000
    };

    var db = mongoose.createConnection(uri, options);

    mongoose.connection.on('error', function(err) {
      console.log('MONGODB ERROR MONGOOSE LEVEL ' + server, err);
    });

    db.on('connecting', function() {
      console.info('MONGODB ' + server + ' connecting.');
    });

    db.on('error', function(err) {
      console.log('MONGODB ERROR ' + server, err);
    });

    db.on('close', function(err) {
      console.log('MONGODB CLOSE ' + server, err);
    });

    db.on('connected', function() {
      console.info('MONGODB ' + server + ' connected successfully.');
    });

    db.once('open', function callback() {
      console.info('MONGODB ' + server + ' opened successfully.');
    });

    db.on('reconnected', function() {
      console.info('MONGODB ' + server + ' reconnected.');
    });

    db.on('timeout', function() {
      console.info('MONGODB ' + server + ' timeout.');
    });

    db.on('disconnected', function() {
      console.info('MONGODB ' + server + ' disconnected');
    });

Esta es la secuencia de eventos que obtengo:

pid:3429 MONGODB geo_uri connected successfully.
pid:3429 MONGODB geo_uri opened successfully.
pid:3429 MONGODB dashboards_db connected successfully.
pid:3429 MONGODB dashboards_db opened successfully.
pid:3429 MONGODB tweet_analytics_db connected successfully.
pid:3429 MONGODB tweet_analytics_db opened successfully.
pid:3429 MONGODB fullcontact_enrichment_db disconnected
pid:3429 MONGODB ERROR fullcontact_enrichment_db { [MongoError: no valid replicaset members found]
  name: 'MongoError',
  message: 'no valid replicaset members found' }
pid:3429 MONGODB uri connected successfully.
pid:3429 MONGODB uri opened successfully.
pid:3429 MONGODB sync_reports_db connected successfully.
pid:3429 MONGODB sync_reports_db opened successfully.
pid:3429 MONGODB uri disconnected
pid:3429 MONGODB CLOSE uri

Entonces ninguna de las bases de datos desconectadas se vuelve a conectar. Debido a la naturaleza aleatoria del problema, no podré proporcionar un código para reproducirlo. Sospecho de algo saturado a nivel de node.js más o menos. Independientemente de la causa de la desconexión, ¿hay algo que pueda hacer para intentar volver a conectarme?

Comentario más útil

@Koslun, la bifurcación debería ser innecesaria ahora. La solución consiste básicamente en establecer socketTimeout en 0 para la base de datos socketOptions ahora.

Así es como se ven mis opciones de enchufe ahora.

    var opts = {
      server: {
        socketOptions: {
          keepAlive: 1,
          socketTimeout: 0
        }
      },
      replSet: {
        socketOptions: {
          keepAlive: 1,
          socketTimeout: 0
        }
    }

Todos 47 comentarios

+1, tuvo 2 cortes en los últimos 5 días relacionados con este problema. Mi solución actual es hacer que mi proceso se bloquee explícitamente ( process.exit(0) ) cuando se emite el evento disconnected . Luego, el proceso se reinicia y la conexión se abre correctamente nuevamente.

Supongo que la mangosta intenta volver a conectarse, pero falla dentro del intervalo reconnectTries * reconnectInterval , y el evento error no se emite debido a esta regresión (https://github.com/Automattic/mongoose/pull / 4653). Lo que no sé es por qué la mangosta / mongo se desconectan aleatoriamente, no tenía este comportamiento antes.
¿Qué hosting mongo estás ejecutando? mLab?

Lo alojamos nosotros mismos en AWS. Desafortunadamente, process.exit(0) no es una opción para nosotros.

Apliqué los cambios en # 4653 y obtuve el mismo comportamiento. Desconexión después de un par de horas:

2016-10-27T11:26:42 pid:5276 MONGODB sync_reports_db connected successfully.
2016-10-27T11:26:42 pid:5276 MONGODB sync_reports_db opened successfully.
.... 2 hours later
2016-10-27T13:45:45 pid:5276 MONGODB sync_reports_db disconnected
2016-10-27T13:45:45 pid:5276 MONGODB CLOSE sync_reports_db

¿No se ha emitido ningún evento error ? (debería ser, 30 segundos después del disconnected uno)

No, eche un vistazo al código en la descripción del problema. A menos que esté haciendo algo mal, existe un controlador de eventos para el evento error . De hecho, el proceso aún se está ejecutando y la mangosta no ha desencadenado ningún otro evento.

Hemos tenido los mismos problemas en los últimos días desde 4.6.5 - desconexiones aleatorias que hacen que el proceso del nodo se atasque. Pero ningún evento error . Volver a 4.5.3 funciona.

@loris ¿esto está relacionado con https://github.com/Automattic/mongoose/commit/f7ebee0c992c45cdb27ba7f0675556b980cddaad en 4.6.6 ?

@mck Sí, https://github.com/Automattic/mongoose/commit/f7ebee0c992c45cdb27ba7f0675556b980cddaad corrige el evento error que no se emite cuando falla el mecanismo de reintento de conexión de mongodb. Sin embargo, no tengo idea de por qué están ocurriendo desconexiones aleatorias en primer lugar, ¿alguna idea @ vkarpov15?

fwiw, nos sucedió entre el 40 y el 50% de las veces si intentábamos hacer una operación de guardar / actualizar (escribiendo alrededor de 650 kb)

Sí, realmente no tengo muchas buenas ideas. Puede intentar llamar a close() en la conexión y luego volver a llamar a connect() usted mismo. @loris , ¿tiene una experiencia similar en la que un guardado / actualización pesado parece causar esto?

Nosotros también nos enfrentamos a esto. En uno de nuestros servicios, recibimos un evento de error (la conexión N a ds0XXXXX-a0.mongolab.com:XXXXX agotó el tiempo de espera), seguido de un evento desconectado. Y la conexión nunca se restablece. En otro servicio, obtenemos un evento desconectado después de una gran solicitud en la base de datos, que está eliminando registros de 2M. Y luego no puede volver a conectarse (mangosta 4.6.6, DB versión 3.0.12).

Nos acaba de pasar de nuevo, hace unos minutos, ejecutando mongodb en mLab también (aunque no estoy seguro de que esté relacionado). Ejecutamos una consulta pesada, se agotó el tiempo de espera ( unhandledRejection { MongoError: connection 0 to ds****-a0.mongolab.com:**** timed out } , el evento disconnected se emitió correctamente, pero nada después, no error , no reconnected etc, por lo tanto, este servidor web siguió ejecutándose y recibiendo solicitudes HTTP, pero se agotó el tiempo de espera hasta que lo reiniciamos porque seguía ejecutando consultas mongoose que se almacenaron en búfer y nunca regresaron.

Nuestra configuración de mangosta (4.6.5 en el nodo 7.0.0):

const mongoConnectOpts = { reconnectTries: 10, reconnectInterval: 500, socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } };
mongoose.connect(process.env.MONGODB_URI, { server: mongoConnectOpts, replset: mongoConnectOpts });
mongoose.connection.on('error', err => {
  console.log({ event: 'mongoose:error', ...err });
  process.exit(0);
});
mongoose.connection.on('connected', () => console.log({ event: 'mongoose:connected' }));
mongoose.connection.on('disconnected', () => console.log({ event: 'mongoose:disconnected' }));
mongoose.connection.on('reconnected', () => console.log({ event: 'mongoose:reconnected' }));

La solución temporal sería process.exit(0) también en el evento disconnected para forzar al servidor web a reiniciarse y configurar una nueva conexión mongodb. ¿Algunas ideas?

Sí, he oído hablar de este tipo de cosas que suceden con mlab antes. TBH, en este caso, simplemente bloquearía el servidor y reiniciaría, las redes irregulares realmente lentas tienden a causar problemas al controlador mongodb y me imagino que depurar esto implicaría coordinar con mlab.

No estoy seguro de qué está mal ahora (mangosta, controlador mongo, mlab o heroku), pero durante los últimos días, ejecutar una solicitud web que ejecuta una consulta de mangosta pesada (que tarda más de 30 segundos en responder) activará una solicitud de heroku tiempo de espera (este es un mecanismo en heroku que agota el tiempo de espera de cualquier solicitud web que demore más de 30 segundos). Una vez que se agote el tiempo de espera de la solicitud web, también se agotará el tiempo de espera de cualquier solicitud web siguiente en ese servidor que requiera una consulta de mangosta. El problema real es que la mangosta activa el evento CERO (no error , close , disconnected , etc.), por lo que no tenemos forma de detectar el desconexión y reinicie el servidor. Así es como configuramos la mangosta:

mongoose.Promise = global.Promise;
mongoose.set('debug', process.env.NODE_ENV === 'development');
const mongoConnectOpts = { reconnectTries: 10, reconnectInterval: 500, socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } };
mongoose.connect(process.env.MONGODB_URI, { server: mongoConnectOpts, replset: mongoConnectOpts });
mongoose.connection.on('error', err => {
  logfmt.log({ event: 'mongoose:error', ...err });
  process.exit(0);
});
mongoose.connection.on('connected', () => logfmt.log({ event: 'mongoose:connected', uri: _.truncate(process.env.MONGODB_URI) }));
mongoose.connection.on('disconnected', () => {
  logfmt.log({ event: 'mongoose:disconnected' });
  process.exit(0);
});
mongoose.connection.on('close', () => logfmt.log({ event: 'mongoose:close' }));
mongoose.connection.on('reconnected', () => logfmt.log({ event: 'mongoose:reconnected' }));

// Setup Redis cache (Default cache TTL: 60 seconds)
cachegoose(mongoose, { engine: 'redis', client: redisCache }, process.env.NODE_ENV === 'development');

@Ioris, ¿puedes ver si esto todavía sucede si deshabilitas el cachegoose?

@ vkarpov15 Intentaremos comprobar esto, pero no es fácil, ya que el error solo ocurre en la producción y no podemos permitirnos ejecutar la producción con la caché desactivada.
@aartiles @ mck- @lushchick ¿

Es posible que esto esté relacionado con https://github.com/christkv/mongodb-core/issues/148. Me he encontrado con un problema similar cuando un miembro de un conjunto de réplicas deja de estar disponible.

No utilizamos el complemento de caché de mangosta.

Todavía lo estoy investigando, lo que puedo decirte hasta ahora:

  • Pude reproducir el problema en mi máquina local: comienzo un ciclo que ejecuta una consulta rápida cada segundo y registro los resultados, un poco más tarde, ejecuto una consulta pesada (como una consulta no indexada en una colección de un millón de filas). Todas las consultas (las rápidas también) se bloquearán / agotarán el tiempo de espera, no se activará ningún evento de mangosta.
  • El problema apareció en 4.6.5 , descendiendo a 4.6.4 soluciona el problema (las consultas rápidas aún se están ejecutando mientras se ejecuta la consulta pesada)
  • Parece que no tiene nada que ver con:

    • el complemento de caché de mangosta

    • ejecutando un conjunto de réplicas o no

Investigué más y el problema vino con la actualización a [email protected] , y la confirmación del error allí es https://github.com/mongodb/node-mongodb-native/pull/1418
parece que arreglaron un error tipográfico, pero algunos departamentos están usando ese nombre de evento (con el error tipográfico)

@loris ¿Sabes dónde están las referencias restantes con el nombre de evento incorrecto? Puedo hacer un PR para arreglarlo, pero no puedo encontrar ninguno.

@jakesjews Tampoco puedo encontrar ninguna referencia, por lo que podría estar equivocado sobre la causa de que haya comprobado versiones que no coinciden en mi máquina, me pondré en contacto con usted.

Tener un problema similar: una falla para volver a conectarse después de una desconexión. Esto se manifiesta en el cliente colgando de cualquier operación de db de mangosta (tiempo de espera a través del almacenamiento en búfer de operaciones).

@jakesjews, mi problema también es exclusivo de los conjuntos de réplicas y no ocurre con una conexión de un solo nodo. Mirando más en el núcleo replset.js.

Se habilitó el registro de depuración dentro de node-mongodb-native para ver si la reconexión de HA funcionaba como se esperaba, parece ser.

attemptReconnect for replset with id successful resuming topologyMonitor 1

A pesar de que el controlador node-mongodb-native afirma que realizó con éxito su intento de Reconexión, Mongoose nunca emitirá un evento de conexión o reconexión como lo hace cuando se reconecta un solo nodo que no es de respuesta.

Como mencionó @loris , process.exit (0) -> reiniciar el servicio funcionaría (en mi caso) ya que el problema está directamente relacionado con la reconexión a un conjunto de réplicas, pero nuevamente no es ideal.

[email protected]
[email protected]

@ mck- Encontré lo mismo que usted, rebajar a 4.5.3 solucionó el problema de reconexión para mi conexión de conjunto de réplicas.

Puedo actualizar todo el camino a 4.5.10 antes de que comience a fallar en 4.6.0 donde ocurre el problema de reconexión del conjunto de réplicas por primera vez. La suposición actual es que podría estar relacionado con la actualización al controlador mongodb 2.2.9.

@loris, ¿ podría proporcionarnos su caso de prueba para que podamos probarlo?

Todavía lo estoy mirando, me equivoqué anteriormente sobre la corrección de errores tipográficos. Parece que el culpable es https://github.com/christkv/mongodb-core/pull/146/commits/09caa9d1e5423acd2f8f154f7b7430028e77e57f
Proporcionar un caso de prueba es un poco complicado ya que solo sucede de esta manera:

  • mangosta 4.6.8 , conectándose a mi localhost mongodb (3.2) con la configuración predeterminada
  • 2 rutas rápidas, una que ejecuta una consulta de mangosta de ejecución prolongada (varios segundos), otra que ejecuta una consulta de mangosta de ejecución rápida (el problema no ocurre cuando se ejecutan las consultas de mangosta directamente en el nodo, con el caso de prueba setInterval / setTimeout, por ejemplo, entonces supongo que está relacionado con cómo se maneja la conexión del grupo)
  • Si ejecuto la ruta rápida de larga duración, luego trato de ejecutar la ejecución rápida, esta última seguirá funcionando sin regresar
  • Configurando poolSize en 50 lugar del predeterminado, solucione el problema
  • Verificando la confirmación anterior de mongodb-core soluciona el problema también (la ruta rápida de ejecución rápida regresa en unos pocos ms mientras se procesa la ruta de ejecución larga) (con el tamaño de grupo predeterminado)
  • Así que supongo que https://github.com/christkv/mongodb-core/pull/146/commits/09caa9d1e5423acd2f8f154f7b7430028e77e57f cambió algo en cómo una mangosta de larga duración puede usar todas las conexiones disponibles en un grupo

Una solución acaba de aterrizar en mongo-core que podría solucionar este problema.

@loris sí, aumentar el tamaño de la piscina ayudará. Parece que se está encontrando con el problema del tren lento en el que el servidor mongodb no puede manejar más de poolSize solicitudes simultáneamente. Aumentar el tamaño de la piscina ayudará, simplemente no lo aumente demasiado, o comenzará a ver problemas de rendimiento con WiredTiger.

Hola,
¿Algún avance en esto? Veo el mismo problema, auto_reconnect no funciona cuando se usa un conjunto de réplicas. Intenté mongoose 4.7.0 con mongodb 2.2.11 y todavía no me reconecto. Estoy usando la versión 3.2.10 de mongod.

Estoy ejecutando todo en un solo host (computadora portátil) con tres instancias de mongod ejecutándose en diferentes puertos con diferentes directorios de bases de datos. No parece que eso deba ser un problema, pero soy nuevo en mongo / mongoose / node / javascript. Mi aplicación de nodo con mangosta también se ejecuta en el mismo host.

Puedo reproducir esto simplemente cerrando todos los procesos de mongod
(launchctl detener mongod01; launchctl detener mongod02; launchctl detener mongod03)
espere el mensaje de conexión cerrada y luego reinicie (reemplace "detener" con "inicio" en los comandos launchctl). Mi aplicación nunca se vuelve a conectar a mongo.

Si hago la misma prueba con una sola instancia de mongod no configurada como un conjunto de réplicas, mongoose se vuelve a conectar bien.

Me complace proporcionar registros o probar parches si eso es útil.

Después de investigar un poco, creo que podría haber encontrado una fuente del problema. Parece que cuando la reconexión automática es verdadera, no se supone que el búfer de conexión se active https://github.com/Automattic/mongoose/blob/master/lib/drivers/node-mongodb-native/connection.js#L153 en la conexión cerrar eventos. Sin embargo, no se establece más propiedad de autoReconnect dentro de la clase replset en mongodb-native https://github.com/mongodb/node-mongodb-native/blob/2.2/lib/replset.js, por lo que cualquier evento cercano de uno de los nodos hace que el búfer se habilite permanentemente. Tuve suerte con la confirmación https://github.com/eflexsystems/mongoose/commit/5ac12727f34b41791f94643b66c8cc88aff4d66a pero quiero darle más tiempo para ver si causó otros problemas antes de hacer una solicitud de extracción.

@joeldodson está describiendo el mismo problema que experimenté. Solo unas versiones de heads-up> = 4.6.0 parecen contener el problema. Mientras tanto, probaría 4.5.10, se ha vuelto a conectar a un conjunto de respuestas y una conexión única bien para mí.

Gracias @jakesjews y @ kog13

Probé 4.5.10 y la mangosta se vuelve a conectar después de reiniciar el conjunto de réplicas. Sin embargo, db.readyState no parece borrarse después de que se detuvieran todas las instancias del conjunto de réplicas. Lo estamos verificando para determinar si rechazamos alguna solicitud (para que no hagan cola esperando a que la aplicación se vuelva a conectar a la base de datos). Además, no recibí las notificaciones de desconexión o conexión cerrada con 4.5.10.

Ya tengo una lógica que se encuentra en un bucle con un temporizador de 5 segundos para intentar conectarme si la base de datos no está disponible cuando se inicia la aplicación. Hemos intentado llamar a eso en el controlador db.on ('cerrado', function () {...}) y parece funcionar bien. Sin embargo, mi preocupación es si intentar conectar explícitamente tendrá algún conflicto con alguna lógica de reconexión bajo el capó. Dado que la reconexión no parece estar sucediendo para los conjuntos de réplicas, creo que está bien. También establecemos auto_reconnect en falso en las opciones de conexión tanto para el servidor como para el replset.

@jakesjews : probé el parche que mencionaste anteriormente pero aún no

Me complace probar más parches para auto_reconnect si alguien tiene alguno. Seguiré investigando también.

Gracias.

@joeldodson, además del parche anterior, también deberá depender de la última versión de mongo-core, que tiene correcciones para asegurarse de que la conexión del monitor del conjunto de réplicas permanezca activa. Si prueba mi tenedor, ya debería tenerlo.

Creo que estoy en un lugar bastante bueno con respecto a los tiempos de espera y la conmutación por error ahora con mangosta. Si alguien más quiere probarlo, querrá usar mi bifurcación de mangosta además de establecer socketTimeout en 0 en socketOptions.

La razón para configurar socketTimeout en 0 es que hay un error en mongo-core por el que todavía necesito presentar un problema. El problema es causado por el grupo de conexiones que se contrae / expande dinámicamente. La forma en que funciona el grupo es que cada vez que agrega una nueva conexión, esa conexión se cerrará después de 30 segundos de inactividad. Los eventos de tiempo de espera desencadenan la eliminación del grupo y también ejecutan una comprobación que compara el número de tiempos de espera con un límite de 30 intentos de conexión. Hay un latido que se ejecuta cada 2 segundos y borra el número de tiempos de espera, pero si se ponen en cola 30 o más solicitudes en paralelo, se agotará el tiempo de espera entre el latido y se destruirá el grupo de conexiones. Por ahora, establecer el tiempo de espera de las conexiones en 0 evita que las conexiones se eliminen en el grupo si están inactivas y evita el problema. Si desea replicar el problema, intente establecer un tamaño de grupo de conexiones en alrededor de 50 y ejecutar 50 consultas en paralelo. Después de que eso suceda, la piscina se destruirá en unos 30 segundos. Tenga en cuenta que el tiempo de espera no afecta la comprobación de los latidos del conjunto de réplicas, ya que tiene su propio tiempo de espera.

He estado realmente abrumado por el trabajo recientemente, así que no he tenido la oportunidad de recopilar todos estos cambios juntos, pero espero hacerlo pronto.

Gracias de nuevo @jakesjews. Saqué tus repositorios mongoose y mongodb-core. La reconexión funcionó. Sin embargo, no obtuve los eventos 'conectado' y 'reconectado' que obtengo cuando uso una sola instancia de Mongo. Además, el readyState no parece reiniciarse, sigue siendo 0 incluso después de la reconexión.

Me complace ayudar con las pruebas o la recopilación de registros.

Sigo teniendo el problema con [email protected]

¿Algo nuevo con respecto a este asunto?

Experimentando los problemas también aquí. Tuve que revertir la actualización de la versión de mangosta debido a problemas de conexión. Una consulta que tarda unos segundos actualmente agota nuestra conexión, donde antes no era el caso.

Este problema debe resolverse; de ​​lo contrario, el paquete no se podrá utilizar.
Probablemente probaré la solución

Si el problema es un error con mongo-core, esto no es realmente un problema con mangosta. Si tiene el problema con la versión más reciente de mongoose, ¿puede presentar un problema en el repositorio mongodb-core ?

En realidad, es un problema con mongoose ya que se ha actualizado para depender de la versión de mongodb-core tenga un problema. Quizás mongoose debería restaurarse a una versión anterior de mongodb-core .

@jakesjews Al ver que [email protected] depende de [email protected] , que a su vez depende de [email protected] , aplicar las correcciones de su bifurcación sería todo lo que se necesita para solucionar estos problemas aparentemente sin efectos secundarios?

Y mirando su bifurcación, ¿ esta confirmación es ahora el único cambio que es necesario para un PR 4.7.xy / o 4.8.x?

@Koslun, la bifurcación debería ser innecesaria ahora. La solución consiste básicamente en establecer socketTimeout en 0 para la base de datos socketOptions ahora.

Así es como se ven mis opciones de enchufe ahora.

    var opts = {
      server: {
        socketOptions: {
          keepAlive: 1,
          socketTimeout: 0
        }
      },
      replSet: {
        socketOptions: {
          keepAlive: 1,
          socketTimeout: 0
        }
    }

@jakesjews Ok, gracias por la rápida aclaración :).

¿Sabes en qué versión de mongodb-core veremos una solución a este error? O, alternativamente, ¿tiene un problema, relaciones públicas o compromiso que podamos rastrear?

¿Alguna actualización sobre el comentario de @Koslun ?

¿Alguna actualización para este problema?

El problema sigue abierto desde 2016: open_mouth:

Me pregunto si este problema aún puede ocurrir con mongoose 5.x con el controlador mongodb 3.3.4 y el servidor MongoDB en la versión 4.x. :pensando:

¿Alguien sabe si el reconectTries se restablece cuando la reconexión es exitosa?

Instancia de Fox, si recnectTries está configurado en 30, y una vez desconectado, mangosta lo intenta 5 veces y la conexión es exitosa.
La próxima vez que se pierda la conexión, ¿cuál será el contador de reintentos?
¿Intentará reconectarse 30 veces?
¿O 25 veces?

@ szabolcs-szilagyi sí, pero solo si no establece useUnifiedTopology en true .

@ bhaveshvyas007 sí lo hace. Aquí está el código relevante

Para la posteridad:

Si está ejecutando Mongoose 5.x sin useUnifiedTopology , lea esta guía para administrar las conexiones de MongoDB .

Si está ejecutando Mongoose 5.x con useUnifiedTopology , este problema no le afecta.

¿Fue útil esta página
0 / 5 - 0 calificaciones