mongoError: โครงสร้างถูกทำลาย


163

ฉันมีเซอร์วิส REST ที่สร้างขึ้นใน node.js พร้อม Restify และ Mongoose และ mongoDB ที่มีคอลเล็กชันที่มีเอกสารขนาดปกติประมาณ 30,000 รายการ ฉันให้บริการโหนดของฉันทำงานผ่าน pmx และ pm2

เมื่อวานทันใดนั้นโหนดก็เริ่มโวยวายข้อผิดพลาดด้วยข้อความ "MongoError: โทโพโลยีถูกทำลาย" ไม่มีอะไรเพิ่มเติม ฉันไม่รู้ว่าสิ่งนี้มีความหมายอย่างไรและสิ่งใดที่ทำให้เกิดสิ่งนี้ได้ นอกจากนี้ยังมีไม่มากที่จะพบเมื่อค้นหา google นี้ ดังนั้นฉันคิดว่าฉันถามที่นี่

หลังจากรีสตาร์ทบริการโหนดวันนี้ข้อผิดพลาดก็หยุดลงฉันยังมีหนึ่งในผู้ที่ทำงานอยู่ในการผลิตและมันทำให้ฉันกลัวว่าสิ่งนี้อาจเกิดขึ้นได้ตลอดเวลาเพื่อเป็นส่วนสำคัญของการตั้งค่าที่ทำงานอยู่ที่นั่น ...

ฉันใช้แพ็คเกจที่กล่าวถึงดังต่อไปนี้:

  • พังพอน: 4.0.3
  • ปรับเปลี่ยน: 3.0.3
  • โหนด: 0.10.25

2
ฉันมีปัญหาที่คล้ายกันโดยใช้ไดรเวอร์ mongodb เท่านั้น :(
0x8890

1
ฉันไม่ได้ใช้ใบเรือดังนั้นไม่ฉันไม่คิดว่าจะแก้ไขปัญหาของฉันได้เลย
dreagan

คำตอบ:


98

ดูเหมือนว่าหมายถึงการเชื่อมต่อเซิร์ฟเวอร์โหนดของคุณไปยังอินสแตนซ์ 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
ฉันมีปัญหาเดียวกันและมันเกิดขึ้นเกือบทุกสัปดาห์และปิดแอปพลิเคชันที่ทำงานกับพังพอนนี่เป็นปัญหาที่ฉันสร้างขึ้นหรือนี่เป็นปัญหาในพังพอนหรือไม่?
Mohammad Ganji

@MohammadGanji: ฉันได้รับข้อผิดพลาดนี้โดยไม่ต้อง Mongoose ในขณะที่การดีบักรหัสลูกค้าและไม่เร็วพอที่จะก้าวข้ามคำสั่ง ไม่แน่ใจว่าเป็นสาเหตุอะไร แต่ตั้งค่าจุดสั่งหยุดทันทีหลังจากการสอบถาม Mongo หลีกเลี่ยง
Dan Dascalescu

@DanDascalescu ฉันลืมที่จะพูดถึงว่าปัญหาของฉันได้รับการแก้ไขมันเป็นปัญหาเกี่ยวกับการบันทึกดูเหมือนว่ามีคำเตือนบางอย่างในบันทึกว่าหลังจากที่บางครั้งใช้เวลาประมาณกิกะไบต์ของการจัดเก็บและปิดกระบวนการ mongo ดังนั้นฉันพยายาม zipping และสำรอง และแก้ปัญหาได้
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
นี่ไม่ได้แก้ปัญหาสำหรับฉัน จริง ๆ แล้วฉันก็เพิ่มการรักษาชีวิตของฉันเป็น 30000 ซึ่งได้ช่วยอย่างมาก แม้ว่าฉันจะยังคงได้รับข้อผิดพลาดของทอพอโลยีเป็นครั้งคราว
ifightcrime

9
ใช้ไดรเวอร์ Mongo จากรุ่น 3.4.2 ตัวเลือกเหล่านี้จะต้องอยู่ในระดับบนสุด: ตัวเลือก: {keepAlive: 1, connectTimeoutMS: 30000, เชื่อมต่อใหม่พยายาม: 30, เชื่อมต่อใหม่ช่วงเวลา: 5000}
Sebastien H.

ฉันได้รับข้อผิดพลาดนี้โดยไม่ต้อง Mongoose ในขณะที่การดีบักรหัสลูกค้าและไม่เร็วพอที่จะก้าวข้ามคำสั่ง ไม่แน่ใจว่าเป็นสาเหตุอะไร แต่ตั้งค่าจุดสั่งหยุดทันทีหลังจากการสอบถาม Mongo หลีกเลี่ยง
Dan Dascalescu

76

ข้อผิดพลาดนี้เกิดจากคนขับ mongo ปล่อยการเชื่อมต่อไม่ว่าด้วยเหตุผลใด (เซิร์ฟเวอร์ไม่ทำงาน)

โดยค่าเริ่มต้นพังพอนจะพยายามเชื่อมต่อใหม่เป็นเวลา 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

3
ใช้ไดรเวอร์ Mongo จากรุ่น 3.4.2 ตัวเลือกเหล่านี้จะต้องอยู่ในระดับบนสุด: ตัวเลือก: {keepAlive: 1, connectTimeoutMS: 30000, เชื่อมต่อใหม่พยายาม: 30, เชื่อมต่อใหม่ช่วงเวลา: 2000}
Sebastien H.

1
เพื่อชี้แจงตามเอกสารของไดรเวอร์ Node MongoDBโดยค่าเริ่มต้นเซิร์ฟเวอร์จะพยายามเชื่อมต่ออีก 30 ครั้งโดยแยกออกจากกันหนึ่งวินาที
โบอาส

4
คุณไม่จำเป็นต้องให้ตัวเลือกเหล่านี้ภายใต้วัตถุเซิร์ฟเวอร์ตอนนี้ มันไปที่วัตถุตัวเลือกโดยตรง
Animesh Singh เมื่อ

3
แค่อยากจะเพิ่มว่ารุ่นล่าสุดของพังพอนมีตัวเลือกผู้ที่อยู่ในระดับบนสุดจึงไม่จำเป็นต้องเพิ่มserver: {ฯลฯ
อเล็กซ์ K

17

ในกรณีของฉันข้อผิดพลาดนี้เกิดdb.close();จากส่วน 'รอคอย' ภายใน 'async'

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
ในกรณีของคาร์ลอสฉันเดาว่าใกล้จะเกิดขึ้นก่อนทุกอย่างอื่น กรณีของฉันคล้ายกัน: ฉันเข้าถึงฐานข้อมูลหลังจากปิดแล้ว มันจะดีถ้านักพัฒนา Mongo สามารถผลิตข้อความแสดงข้อผิดพลาดที่ชัดเจนมากขึ้น "โทโพโลยีแตก" ดูเหมือนบันทึกย่อภายใน
Juan Lanus

3
ทางออกของคุณคือย้ายdb.closeเข้าไปในthenบล็อกใช่ไหม
AlexChaffee

มันถูกต้องในกรณีของฉันฉันเพียงลบบรรทัด db.close () แต่ย้ายเข้าไปในบล็อกนั้นดูเหมือนจะเป็นทางออกที่ดี
Carlos Rodríguez

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 ตามความคิดเห็นนี้

เพื่อให้แน่ใจว่าทุกรุ่นมีดัชนีของพวกเขาสร้างขึ้นก่อนที่จะตัดการเชื่อมต่อคุณสามารถ:

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

await mongoose.disconnect();

ขอบคุณถ้าคุณใช้กรณีทดสอบ - นี่อาจเป็นคำตอบที่น่าจะเป็น ...
Nick H247

1
นี่มันสำหรับฉัน ขอบคุณ! ฉันกำลังรันการทดสอบใน Jest ด้วย mongodb-memory-server, รับข้อผิดพลาดเป็นระยะ ๆ ในทอพอโลยีหรือการเปิด / การปิดสัญญาที่ยังไม่เสร็จ แต่บางครั้งก็ใช้งานได้ การเพิ่มการรอดัชนีแก้ไขไว้
roblingle

ฉันได้รับข้อผิดพลาดนี้โดยไม่ต้อง Mongoose ในขณะที่การดีบักรหัส Jest เช่น @roblingle และไม่เร็วพอที่จะก้าวข้ามคำสั่ง ไม่แน่ใจว่าเป็นสาเหตุอะไร แต่ตั้งค่าจุดสั่งหยุดทันทีหลังจากการสอบถาม Mongo หลีกเลี่ยง
Dan Dascalescu

@ roblingle คุณจะแก้ไขได้อย่างไร? ฉันพบปัญหานี้และทำให้ฉันไม่สามารถเชื่อมต่อกับ MongoDB ได้อีก ฉันได้ทำการลบทุกอย่างและติดตั้ง MongoDB ใหม่ (ผ่าน homebrew) และตอนนี้มันจะไม่ทำงานเมื่อเริ่มต้นอีกต่อไป (อาจเป็นปัญหาที่ไม่เกี่ยวข้อง)
bobbyz

ฟังดูไม่เกี่ยวข้อง แอพของฉันทำงานได้ดี แต่การทดสอบล้มเหลว
roblingle

3

ความเห็นของเซบาสเตียนเกี่ยวกับคำตอบของ Adrien ต้องการความสนใจมากกว่านี้มันช่วยฉันได้ แต่การเป็นความเห็นอาจไม่ได้รับความสนใจบ้างในบางครั้งดังนั้นนี่เป็นวิธีแก้ปัญหา :

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

ฉันว่ามีข้อผิดพลาดเดียวกัน ในที่สุดฉันก็พบว่าฉันมีข้อผิดพลาดบางอย่างในรหัสของฉัน ฉันใช้ load balance สำหรับเซิร์ฟเวอร์ nodejs สองตัว แต่ฉันเพิ่งปรับปรุงรหัสของเซิร์ฟเวอร์เดียว

ฉันเปลี่ยนเซิร์ฟเวอร์ mongod ของฉัน from standalone to replicationแต่ฉันลืมที่จะทำการปรับปรุงที่สอดคล้องกันสำหรับสตริงการเชื่อมต่อดังนั้นฉันจึงพบข้อผิดพลาดนี้

สตริงการเชื่อมต่อแบบสแตนด์อโลน: สตริง mongodb://server-1:27017/mydb การเชื่อมต่อการจำลองแบบ: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

รายละเอียดที่นี่:[mongo doc สำหรับสตริงการเชื่อมต่อ]


2

ฉันพบสิ่งนี้ในสภาพแวดล้อม kubernetes / minikube + nodejs + พังพอน ปัญหาคือว่าบริการ 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 เพื่อแก้ไขข้อผิดพลาดของทอพอโลยีจากนั้นเพียงแค่เปลี่ยนตัวเลือกของพังพอนหรือ 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/how-to-ask
B - rian

1

ฉันได้รับข้อผิดพลาดนี้ในขณะที่ฉันกำลังสร้างฐานข้อมูลใหม่ใน MongoDb Compass Community ของฉัน ปัญหาเกิดขึ้นกับ 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.