mongoError:トポロジが破壊されました


163

RestifyとMongooseを使用してnode.jsに組み込まれたRESTサービスと、約30.000の通常サイズのドキュメントを含むコレクションを備えたmongoDBがあります。ノードサービスをpmxとpm2で実行しています。

昨日、突然、ノードは「MongoError:Topology was destroyed」というメッセージでエラーを回避し始め、それ以上は何も起こりませんでした。これが何を意味し、何がこれを引き起こしたのかはわかりません。これをgoogle-searchしても、それほど多くは見つかりません。だから私はここで尋ねようと思いました。

本日ノードサービスを再起動した後、エラーの発生は停止しました。これらの1つも本番環境で実行されており、そこで実行されているセットアップのかなり重要な部分でいつでも発生する可能性があることを怖がっています...

上記のパッケージの次のバージョンを使用しています。

  • マングース:4.0.3
  • 再確認:3.0.3
  • ノード:0.10.25

2
mongodbドライバーのみを使用して同様の問題が発生しています:(
0x8890

1
私は帆を使用していないので、いいえ、それは私の問題を解決するとは思いません
dreagan '27 / 07/27

回答:


98

これは、MongoDBインスタンスへの書き込みを試みている間に、ノードサーバーからMongoDBインスタンスへの接続が中断されたことを意味します。

そのエラーを生成するMongoソースコードをてください。

Mongos.prototype.insert = function(ns, ops, options, callback) {
    if(typeof options == 'function') callback = options, options = {};
    if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
    // Topology is not connected, save the call in the provided store to be
    // Executed at some point when the handler deems it's reconnected
    if(!this.isConnected() && this.s.disconnectHandler != null) {
      callback = bindToCurrentDomain(callback);
      return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
    }

    executeWriteOperation(this.s, 'insert', ns, ops, options, callback);
}

クラッシュや「修正」を促進するためのアップグレードがインストールされていないため、これはコメントで引用されているSailsの問題とは関係がないようです。


2
私は同じ問題を抱えており、それはほぼ毎週起こり、mongoで動作するアプリケーションをシャットダウンします。これは私が生成した問題ですか、これはmongooseの問題ですか?
Mohammad Ganji

@MohammadGanji:クライアントコードをデバッグしていて、ステートメントをステップオーバーするのに十分な速度ではないときに、Mongooseなしでこのエラーが発生します。原因は不明ですが、mongoクエリの直後にブレークポイントを設定すると回避できます。
Dan Dascalescu 2018

@DanDascalescu私の問題が解決したことを言及するのを忘れていました。それはロギングの問題でした。ログにいくつかの警告があり、しばらくするとストレージがギガバイトになり、mongoプロセスがシャットダウンしたため、圧縮とバックアップを試みました。問題は解決
Mohammad Ganji

83

Jasonの回答が受け入れられたことは知っていますが、Mongooseでも同じ問題があり、Mongodbの接続を本番環境で維持するために、データベースをホストしいるサービスが次の設定を適用することを推奨していることがわかりました。

var options = {
  server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
  replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
};
mongoose.connect(secrets.db, options);

この返信が「トポロジが破棄されました」エラーを抱えている他の人々の助けになることを願っています。


4
これで問題が解決しませんでした。実際には、keepAliveを30000に増やしましたが、これは非常に役立ちました。それでも時折発生するトポロジエラーは発生しますが、
ifightcrime

9
バージョン3.4.2のMongoドライバーを使用する場合、これらのオプションは最上位にある必要があります:オプション:{keepAlive:1、connectTimeoutMS:30000、reconnectTries:30、reconnectInterval:5000}
Sebastien H.

クライアントコードをデバッグしていて、ステートメントをステップオーバーする速度が十分でないため、Mongooseなしでこのエラーが発生しました。原因は不明ですが、mongoクエリの直後にブレークポイントを設定すると回避できます。
Dan Dascalescu 2018

76

このエラーは、何らかの理由でサーバーがダウンしているなどの理由でmongoドライバーが接続をドロップしたことが原因です。

デフォルトでは、mongooseは30秒間再接続を試み、再試行を停止し、再起動するまでエラーを永久にスローします。

これは、接続オプションのこれら2つのフィールドを編集することで変更できます

mongoose.connect(uri, 
    { server: { 
        // sets how many times to try reconnecting
        reconnectTries: Number.MAX_VALUE,
        // sets the delay between every retry (milliseconds)
        reconnectInterval: 1000 
        } 
    }
);

接続オプションのドキュメント


3
うん。技術的に受け入れられた回答は、尋ねられた質問に答えますが、これは議論中のシナリオを回避する正しい方法です。
kingdango 2016年

3
バージョン3.4.2のMongoドライバーを使用する場合、これらのオプションは最上位にある必要があります。オプション:{keepAlive:1、connectTimeoutMS:30000、reconnectTries:30、reconnectInterval:2000}
Sebastien H.

1
明確にするために、ノードMongoDBドライバーのドキュメントによると、サーバーはデフォルトで30回再接続を試み、再試行の間隔は1秒です。
Boaz

4
ここで、サーバーオブジェクトの下でこれらのオプションを提供する必要はありません。オプションオブジェクトに直接移動します。
Animesh Singh

3
ちょうどはマングースの最近のバージョンは、トップレベルでそれらのオプションを持っていることを追加したい、追加する必要はありませんのでserver: {など
アレックス・K

17

私の場合、このエラーはdb.close();「async」内の「await」セクションが原因で発生しました

MongoClient.connect(url, {poolSize: 10, reconnectTries: Number.MAX_VALUE, reconnectInterval: 1000}, function(err, db) {
    // Validate the connection to Mongo
    assert.equal(null, err);    
    // Query the SQL table 
    querySQL()
    .then(function (result) {
        console.log('Print results SQL');
        console.log(result);
        if(result.length > 0){

            processArray(db, result)
            .then(function (result) {
                console.log('Res');
                console.log(result);
            })
            .catch(function (err) {
                console.log('Err');
                console.log(err);
            })
        } else {
            console.log('Nothing to show in MySQL');
        }
    })
    .catch(function (err) {
        console.log(err);
    });
    db.close(); // <--------------------------------THIS LINE
});

2
カルロスのケースでは、クローズは他のすべての前に起こったと思います。私の場合も同様でした。DBを閉じた後、DBにアクセスしました。Mongoの開発者がより明示的なエラーメッセージを生成できると便利です。「Topology broken」は内部メモのように聞こえます。
フアンLanus

3
あなたのソリューションは、移動することだったdb.closethen右、ブロック?
AlexChaffee

それは正しいです、私の場合、私はdb.close()行を削除するだけですが、それをthenブロックに移動することは素晴らしい解決策のようです。
カルロスロドリゲス

1
をブロックに移動するdb.closeことはthen、ネイティブのMongoDB Node.jsドライバーでうまく機能しました。
kevinmicke

12

Gaafarの回答にほんの少しの追加をしただけで、非推奨の警告が出されました。次のように、サーバーオブジェクトの代わりに:

MongoClient.connect(MONGO_URL, {
    server: {
        reconnectTries: Number.MAX_VALUE,
        reconnectInterval: 1000
    }
});

最上位のオブジェクトに移動できます。基本的には、サーバーオブジェクトから取り出し、オプションオブジェクトに次のように配置します。

MongoClient.connect(MONGO_URL, {
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 1000
});

7

「トポロジが破壊されました」は、このコメントに従って、mongoドキュメントインデックスが作成される前にmongooseが切断されたことが原因である可能性があります

切断する前にすべてのモデルのインデックスが作成されていることを確認するには、次の方法があります。

await Promise.all(mongoose.modelNames().map(model => mongoose.model(model).ensureIndexes()));

await mongoose.disconnect();

テストケースを実行している場合は、ありがとうございます-これはおそらく非常にありそうな答えです...
Nick H247

1
これで終わりです。ありがとうございました!私はJestでmongodb-memory-serverを使用してテストを実行しており、トポロジで散発的なエラーが発生したり、ハンドルや未完成のPromiseが開いたりしていました。しかし時々それは働いた。インデックスの待機を追加することで修正されました。
roblingle 2018

@roblingleのようなJestコードをデバッグしていて、ステートメントをステップオーバーするのに十分な速度ではないときに、Mongooseなしでこのエラーが発生します。原因は不明ですが、mongoクエリの直後にブレークポイントを設定すると回避できます。
Dan Dascalescu 2018

@roblingleどうやってそれを修正したのですか?この問題に遭遇しただけで、MongoDBに再び接続できなくなりました。私はそれ以来すべてを削除し、MongoDBを(homebrew経由で)再インストールしましたが、起動時にもう実行されなくなりました。(無関係な問題である可能性があります)
bobbyz

無関係に聞こえます。アプリは問題なく動作しましたが、テストが失敗しました。
roblingle 2018年

3

エイドリアンの答えに対するセバスチャンのコメントはもっと注意が必要ですが、それは私を助けましたが、コメントであることはいつか無視されるかもしれないので、ここに解決策があります

var options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 }
mongoose.connect(config.mongoConnectionString, options, (err) => {
    if(err) {
        console.error("Error while connecting", err);
    }
});

2

他にも同じエラーがありました。最後に、コードにエラーがあることがわかりました。2つのnodejsサーバーに負荷分散を使用していますが、1つのサーバーのコードを更新するだけです。

mongodサーバーを変更しfrom standalone to replicationましたが、接続文字列に対応する更新を行うのを忘れたため、このエラーに遭遇しました。

スタンドアロン接続文字列: mongodb://server-1:27017/mydb レプリケーション接続文字列: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

詳細はこちら:[接続文字列のmongoドキュメント]


2

私はこれをkubernetes / minikube + nodejs + mongoose環境で満たしました。問題は、DNSサービスが一種のレイテンシで稼働していたことでした。DNSを確認する準備ができて、私の問題は解決しました。

const dns = require('dns');

var dnsTimer = setInterval(() => {
	dns.lookup('mongo-0.mongo', (err, address, family) => {
		if (err) {
			console.log('DNS LOOKUP ERR', err.code ? err.code : err);
		} else {
			console.log('DNS LOOKUP: %j family: IPv%s', address, family);
			clearTimeout(dnsTimer);
			mongoose.connect(mongoURL, db_options);
		}
	});
}, 3000);


var db = mongoose.connection;
var db_options = {
	autoReconnect:true,

	poolSize: 20,
	socketTimeoutMS: 480000,
	keepAlive: 300000,

	keepAliveInitialDelay : 300000,
	connectTimeoutMS: 30000,
	reconnectTries: Number.MAX_VALUE,
	reconnectInterval: 1000,
	useNewUrlParser: true
};

(db_optionsの数値は、stackoverflowおよび同様のサイトで見られる任意のものです)


2

ここで私がしたことは、それはうまくいきます。以下のオプションを追加した後、問題はなくなりました。

const dbUrl = "mongodb://localhost:27017/sampledb";
const options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000, useNewUrlParser: true }
mongoose.connect(dbUrl,options, function(
  error
) {
  if (error) {
    console.log("mongoerror", error);
  } else {
    console.log("connected");
  }

});

2

トポロジエラーを解決するには、mongoを再起動し、mongooseまたはmongoclientのいくつかのオプションを変更して、この問題を解決する必要があります。

var mongoOptions = {
    useMongoClient: true,
    keepAlive: 1,
    connectTimeoutMS: 30000,
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 5000,
    useNewUrlParser: true
}

mongoose.connect(mongoDevString,mongoOptions);

SOへようこそ!回答を編集し、いくつかの情報を追加してください。つまり、問題の解決方法などです。詳細なガイダンスについては、stackoverflow.com / help
B--rian

1

MongoDb Compassコミュニティで新しいデータベースを作成しているときに、このエラーが発生しました。問題は私のMongodにあり、実行されていませんでした。したがって、修正として、Mongodコマンドを前述のように実行する必要がありました。

C:\Program Files\MongoDB\Server\3.6\bin>mongod

そのコマンドを実行した後、データベースを作成することができました。

それが役に立てば幸い。


1

私はしばらくの間これに苦労していました-他の回答からわかるように、問題は非常に異なる場合があります。

原因を見つける最も簡単な方法は、これをloggerLevel: 'info'オプションでオンにすることです


0

私の場合、このエラーは、同じサーバーインスタンスが既にバックグラウンドで実行されていることが原因で発生しました。

奇妙なことに、サーバーがすでに実行されていることに気付かずにサーバーを起動したとき、コンソールに「何かがポートxxxを使用している」などのメッセージが表示されませんでした。サーバーに何かをアップロードすることもできました。そのため、この問題を特定するのにかなり時間がかかりました。

さらに、想像できるすべてのアプリケーションを閉じた後も、このポートを使用しているプロセスをMacのアクティビティモニターで見つけることができませんでした。lsofトレースに使用する必要があります。犯人は驚くべきことではありませんでした-それはノードプロセスです。ただし、ターミナルに表示されたPIDで、モニターのポート番号がサーバーで使用されているものとは異なることがわかりました。

全体として、すべてのノードプロセスを強制終了すると、この問題を直接解決できます。


-3

私はこの問題を次の方法で解決しました:

  1. mongoが実行されていることを確認する
  2. サーバーを再起動する

4
これによって問題が再発するのを防ぐことはできません
Sam Munroe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.