Node.js- PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR 해결법

janghoosa·2022년 8월 18일
0

Node.js

목록 보기
2/4
post-custom-banner

문제 상황

서버에 부하 테스트를 진행하면서 pm2의 cluster모드를 통해 여러개의 코어를 사용하게 해놓았는데 그 과정에서 DB와 통신하는 과정에서 PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR 오류가 계속 발생하였다.

문제 분석

에러 로그를 분석해보면 쿼리를 실행하기 전에 FATAL한 에러가 발생하여 작업을 할 수 없다는 것이었다.
인터넷 검색을 해보았더니 여러 글이 나왔지만 모두 정확한 이유를 알고 있지 않았고 해결 방법도 되는 경우가 있고 없는 경우가 있었다.

필자와 같은 경우는 평소에는 이상이 없다가 많은 요청이 들어올 때 오류가 발생하는 특징이 있었다.

내가 생각했던 이유는 connection을 받아오는 과정에서 요청을 수행한 후 release가 되지 않던가 동시에 요청을 보내 동시에 connection을 받아올 수 없는 이유인가로 줄이고 생각해보았다.

그 과정에서 DB와의 통신과정을 알게 되었고 pool과 connection의 차이에 대해 알게 되었다.

문제 해결

mysql.createConnection() -> connection.connect() -> connection.query() -> connection.end()

클라이언트측에서 데이터베이스에 접속해서 질의를 수행한 후, 결과를 받고 접속을 종료하는 일련의 과정이 Connection으로 데이터베이스에 연결되는 과정이다.

사용자의 요청에 따라 Connection을 생성하다 보면 많은 수의 연결이 발생했을 때 서버에 과부하가 걸리게 된다.

이러한 상황을 방지하기 위해 미리 일정수의 Connection을 만들어 Pool에 담아뒀다가 사용자의 요청이 발생하면 연결을 해주고 연결 종료 시 Pool에 다시 반환하여 보관하는 것이 바로 Connection Pool이다.

이러한 Connection Pool은 Connection을 미리 생성해두고 관리함으로써 데이터베이스에 과부하를 방지하고 유동적으로 Connection을 관리할 수 있다는 장점이 있다.

나한테 발생했던 이유는 MySQL과 같은 무료 RDBMS에서는 connection을 자동으로 release 해주지 않아 문제가 발생한 것이다.

이 문제를 해결하기 위해 앞으로 MySQL을 사용할때는 pool에서 connection을 받아와서 사용하고 release해줘야 할 것이다.

아래와 같이 query함수를 만들면 기존에 쓰던 코드를 수정할 필요 없이 바로 사용할 수 있다.

var pool = mysql.createPool({ // createConnection이 아닌 createPool
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  port: process.env.DB_PORT,
});

module.exports = {
  query: function(){
      var sql_args = [];
      var args = [];
      for(var i=0; i<arguments.length; i++){
          args.push(arguments[i]);
      }
      var callback = args[args.length-1]; // 마지막 인자로 callback을 받아온다.
      pool.getConnection(function(err, connection) { // pool에서 connection을 받아온다.
      if(err) {
              console.log(err);
              return callback(err);
          }
          if(args.length > 2){
              sql_args = args[1];
          }
      connection.query(args[0], sql_args, function(err, results) {
        connection.release(); // 마지막 쿼리를 진행한 후에 connection을 release해준다.
        if(err){
                  console.log(err);
                  return callback(err);
              }
        callback(null, results);
      });
    });
  }
};

출처:
https://cotak.tistory.com/105 [TaxFree:티스토리]
https://stackoverflow.com/questions/17015590/node-js-mysql-needing-persistent-connection

profile
백엔드 개발자 지망생입니다 :)
post-custom-banner

0개의 댓글