Mongoose: Не подключайтесь повторно после отключения

Созданный на 26 окт. 2016  ·  47Комментарии  ·  Источник: Automattic/mongoose

После обновления с 4.4.11 до> = 4.6.1 мы получаем случайные отключения, и мангуст никогда не подключается повторно.

версия мангуста: 4.6.5
версия mongodb: 3.2.9

Вот как я создаю соединения:

    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');
    });

Вот последовательность событий, которые я получаю:

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

После этого ни одна из отключенных баз данных не подключится повторно. Из-за случайного характера проблемы я не смогу предоставить код для ее воспроизведения. Я подозреваю что-то насыщенное на уровне node.js или около того. Независимо от причины отключения, могу ли я что-нибудь сделать, чтобы попытаться восстановить подключение?

Самый полезный комментарий

@Koslun, вилка теперь не нужна. Исправление в значительной степени заключается в установке socketTimeout в 0 для socketOptions базы данных.

Вот как теперь выглядят мои варианты сокетов.

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

Все 47 Комментарий

+1, за последние 5 дней было 2 отключения, связанных с этой проблемой. Мой текущий обходной путь - вызвать явный сбой моего процесса ( process.exit(0) ) при возникновении события disconnected . Затем процесс перезапускается, и соединение снова открывается правильно.

Я предполагаю, что мангуст пытается повторно подключиться, но терпит неудачу в течение интервала reconnectTries * reconnectInterval , а событие error не генерируется из-за этой регрессии (https://github.com/Automattic/mongoose/pull / 4653). Чего я не знаю, так это того, почему мангусты / монго случайно отключаются, у меня такого поведения раньше не было.
Какой у вас mongo-хостинг? млаб?

Мы сами размещаем его в AWS. К сожалению, process.exit(0) для нас не вариант.

Я применил изменения в # 4653 и получил такое же поведение. Отключение через пару часов:

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

Нет события error ? (должно быть через 30 секунд после disconnected one)

Нет, посмотрите код в описании проблемы. Если я не делаю что-то не так, есть обработчик для события error . Фактически, процесс все еще выполняется, и мангуст не вызвал никаких других событий.

У нас были те же проблемы в последние несколько дней с момента 4.6.5 - случайных отключений, из-за которых процесс узла зависает. Но нет события error . Возврат к 4.5.3 работает.

@loris это связано с https://github.com/Automattic/mongoose/commit/f7ebee0c992c45cdb27ba7f0675556b980cddaad в 4.6.6 ?

@mck Да, https://github.com/Automattic/mongoose/commit/f7ebee0c992c45cdb27ba7f0675556b980cddaad исправляет событие error которое не генерируется при сбое механизма повторной попытки подключения mongodb. Однако я понятия не имею, почему вообще случаются случайные отключения, любая идея @ vkarpov15?

fwiw, у нас это происходило в 40-50% случаев, если мы пытались выполнить операцию сохранения / обновления (пишет около 650 КБ)

Да, у меня действительно не так много хороших идей. Вы можете попробовать позвонить close() в соединении, а затем снова позвонить connect() самому себе. @loris есть ли у вас подобный опыт, когда это, кажется, вызывает тяжелое сохранение / обновление?

Мы тоже с этим сталкиваемся. В одной из наших служб мы получаем событие об ошибке (соединение N с ds0XXXXX-a0.mongolab.com:XXXXX истекло), за которым следует событие отключения. И связь никогда не восстанавливается. В другом сервисе мы получаем событие отключения после тяжелого запроса к БД, который удаляет 2M записей. И затем не удается повторно подключиться (мангуст 4.6.6, версия БД 3.0.12).

Это случилось с нами снова, несколько минут назад, когда мы запускали mongodb и на mLab (не уверен, что это связано с этим). Мы выполнили тяжелый запрос, время ожидания истекло ( unhandledRejection { MongoError: connection 0 to ds****-a0.mongolab.com:**** timed out } , событие disconnected было правильно сгенерировано, но ничего после, ни error , ни reconnected т. Д., таким образом, этот веб-сервер продолжал работать и получать HTTP-запросы, но все они истекли, пока мы не перезапустили его, потому что он продолжал выполнять запросы мангуста, которые буферизовались и никогда не возвращались.

Наша установка мангуста (4.6.5 на узле 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' }));

Временным обходным решением будет process.exit(0) также в событии disconnected чтобы принудительно перезапустить веб-сервер и установить новое соединение mongodb. Любые идеи?

Да, я слышал о подобных вещах, происходящих с mlab раньше. В этом случае я бы просто вывалил сервер из строя и перезапустил его, очень медленная, нечеткая сеть имеет тенденцию вызывать проблемы для драйвера mongodb, и я предполагаю, что отладка этого требует координации с mlab.

Я не уверен, что сейчас не так (mongoose, драйвер mongo, mlab или heroku), но в последние несколько дней запуск веб-запроса, который выполняет тяжелый запрос mongoose (для ответа требуется более 30 секунд), вызовет запрос heroku тайм-аут (это механизм в heroku, который тайм-аут любого веб-запроса занимает более 30 секунд). По истечении времени ожидания этого веб-запроса любой следующий веб-запрос на этом сервере, для которого требуется запрос мангуста, также будет отключен. Настоящая проблема заключается в том, что событие ZERO запускается мангустом (нет error , close , disconnected и т. Д.), Поэтому у нас нет возможности обнаружить отключение и перезапуск сервера. Вот как мы настраиваем мангуста:

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, можете ли вы увидеть, происходит ли это по-прежнему, если вы отключите cachegoose?

@ vkarpov15 Попробую проверить это, но это непросто, поскольку ошибка возникает только в производстве, и мы не можем позволить себе запускать производство с отключенным кешем.
@aartiles @ mck- @lushchick , ребята, вы пользуетесь плагином кеширования мангуста?

Возможно, это может быть связано с https://github.com/christkv/mongodb-core/issues/148. Я столкнулся с аналогичной проблемой, когда член набора реплик стал недоступен.

Мы не используем плагин кеширования мангуста.

Я все еще изучаю это, что я могу вам сказать:

  • Мне удалось воспроизвести проблему на моем локальном компьютере: я запускаю цикл, выполняя быстрый запрос каждую секунду и регистрирую результаты, с некоторой задержкой позже, я запускаю тяжелый запрос (например, неиндексированный запрос для коллекции из миллиона строк). Все запросы (также быстрые) будут заблокированы / истечет время ожидания, событие мангуста не будет запущено.
  • Проблема появилась в 4.6.5 , переход на 4.6.4 устраняет проблему (быстрые запросы все еще выполняются, пока выполняется тяжелый запрос)
  • Похоже, это не причем:

    • плагин кеширования мангуста

    • запущен набор реплик или нет

Я покопался еще раз, и проблема возникла с обновлением до [email protected] , а ошибочная фиксация есть https://github.com/mongodb/node-mongodb-native/pull/1418
похоже, что они исправили опечатку, но это eventName (с опечаткой) используется некоторыми отделами

@loris Вы знаете, где находятся оставшиеся ссылки с неправильным названием события? Я могу сделать пиар, чтобы исправить это, но я не могу его найти.

@jakesjews Не могу найти никаких ссылок, так что я могу ошибаться насчет причины, по которой я мог проверить несоответствующие версии на своей машине, я вернусь к вам

Аналогичная проблема: невозможность повторного подключения после отключения. Это проявляется в клиенте, зависая при любой операции mongoose db (тайм-аут через буферизацию операции).

@jakesjews Моя проблема также уникальна для наборов реплик и не возникает при подключении к одному узлу. Подробнее о ядре replset.js.

Включено ведение журнала отладки в node-mongodb-native, чтобы увидеть, работает ли повторное подключение высокой доступности, как ожидалось, похоже.

attemptReconnect for replset with id successful resuming topologyMonitor 1

Несмотря на то, что драйвер node-mongodb-native утверждает, что он успешно выполнил попытку Reconnect, mongoose никогда не будет генерировать событие подключения или повторного подключения, как это происходит при повторном подключении одного узла без повторного подключения.

Как упоминалось в @loris , process.exit (0) -> перезапуск службы будет работать (в моем случае), поскольку проблема напрямую связана с повторным подключением к набору реплик, но опять же не идеально.

[email protected]
[email protected]

@ mck - обнаружил то же самое, что и вы, при переходе на версию 4.5.3 была устранена проблема повторного подключения для моего подключения к набору реплик.

Я могу полностью обновиться до 4.5.10, прежде чем он начнет давать сбой в 4.6.0, где проблема повторного подключения набора реплик возникает впервые. Текущее предположение, что это могло быть связано с обновлением драйвера mongodb 2.2.9.

@loris не могли бы вы предоставить свой тестовый пример, чтобы мы могли его попробовать?

Я все еще смотрю на это, раньше я ошибался насчет фиксации исправления опечатки. Похоже, виноват https://github.com/christkv/mongodb-core/pull/146/commit/09caa9d1e5423acd2f8f154f7b7430028e77e57f
Предоставить тестовый пример немного сложно, так как это происходит только так:

  • mongoose 4.6.8 , подключение к моему localhost mongodb (3.2) с настройками по умолчанию
  • 2 экспресс-маршрута, один из которых выполняет длительный запрос мангуста (несколько секунд), другой - быстрый запрос мангуста (проблема не возникает при выполнении запросов мангуста непосредственно в узле, например, с тестовым примером setInterval / setTimeout, так что я предполагаю, что это связано с тем, как обрабатывается соединение с пулом)
  • Если я пройду длительный экспресс-маршрут, а затем попытаюсь попасть на быстрый бег, последний продолжит бежать, не возвращаясь
  • Установка poolSize на 50 вместо значения по умолчанию, устраните проблему.
  • Проверка предыдущей фиксации из mongodb-core устраняет проблему (быстрый экспресс-маршрут возвращается через несколько мс, пока обрабатывается длительный маршрут) (с размером пула по умолчанию)
  • Итак, я думаю, https://github.com/christkv/mongodb-core/pull/146/commit/09caa9d1e5423acd2f8f154f7b7430028e77e57f что-то изменил в том, как один долго работающий мангуст может использовать каждое доступное соединение в пуле.

Исправить только что приземлился в Монго-ядро , которое могло бы решить эту проблему.

@loris да, увеличение размера пула поможет. Похоже, вы столкнулись с проблемой медленного поезда, когда сервер mongodb не может одновременно обрабатывать более poolSize запросов. Увеличение размера пула поможет, просто не увеличивайте его слишком сильно, иначе вы начнете видеть проблемы с производительностью с WiredTiger.

Привет,
какие-нибудь обновления по этому поводу? У меня та же проблема, auto_reconnect не работает при использовании набора реплик. Я только что попробовал mongoose 4.7.0 с mongodb 2.2.11 и все еще не подключаюсь. Я использую mongod версии 3.2.10.

Я запускаю все на одном хосте (ноутбуке) с тремя экземплярами mongod, работающими на разных портах с разными каталогами баз данных. Не похоже, что это должно быть проблемой, но я новичок в mongo / mongoose / node / javascript. Мое приложение узла с мангустом также работает на том же хосте.

Я могу воспроизвести это, просто отключив все процессы mongod
(launchctl stop mongod01; launchctl stop mongod02; launchctl stop mongod03)
дождитесь сообщения о закрытии соединения, затем перезапустите (замените "stop" на "start" в командах launchctl). Мое приложение никогда не подключается к монго.

Если я провожу тот же тест с одним экземпляром mongod, не настроенным как набор реплик, mongoose повторно подключается нормально.

рад предоставить журналы или попробовать исправления, если это полезно.

Покопавшись, я думаю, что нашел один источник проблемы. Похоже, что когда autoreconnect истинно, буфер подключения не должен становиться активным https://github.com/Automattic/mongoose/blob/master/lib/drivers/node-mongodb-native/connection.js#L153 при подключении закрыть события. Однако больше нет свойства autoReconnect, установленного внутри класса replset в mongodb-native https://github.com/mongodb/node-mongodb-native/blob/2.2/lib/replset.js, поэтому любое событие закрытия с одного узла заставляет буфер становиться постоянно включенным. Мне немного повезло с фиксацией https://github.com/eflexsystems/mongoose/commit/5ac12727f34b41791f94643b66c8cc88aff4d66a, но я хочу дать ему еще немного времени, чтобы увидеть, вызвало ли это какие-либо другие проблемы, прежде чем я сделаю запрос на перенос.

@joeldodson, вы описываете ту же проблему, что и я. Похоже, что проблема в одном из выпусков> = 4.6.0. Тем временем я бы попробовал 4.5.10, он переподключался к реплицирующему набору, и одно соединение меня устраивало.

Спасибо @jakesjews и @ kog13

Я попробовал 4.5.10, и мангуст снова подключается после перезапуска набора реплик. Однако db.readyState, похоже, не очищается после остановки всех экземпляров в наборе реплик. Мы проверяем это, чтобы определить, отклонять ли какие-либо запросы (чтобы они не стояли в очереди, ожидая повторного подключения приложения к БД). Кроме того, я не получал уведомления об отключении или закрытии соединения с 4.5.10.

У меня уже есть логика, которая находится в цикле с 5-секундным таймером, чтобы попытаться подключиться, если БД недоступна при запуске приложения. Мы пробовали вызвать это в обработчике db.on ('closed', function () {...}), и, похоже, он работает нормально. Меня беспокоит, однако, что явная попытка подключения будет иметь какие-либо конфликты с какой-либо логикой повторного подключения под капотом. Поскольку повторного подключения для наборов реплик не происходит, я думаю, что это нормально. Также мы устанавливаем auto_reconnect в false в параметрах подключения как для сервера, так и для набора реплик.

@jakesjews - Я попробовал патч, который вы упомянули выше, но так и не смог восстановить соединение. Возможно, я что-то пропустил, но похоже, что этот патч был больше связан с обеспечением генерации события закрытия и обновления readyState.

Рад попробовать еще патчи для auto_reconnect, если они есть. Я тоже буду копаться.

Благодарю.

@joeldodson в дополнение к вышеупомянутому

Я думаю, что сейчас я нахожусь в довольно хорошем месте в отношении таймаутов и аварийного переключения с мангустом. Если кто-то еще захочет попробовать это, вы захотите использовать мою вилку mongoose в дополнение к установке socketTimeout на 0 в socketOptions.

Причина установки socketTimeout в 0 заключается в том, что в mongo-core есть ошибка, о которой мне все еще нужно сообщить. Проблема вызвана динамически сжимающимся / расширяющимся пулом соединений. Пул работает так, что каждый раз, когда он добавляет новое соединение, оно закрывается через 30 секунд бездействия. События тайм-аута запускают удаление из пула, а также запускают проверку, сравнивающую количество тайм-аутов с ограничением в 30 попыток подключения. Существует контрольный сигнал, который запускается каждые 2 секунды и очищает количество тайм-аутов, но если 30 или более запросов ставятся в очередь параллельно, это приведет к тому, что все они будут истекать по таймауту между контрольным сигналом и уничтожить пул соединений. На данный момент установка тайм-аута для соединений на 0 предотвращает удаление соединений обратно в пул, если они неактивны, и позволяет избежать проблемы. Если вы хотите воспроизвести проблему, попробуйте установить размер пула соединений примерно на 50 и выполнить 50 параллельных запросов. После этого пул будет уничтожен примерно через 30 секунд. Обратите внимание, что тайм-аут не влияет на контрольное сообщение, проверяющее набор реплик, поскольку у него есть собственный тайм-аут.

В последнее время я был действительно завален работой, поэтому у меня не было возможности собрать все эти изменения вместе, но я надеюсь, что скоро доберусь до них.

Еще раз спасибо @jakesjews. Я вытащил ваши репозитории mongoose и mongodb-core. Повторное подключение сработало. У меня не было событий «подключено» и «повторно подключено», хотя они возникают при использовании одного экземпляра Mongo. Кроме того, похоже, что readyState не сбрасывается, он по-прежнему равен 0 даже после повторного подключения.

Рад помочь с тестированием или сбором логов.

Проблема с [email protected]

Что-нибудь новенькое по этому поводу?

Здесь тоже есть проблемы. Пришлось отменить обновление версии мангуста из-за проблем с подключением. Запрос, занимающий несколько секунд, в настоящее время прерывает наше соединение, чего раньше не было.

Эта проблема должна быть решена, иначе пакет не будет использоваться.
Возможно, попробую решение @jakesjews, когда у меня будет время. А пока использую 4.4.X

Если проблема связана с ошибкой mongo-core, то на самом деле это не проблема mongoose. Если у вас возникла проблема с самой последней версией mongoose, можете ли вы сообщить о проблеме в репозитории mongodb-core ?

На самом деле это проблема с mongoose поскольку она была обновлена, чтобы зависеть от версии mongodb-core , в которой возникла проблема. Возможно, mongoose следует восстановить до предыдущей версии mongodb-core .

@jakesjews Видя, что [email protected] зависит от [email protected] , который, в свою очередь, зависит от [email protected] , применение исправлений из вашей вилки - это все, что требуется для устранения этих проблем. казалось бы, без побочных эффектов?

А если посмотреть на ваш форк, то теперь

@Koslun, вилка теперь не нужна. Исправление в значительной степени заключается в установке socketTimeout в 0 для socketOptions базы данных.

Вот как теперь выглядят мои варианты сокетов.

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

@jakesjews Хорошо, спасибо за быстрое разъяснение :).

Вы знаете, в какой версии mongodb-core мы увидим исправление этой ошибки? Или есть проблема, PR или коммит, который мы можем отследить?

Есть обновления относительно комментария @Koslun ?

Есть обновления по этой проблеме?

Проблема все еще открыта с 2016 года: open_mouth:

Мне интересно, может ли эта проблема возникнуть с mongoose 5.x с драйвером mongodb 3.3.4 и сервером MongoDB в версии 4.x? : мышление:

Кто-нибудь знает, если повторное подключение сбрасывается при успешном повторном подключении.

Экземпляр Fox, если для reconnectTries установлено значение 30, и после отключения mongoose пытается 5 раз, и соединение успешно.
В следующий раз, когда соединение будет потеряно, каков будет счетчик повторных попыток?
Будет ли он 30 раз пытаться переподключиться?
Или 25 раз?

@ szabolcs-szilagyi да, но только если вы не установите useUnifiedTopology на true .

@ bhaveshvyas007 да, это так. Вот соответствующий код

Для потомков:

Если вы используете Mongoose 5.x без useUnifiedTopology , прочтите это руководство по управлению соединениями MongoDB .

Если вы используете Mongoose 5.x с useUnifiedTopology , эта проблема вас не коснется.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги