nodejs/docker/socket.io(+redis) 여러개의 서버로 채팅

2021. 11. 3. 19:14개발/nodejs

로드밸런싱을 위해 서버를 여러개 두었더니 채팅 기능에 문제가 생겼다.

  socket.io-redis 모듈을 사용하여 해결하였다.

 

 사실 수정된 부분도 별로 없고 한데, 별 이유로 삽질하느라 시간을 너무 많이 잡아먹어 되풀이 하지 않도록 적어본다.

 

 

우선 레디스를 먼저 설치해주어야 한다.

 난 도커로 설치하였다.

 

1. Dockerfile 및 redis.conf 작성

 - Dockerfile

FROM redis
COPY redis.conf /etc/redis/redis.conf
CMD ["redis-server", "/etc/redis/redis.conf"]

- redis.conf 

bind 0.0.0.0

  기본으로 로컬에서만 접근 가능하도록 되어있으니 설정 해주어야 한다. 

 

 

2. 빌드 및 컨테이너 생성/실행

  Dockerfile 과 redis.conf 파일이 있는 디렉토리에서..

sudo docker build -t 이미지명:태그
sudo docker build -t dockerId/redis:tag .

sudo docker create --name 컨테이너명 -p 외부포트:내부포트 이미지명:태그
sudo docker create --name redis -p 6379:6379 dockerId/redis:tag

sudo docker start redis

  레디스는 기본 6379 포트를 사용한다. 

 다른 포트를 사용하고 싶을경우 ( 예 1234 ) 위의 redis.conf 에 port 1234 를 추가해주고 그에 맞게 컨테이너를 만들어주면 된다.

 ( 근데 외부에서 막 붙는게 걱정될 경우 컨테이너 생성할 때 외부포트를 다른걸로 하면 될것같다 )

 

 

 

 

 

 

 

3. socket.io / socket.io-redis 모듈 설치

npm i --save socket.io
npm i --save socket.io-redis

 

2. 서버 설정파일 수정

 - www.js

let app = require('../app');
let server = http.createServer(app);

// 채팅 관련 부분을 따로 빼 모아두었다.
let socket = require('./socket');
...
let io = require('socket.io')(server);
socket(io);
...

        

 

3. 채팅 처리 관련 파일 수정

 - socket.js ( 서버사이드 )

let redis = require('socket.io-redis');

...
module.exports = function (io) {
	// 당연하지만 해당 서버에 레디스가 설치 되어있어야 한다.
	io.adapter(redis({host: 'xxx.xxx.xxx.xx', port: 6379}));
    
    // 커넥트 
    io.sockets.on('connection', (socket) => {
    
    // 메시지 수신 및 전달
    socket.on('message', (data) => {
    // 간혹 데이터가 문자열로 넘어오는 경우가 있어 처리
    if (typeof data == typeof '') data = JSON.parse(data);
   
	// 같은 방 사람에게만 발송 
    socket.broadcast.to(`${data.room_id}`).emit('message', (data))
    });
    
    });
    
}
...

  서버주소, 포트 잘 확인해주어야 한다. 서버에 오타난거 모르고 다른곳에서 원인 찾다가 정말 많은 시간을 버렸다.

 

 - chat.js ( 클라이언트 )

<script defer src="/socket.io/socket.io.js"></script>
<script>
	// 로컬에서만 테스트 할 경우 값을 비워도 되지만, 그게 아닐경우 HOST:PORT 를 입력해야된다
	var socket = io.connect("xxx.xxx.xx.xx:port");
    
    socket.on('message', function (data) {
                    /*
                    수신받은 메시지 처리
                    */
                });
                
                // 메시지 전송
                socket.emit('message', {
                        "nickname": nickname,
                        "content": val,
                        "room_id": room_id
                    });
                    
                    });
    
</script>

    로드밸런싱 하기 전에는 host:port 를 적지 않아도 잘 작동했던것 같은데.. 뭔가 이상하지만 무튼 적어주니 정상 작동하였다.

 

 

 

  여러개로 나누었던 서버 끼리의 채팅은 물론, 로컬에서 실행한 서버도 메시지가 공유되었다.

 

 

 

 

 

 + 레디스 연결시 timeout 이 발생한다면 포트 열려있는지 꼭 확인해보고,  주소 잘 적었는지도 확인해보자