2일동안이나 날 괴롭힌 끔찍한 에러를 만났다.
에러로그는
Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
처음에 로그를 보고 구글링했는데 답이 나오지않았다.
우리의 서비스는
채팅을 위한 socket.io
채팅방 목록 캐시 저장 서버인 redis
라이브스트리밍 RDB mysql
를 nodejs 서버에서 사용하고 있었다.
얼핏 에러로그를 보면 소켓이 문제구나 라고 생각이 들었고, 에러가 나타나는 상황도 너무 가지각색이었다.
문제해결 프로세스를 아무리 다시 되새기고 처음으로 돌아가려고 해도 에러가 나는 상황이 너무 가지각색이었다.
어찌저찌 찾은 저 에러코드에 대한 내용도
상대방이 TCP 연결을 끊은 경우에 이 에러코드가 나옵니다.
였기 때문에 하루종일 socket.io와 redis 쪽 문젠가 싶어서 socket.io 연결 및 이벤트들의 코드를 아무리 고쳐보고, redis쪽 비동기 코드를 아무리 고쳐봐도 문제는 해결되지 않았다.
하루 반을 그렇게 삽질하다가 머리속에 스쳐지나간 점이 있었다.
코드를 수정하고 라이브스트리밍을 테스트 하는 도중 이것저것을 만지다보면, 저 에러를 뱉으면서 서버가 죽었는데 죽은 서버를 켜서, 라이브스트리밍을 시작하는 mysql 쿼리를 보내고 나면 금방 죽는다 라는 것이었다.
????????????? --> Query를 보내고 일정한 시간이 지나면 에러를 뱉으면서 서버가 죽는다?
너구나..
내가 잘못한 것
1. mysql이나, 모든 예외상황이 생길만한 것들에는 예외처리를 해뒀어야했는데 안해놨다.
2. 원인이 웹소켓쪽이라고 단정지었다.(TCP는 생각해보면 http 프로토콜의 4계층에도 있다.. 해결하고나니 보이네)
에휴.. 예외처리를 하니 문제가 생긴 부분이 바로 보였다.
예외처리한 부분
1. 크리티컬한 예외가 생겨도 일단은 꺼지지 않게 해주는 예외처리 ( 테스트서버에서만 테스트용으로)
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
2. mysql을 connection 하는 부분에 예외처리
//예외처리 안한거
con.connect();
//예외처리 한거
con.connect(function(err){
console.log(err.code);
});
그렇게 다시 서버를 실행하고, 쿼리를 정확히 두번 보내려고하니까 해당 에러로그를 뱉어냈다. (감격)
Error: Cannot enqueue Query after invoking quit.
at Protocol._validateEnqueue (/usr/local/nginx/chat/node_modules/mysql/lib/protocol/Protocol.js:215:16)
at Protocol._enqueue (/usr/local/nginx/chat/node_modules/mysql/lib/protocol/Protocol.js:138:13)
at Connection.query (/usr/local/nginx/chat/node_modules/mysql/lib/Connection.js:198:25)
at /usr/local/nginx/chat/index.js:796:7
at Layer.handle [as handle_request] (/usr/local/nginx/chat/node_modules/express/lib/router/layer.js:95:5)
at next (/usr/local/nginx/chat/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/usr/local/nginx/chat/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/usr/local/nginx/chat/node_modules/express/lib/router/layer.js:95:5)
at /usr/local/nginx/chat/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/usr/local/nginx/chat/node_modules/express/lib/router/index.js:335:12)
커넥션이 끊기고 나서 또 쿼리를 보내려고하니 서버가 튕기지..
문제는 python, php에서 사용하던 것처럼 connection을 만들고, 쿼리를 보낸후 connection을 close 해준게 문제가 됐었다.
뭐때문인진 모르고 non-blocking I/O 때문인가? 라는 얕은 추측은 하는데 너무 힘들어서 일단 제대로 알아보진 않았다.
바로 검색어들을 바꾸니 레퍼런스가 쏟아져 나오기 시작했다.
nodejs mysql server closed connection
근데 진짜 왜일까? 왜 커넥션 닫고 다시 연결해주는데 안되는거지? 아시는분 알려주세요 제발 - TodoList
아무튼 이리저리 레퍼런스들 확인하다 보니
nodejs 서버를 켠 동안은 connection을 닫으면 안됨!
이었다.
엥 그럼 나같이 nodejs 서버 키고 쿼리 많이 보내야되는사람들은 어떡하지? 라고 찾아보니
나는 일정을 맞춰야하기 때문에 제일 빠르게 해결할 수 있는 부분은 connection을 pool 방식으로 연결을 하라는 것이었다.
그럼 켰다껐다해도 되는데 DB에 부담이 간다고 한다. 문식아(우리 DBA) 미안..
그걸로 해버려야지~
좋은 레퍼런스를 찾았다.
보안을 위해 db의 config파일은 따로 분리를 했어야했다.
//consts.js
var mysql = require('mysql');
var pool = mysql.createPool({
Host : 'localhost',
user : 'user',
password : 'secret',
database : 'test',
port : 3306
});
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]; //last arg is callback
pool.getConnection(function(err, 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(); // always put connection back in pool after last query
if(err){
console.log(err);
return callback(err);
}
callback(null, results);
});
});
}
};
이렇게 pool 방식으로 argument가 몇개 들어오든 쿼리를 보내고, 끝나면 release를 시켜서
연결하고 끊고 하는 방식이다.
//실행하려는 곳
var connection = require('./consts.js');
con.query("SELECT * FROM live WHERE live_idx=?", [live_idx], function (err, result) {
if (err) throw err;
//your code
});
요론식으로 쓰니까 connection pool이 잘 생성되고 release 된다. 코드는 천천히 보면 이해하기 쉽다.
이 문제를 마구 뒤지면서 내가 확실히 JavaScript에 대한 이해가 많이 부족하다고 생각했다.
변수에 관한 부분이나, 함수에 관한 부분이나, 비동기처리를 위한 부분이나 콜백 이런 부분들이 나에겐 약점이었다.
(Java 쓰레드가 젤 싫었음)
그래도 그런부분을 많이 배웠다. 오늘도 깨달았다!
'DB' 카테고리의 다른 글
Scylladb 설치 - Ubuntu 20.04 (0) | 2023.01.01 |
---|---|
채팅 영구저장 - RDB vs NoSQL (0) | 2022.12.29 |
Ubuntu 20.04 - Redis 설치 (0) | 2022.08.23 |
MariaDB - Ubuntu 20.04(LTS) DB Replication -ec2 mmm(multi master manager) 서버 설정 (1) | 2022.06.28 |
Mariadb-15.1 user의 host 변경 - ALTER TABLE error (0) | 2022.06.26 |
댓글