Socket.io를 이용하여 데이터 크롤링 결과를 실시간으로 뿌려주는 기능을 구현하였다.
물론 Node.js를 두개로 나누어 웹 서비스용과 데이터 크롤링 및 전송용으로 나눠서 사용했지만, Node.js http request 모듈이 특정 사이트에 가면 timeout이 생기는 문제가 발생했다.(Node.js가 Non-blocking이 아니었나..)
그래서 서버를 웹 서비스 / 데이터 크롤링 / 데이터 전송 세가지로 나누고, 데이터 크롤링 서버가 데이터를 redis 상에 업데이트 하면 이 정보를 데이터 전송 서버에 전달하도록 구현하는데 redis publish, subscribe를 사용했다.
우선 데이터 크롤링에서 얻은 데이터는 실시간 데이터기 때문에 소실되어도 문제가 크게 없어서, redis pub/sub이 적당하였다. 사실 MQ(메시지큐)를 쓰게되면, 오히려 데이터를 체크하고 제거하는게 문제가 될 수도 있었다. (Scale Out을 고려하면 더욱)
아무튼 인터넷상에 다양한 예제들을 보면서 대충 구현했는데, 문제가 생겨버렸다.
Only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context
이 오류는 subscribe 하고 있는 redis connection이 저 위의 명령 외의 다른 명령(데이터를 가져온다던지, 입력한다던지)을 수행하면, 현재 커넥션은 subscribe중이라 다른 동작은 할 수 없다는 뜻이었는데, 당연히 커넥션 재활용은 하지 않은 상태.
일반적으로 인터넷 예제에서는 pub/sub 커넥션 2개와 데이터 관리용 커넥션 1개, 총 3개를 사용한다.
나도 당연히 이를 참조한거기 때문에 커넥션 3개 이상을 사용했다.(디버깅할때는 3개로 해봤지만) 근데 안되네..
진짜 별 삽질을 다해봤는데, 이유를 찾을 수 없었다.
두어시간 날려버리고, 우연치 않게 redis-cli에서 커넥션 리스트를 확인하면서 알 수 있었는데...
결론은 커넥션이 2개밖에 안생겼다. 즉 커넥션 생성이 문제가 있었던 것.
왜일까... 우선 내 코드는 모듈화를 위해서 따로 redis-client.js를 작성하고 이를 require 명령으로 import후 사용하는 것이다.
redis-client.js
sending-server.js
pub-sub.js
변경한 코드
// redis-client.js
var redis = require('redis');
var redisConfig = require('./redis-client-info');
module.exports = (function(){
var rds = new redis.createClient(redisConfig.port, redisConfig.host);
return {
client : rds
};
}());
// 기존 코드
// redis-client.js를 바탕으로 새로 만든 모듈들
var rdb = require('./redis-db');
var crdb = reuqire('./redis-db');
var rpub = require('./pub-sub.js');
var rsub = require('./pub-sub.js');
module.exports = function(){
var client = require('./util/redis-client').client;
function subscribe(channel){
client.subscribe(channel);
}
function publish(channel, data){
client.publish(channel, data);
}
function ping(channel){
client.ping(channel);
}
function onMsgListener(callback){
client.on("message", function(channel, message){
callback(channel,message);
});
}
return {
subscribe:subscribe,
publish:publish,
ping:ping,
client:client,
onMsgListener:onMsgListener
};
}();
pub-sub.js
즉, 그냥 pub-sub 소스코드에서 redis의 createClient를 호출했다.
왜 안되던 것이었을까? 심지어 동일한 JS 모듈을 호출하는게 여러개나 있었는데!
정말 이해하지 못하겠다. 그래서 나는 버그라고 자기 위로를 하고있다.
var rutils = require('./util/redis-utils');
var redisConfig = require('./util/redis-client-info');
var redis = require('redis');
module.exports = function(){
var client = new redis.createClient(redisConfig.port, redisConfig.host);
function subscribe(channel){
client.subscribe(channel);
}
function publish(channel, data){
client.publish(channel, data);
}
function ping(channel){
client.ping(channel);
}
function onMsgListener(callback){
client.on("message", function(channel, message){
callback(channel,message);
});
}
return {
subscribe:subscribe,
publish:publish,
ping:ping,
client:client,
onMsgListener:onMsgListener
};
}();
혹시 아시는분 있다면 댓글로 알려주세요.
'프로그래밍 > 서버, DBMS' 카테고리의 다른 글
[서버] 우분투 아파치 가상호스트 및 프록시 설정 (0) | 2019.03.27 |
---|---|
[SSL] 아파치에 Let's encrypt 인증서 설치 및 certbot을 이용한 자동 갱신 (0) | 2019.03.19 |
[티스토리] 티스토리 OPEN API 이용하여, Access token 발급받기 (2020.12.10 업데이트) (2) | 2019.03.10 |
[서버] 웹 서비스 단일 로그인 (아이디당 1세션 유지) (0) | 2019.03.10 |
[Node.js] Express-session 기반 로그인 세션 관리시, 로그인 리다이렉트 Ajax 처리 (0) | 2019.03.04 |