nodejs mysql Error: การเชื่อมต่อหายไปเซิร์ฟเวอร์ปิดการเชื่อมต่อ


93

เมื่อฉันใช้ node mysql ข้อผิดพลาดจะปรากฏขึ้นระหว่างเวลา 12:00 ถึง 02:00 น. ว่าการเชื่อมต่อ TCP ถูกปิดโดยเซิร์ฟเวอร์ นี่คือข้อความฉบับเต็ม:

Error: Connection lost: The server closed the connection.
at Protocol.end (/opt/node-v0.10.20-linux-x64/IM/node_modules/mysql/lib/protocol/Protocol.js:73:13)
at Socket.onend (stream.js:79:10)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)

มีเป็นวิธีการแก้ปัญหา อย่างไรก็ตามหลังจากลองทำตามวิธีนี้ปัญหาก็ปรากฏขึ้นเช่นกัน ตอนนี้ไม่รู้จะทำอย่างไร มีใครเจอปัญหานี้บ้าง?

นี่คือวิธีที่ฉันเขียนตามแนวทางแก้ไข:

    var handleKFDisconnect = function() {
    kfdb.on('error', function(err) {
        if (!err.fatal) {
            return;
        }
        if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
            console.log("PROTOCOL_CONNECTION_LOST");
            throw err;
        }
        log.error("The database is error:" + err.stack);

        kfdb = mysql.createConnection(kf_config);

        console.log("kfid");

        console.log(kfdb);
        handleKFDisconnect();
    });
   };
   handleKFDisconnect();

if (err.code !== 'PROTOCOL_CONNECTION_LOST') { console.log("PROTOCOL_CONNECTION_LOST"); throw err; }โปรดทราบว่าในรหัสของคุณคุณมีข้อความถูกต้อง: คุณดำเนินการif()บล็อกหากยังไม่ PROTOCOL_CONNECTION_LOSTได้รับข้อความแจ้งว่าเป็นข้อผิดพลาดนั้น ... อาจสับสนมาก
Alexis Wilke

คำตอบ:


164

พยายามใช้รหัสนี้เพื่อจัดการกับการตัดการเชื่อมต่อของเซิร์ฟเวอร์:

var db_config = {
  host: 'localhost',
    user: 'root',
    password: '',
    database: 'example'
};

var connection;

function handleDisconnect() {
  connection = mysql.createConnection(db_config); // Recreate the connection, since
                                                  // the old one cannot be reused.

  connection.connect(function(err) {              // The server is either down
    if(err) {                                     // or restarting (takes a while sometimes).
      console.log('error when connecting to db:', err);
      setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
    }                                     // to avoid a hot loop, and to allow our node script to
  });                                     // process asynchronous requests in the meantime.
                                          // If you're also serving http, display a 503 error.
  connection.on('error', function(err) {
    console.log('db error', err);
    if(err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
      handleDisconnect();                         // lost due to either server restart, or a
    } else {                                      // connnection idle timeout (the wait_timeout
      throw err;                                  // server variable configures this)
    }
  });
}

handleDisconnect();

ในรหัสของคุณฉันขาดชิ้นส่วนหลังจากนั้น connection = mysql.createConnection(db_config);


ตกลงฉันจะลองสิ่งนี้ แต่ฉันจะจำลองสถานการณ์นี้ได้อย่างไร
jackieLin

1
เคล็ดลับ: ฉันกำลังทดสอบการเชื่อมต่อใหม่โดยเริ่มบริการ mysql ใหม่เพื่อให้แน่ใจว่าทุกอย่างทำงานได้ดี
kriskodzi

2
@jackieLin คุณสามารถจำลองสถานการณ์เริ่มต้นบริการ mysql บน Ubuntu sudo service mysql restart
igor

1
ขอบคุณ @ user3073745 ปัญหานี้แก้ไขได้โดยการรีสตาร์ท
jackieLin

1
ทำงานได้อย่างสมบูรณ์แบบสำหรับโหนด 8. *, npm 5.6.0 และ mysql: 5.7 ... ขอบคุณ !!
JRichardsz

47

ฉันจำกรณีการใช้งานเดิมของฉันสำหรับกลไกนี้ไม่ได้ ทุกวันนี้ฉันไม่สามารถนึกถึงกรณีการใช้งานที่ถูกต้องได้

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

tl; dr; อย่าใช้วิธีนี้


วิธีแก้ปัญหาในทางปฏิบัติคือบังคับให้ MySQL รักษาการเชื่อมต่อไว้:

setInterval(function () {
    db.query('SELECT 1');
}, 5000);

ฉันชอบโซลูชันนี้มากกว่าพูลการเชื่อมต่อและการจัดการการตัดการเชื่อมต่อเนื่องจากไม่จำเป็นต้องจัดโครงสร้างโค้ดของคุณในลักษณะที่ตระหนักถึงสถานะการเชื่อมต่อ การสอบถามทุกๆ 5 วินาทีทำให้มั่นใจได้ว่าการเชื่อมต่อจะยังคงมีชีวิตอยู่และPROTOCOL_CONNECTION_LOSTไม่เกิดขึ้น

นอกจากนี้วิธีนี้ยังช่วยให้มั่นใจได้ว่าคุณยังคงมีการเชื่อมต่อเดิมอยู่เสมอเมื่อเทียบกับการเชื่อมต่อใหม่ นี้เป็นสิ่งสำคัญ. ลองพิจารณาว่าจะเกิดอะไรขึ้นหากสคริปต์ของคุณใช้LAST_INSERT_ID()และการเชื่อมต่อ mysql ถูกรีเซ็ตโดยที่คุณไม่รู้ตัว?

อย่างไรก็ตามสิ่งนี้ช่วยให้มั่นใจได้ว่าการหมดเวลาการเชื่อมต่อ ( wait_timeoutและinteractive_timeout) จะไม่เกิดขึ้น มันจะล้มเหลวตามที่คาดไว้ในสถานการณ์อื่น ๆ ทั้งหมด ดังนั้นอย่าลืมจัดการข้อผิดพลาดอื่น ๆ


1
แค่อยากรู้ว่าคุณจะใส่แบบสอบถามฐานข้อมูลนั้นไว้ที่ไหน ที่ด้านล่างของเซิร์ฟเวอร์ nodejs ใช่ไหม ปัญหาเดียวคือฉันใช้ mysql เพื่อพิสูจน์ตัวตนผู้ใช้เพียงครั้งเดียวจากนั้นฉันเก็บข้อมูลไว้ในวัตถุผู้ใช้ชั่วคราวสำหรับเกม rpg ของฉัน ฉันไม่รู้ว่าทำไมฉันถึงได้รับข้อผิดพลาดปิด mysql แบบสุ่มในวันนี้อืม ฉันกำลังปิดการเชื่อมต่ออย่างถูกต้อง ฯลฯ เช่นกัน
NiCk Newman

1
คุณควรเชื่อมต่อกับฐานข้อมูลและยกเลิกการเชื่อมต่อตามความต้องการ โซลูชันนี้มีไว้สำหรับบริการที่ทำงานอย่างต่อเนื่องและใช้การเชื่อมต่อฐานข้อมูลตลอดเวลา
Gajus

1
ฟังดูไม่น่าจะเป็นไปได้เนื่องจากโค้ดของคุณเป็นไปตามรูปแบบที่อธิบายไว้ (คล้ายกับgist.github.com/gajus/5bcd3c7ec5ddcaf53893 ) หากสิ่งนี้เกิดขึ้นเพียงครั้งเดียวหรือสองครั้งจากข้อความค้นหาหลายพันรายการฉันจะถือว่าปัญหาการเชื่อมต่อเซิร์ฟเวอร์โอเวอร์โหลดหรือบางอย่างตามบรรทัดเหล่านั้น
Gajus

3
นั่นอาจเป็นคำแนะนำที่แย่ที่สุดที่เคยมีมา! มีคนแนะนำว่าคุณควรตอกฐานข้อมูลด้วยแบบสอบถามเพื่อให้การเชื่อมต่อไม่หายไป? จะเกิดอะไรขึ้นถ้า 100 คนทำสิ่งนี้? หรือทำไมไม่ 10,000 ถ้าแอปของคุณไม่ทราบเธรดควรจะถูกส่งกลับไปยัง MySQL Thread Pool โดยไม่ต้องบีบเธรดเพื่อให้โค้ดที่อ่อนแอของคุณไม่พัง! ในกรณีนี้คุณจะใช้ฟังก์ชันสำหรับการเชื่อมต่อใหม่หากเกิดเหตุการณ์ดังกล่าว ! นี่ไม่น่าเชื่อมันช่างเป็นเรื่องที่น่ายินดีขอบคุณพระเจ้าที่ FB ไม่มีคุณเป็นหัวหน้าสถาปนิก !!
Patrik Forsberg

2
ฉันได้อัปเดตคำตอบเพื่อแสดงว่าฉันไม่แนะนำแนวทางนี้ ขอบคุณสำหรับการแก้ไข Patrik
Gajus


4

ทางออกที่ดีกว่าคือใช้สระว่ายน้ำ - จัดการสิ่งนี้ให้คุณไม่ดี

const pool = mysql.createPool({
  host: 'localhost',
  user: '--',
  database: '---',
  password: '----'
});

// ... later
pool.query('select 1 + 1', (err, rows) => { /* */ });

https://github.com/sidorares/node-mysql2/issues/836


นี่ควรเป็นคำตอบที่ได้รับการยอมรับ การใช้กลไกพูลจะซ่อนรายละเอียดที่ซับซ้อนทั้งหมดเกี่ยวกับวิธีจัดการกับเวลาในการเชื่อมต่อ นอกจากนี้ยังมีเอกสารเกี่ยวกับวิธีการใช้งานในnode_modules/mysql/Readme.mdไฟล์ที่มาพร้อมกับโมดูลโหนด MySQL
Alexis Wilke

1

การสร้างและทำลายการเชื่อมต่อในแต่ละแบบสอบถามอาจซับซ้อนฉันปวดหัวกับการย้ายเซิร์ฟเวอร์เมื่อฉันตัดสินใจติดตั้ง MariaDB แทน MySQL ด้วยเหตุผลบางประการในไฟล์ etc / my.cnf พารามิเตอร์ wait_timeout มีค่าเริ่มต้น 10 วินาที (ทำให้ไม่สามารถใช้การคงอยู่ได้) จากนั้นตั้งค่าโซลูชันเป็น 28800 นั่นคือ 8 ชั่วโมง ฉันหวังว่าจะช่วยใครสักคนในเรื่อง "güevonada" ... ขอโทษที่ภาษาอังกฤษไม่ดีของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.