nodejs Programming

[Node.js] Socket.IO와 Redis를 활용한 채팅 서버 개발

이번 글에서는 Node.js와 Socket.IO를 통해 기본적인 채팅 애플리케이션을 구축하는 방법을 소개합니다. 이어 Redis Pub/Sub 메세징 기능을 적용해 Clustering 모드로 애플리케이션을 확장하는 법까지 알아보겠습니다.

  • Socket.IO 기반의 채팅 애플리케이션 구축
  • Redis의 Publish/Subscribe 기능 활용 
  • PM2를 활용한 Clustering 모드 적용

Socket.IO 기반의 채팅 사이트 구축

1. Socket.IO Demo Project 받기

Socket.IO 공식 데모 프로젝트를 git clone합니다.

[guser@nodejs ~]$ git clone https://github.com/socketio/socket.io

2. WORK_DIR 변경
(가비아 Node.js 호스팅을 이용하지 않는 경우, 아래 단계는 생략합니다.)

[guser@nodejs ~]$ vi .bashrc 

[변경 전]

export WORK_DIR="/web"

[변경 후]
WORK_DIR에 프로젝트 경로를 설정합니다.

export WORK_DIR="/web/socket.io/examples/chat"

3. Project Directory로 이동

[guser@nodejs ~]$ cd socket.io

4. NPM 설치

[guser@nodejs socket.io]$ npm install

/socket.io/package.json에 명시한 dependencies 목록을 설치합니다.

5. Chatt 예제 프로젝트로 이동

[guser@nodejs socket.io]$ cd examples/chat/

6. NPM 설치

/socket.io/examples/chat/package.json에 명시한 dependencies 목록을 설치합니다.

[guser@nodejs chat]$ npm install

7. Socket.IO 코드 리뷰

/socket.io/examples/chat/index.js

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
io.on('connection', (socket) =>  { 
  socket.on('new message', (data) => {
    socket.broadcast.emit('new message', data);
  });
});

Socket.IO를 사용하는 기본적인 서버 사이드 코드입니다.

line 1~4: Express 모듈을 통해 HTTP 서버를 생성하고 Socket.IO 서버와 연결합니다. (line 4의 ‘../..’ 는 ‘socket.io‘ 모듈을 로드합니다.)
line 6: Client의 Connection 이벤트 발생 시, Client Socket 파라미터와 함께 Callback을 받습니다.
line 7: Client로부터 “new message”라는 이벤트 수신할 시, data 파라미터와 함께 Callback을 받습니다.
line 8: “new message”라는 이벤트로 Broadcasting(자신을 제외한 모든 Client에게 전송) 합니다.

/socket.io/examples/chat/public/main.js

var socket = io();
const sendMessage = () => {
    var message = $inputMessage.val();
    message = cleanInput(message);
    if (message && connected) {
        $inputMessage.val('');
        addChatMessage({
        username: username,
        message: message
    });
    socket.emit('new message', message);
    }
}
socket.on('new message', (data) => {
    addChatMessage(data);
});

Socket.IO를 사용하는 기본적인 클라이언트 사이드 코드입니다. View에 관련 된 코드는 다루지 않습니다.

line: 1Socket.IO 서버에 Connection 요청을 하여 Client socket을 생성합니다.
line: 3: View에서 메세지 전송 시, 호출할 함수
line: 12: Server로 “new message”라는 이벤트를 message 파라미터와 함께 전송합니다.
line: 16: Server로 부터 “new message”라는 이벤트를 수신 시, data 파라미터와 함께 Callback을 받습니다.

8. PM2(프로세스 매니저) 설치

PM2는 Node.js 프로세스 관리도구입니다. PM2를 이용해 애플리케이션 재시작, 재로드뿐 아니라 로그 모니터링도 쉽게 할 수 있습니다.

[guser@nodejs chat]$ npm install pm2 -g

[ PM2 관리 명령어 ]

table01.png

* app_name 대신 all 또는 애플리케이션 id로 변경하여 사용할 수 있습니다.

9. npm start 스크립트 변경

애플리케이션을 PM2(프로세스 매니저)로 실행하도록 start 스크립트를 변경합니다.

[guser@nodejs chat]$ vi package.json

/socket.io/examples/chat/package.json

[변경 전]

 "scripts": {
    "start": "node index.js"
  }

[변경 후]

 "scripts": {
    "start": "pm2 start index.js"
  }

10. 웹 애플리케이션 실행

[guser@nodejs chat]$ npm start
chatapp01.png

11. 웹 애플리케이션 사이트 접속

가비아 Node.js 호스팅: https://{SSH접속 ID}.gabia.io
로컬: http://localhost:3000/

chatapp02.png
chatapp03.png

Redis Publish/Subscribe 기능 활용

1. socket.io-redis 모듈 설치

[guser@nodejs chat]$ npm install socket.io-redis

/socket.io/examples/chat/package.json에 socket.io-redis 모듈을 설치합니다.

2. Redis 연결

/socket.io/examples/chat/index.js

var express = require('express');
var app = express();
var path = require('path');
var server = require('http').createServer(app);
var io = require('../..')(server);
var redis = require('socket.io-redis');
var port = process.env.PORT || 3000;
server.listen(port, () => {
  console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(path.join(__dirname, 'public')));
// Chatroom
var numUsers = 0;
// Adapting Redis
io.adapter(redis({ host: 'localhost', port: 6379 }));
io.on('connection', (socket) =>  { /* … */ });

Socket.IO를 사용하는 기본적인 서버 사이드 코드입니다.
line 6: Socket.IO와 Redis 연결을 위해 redis 객체를 생성합니다.
line 20: Redis의 host와 port 값을 넣어 Socket.IO 서버에 연결합니다.

3. 웹 애플리케이션 실행

[guser@nodejs chat]$ npm start

4. Redis Data Monitoring

chatapp04.png

 

사용자의 접속 및 메세지 전송이 Redis를 통해 이루어지는 것을 확인할 수 있습니다.

chatapp05.png

PM2를 활용한 Clustering 모드 적용

1. Processes config 파일 생성

[guser@nodejs chat]$ vi processes.config.js

/socket.io/examples/chat/processes.config.js

module.exports = {
  apps : [{
    script    : "./index.js",
    instances : "max",
    exec_mode : "cluster"
  }]
}

[ Instances 옵션 ]

table02.png

2. npm start 스크립트 변경

[guser@nodejs chat]$ vi package.json

/socket.io/examples/chat/package.json

[변경 전]
 "scripts": {
    "start": "pm2 start index.js"
  }
[변경 후]
 "scripts": {
    "start": "pm2 start processes.config.js"
  }

3. 소켓 연결 설정

/socket.io/examples/chat/public/main.js

var socket = io(url, {transports: [ 'websocket' ]});

line 1: 접속 URL(도메인 혹은 IP)과 transports를 설정 합니다. transports를 websocket으로 설정하면 polling 방식을 사용하지 않게 됩니다.

4. 웹 애플리케이션 실행

[guser@nodejs chat]$ npm start
chatapp06.png

instances를 max로 설정하여 16개의 프로세스가 실행된 것을 확인할 수 있습니다.

지금까지 Socket.IO와 Redis Pub/Sub을 활용한 채팅 애플리케이션을 만들어 보았습니다. 완성된 프로젝트 코드는 여기에서 확인 할 수 있습니다.

채팅 서버 개발, 가비아 Node.js 호스팅을 이용하면 더 간편해 집니다.
CBT, OBT를 거쳐 안정성이 검증된 컨테이너 기반 Node.js 호스팅을 이용해 보세요!

초보 개발자도 쉽게 사용할 수 있도록 Node.js에 최적화된 호스팅 환경을 제공합니다.

[Node.js 호스팅 알아보기]

[참고]
https://socket.io/
https://github.com/gabia/socket.io