저희의 핵심 기능인 socket 간의 실시간 상태 공유와 이메일 초대를 위해 Redis를 사용했습니다.
Redis는 여러 데이터 구조를 제공하는 in-memory 데이터 저장소로 빠른 작동 속도를 가지고 있어 cache나 database, message broker로 사용됩니다.
서버의 성능을 높이기 위해 고민한 결과입니다.
저희 프로젝트에서 사용한 Node.js는 single-threaded 어플리케이션을 생성합니다.
이는 먼저 요청된 작업을 처리하는데 시간이 길다면, 나중에 요청된 작업을 처리하지 못하는 사태가 발생함을 의미합니다. 이런 일을 방지하기 위해서 Node.js는 cluster 모듈을 제공합니다.
cluster module은 하나의 서버 안에 single-threaded인 여러 프로세스를 만들고 cluster manager가 여러 프로세스 사이에서 load balancing을 하여 마치 다중 스레드 방식으로 요청을 처리하는 것처럼 작동하게 합니다.
cluster를 적용하는 것은 Node.js로 작동하는 서버의 성능을 향상시킬 수 있는 방법 중 하나입니다.
cluster 모듈은 프로세스를 기반으로 작동을 합니다. 프로세스의 자원은 공유되지 않는다는 특징을 가지고 있습니다. 그러므로 cluster 모듈을 사용하지 않았을 때, 작성했던 다음과 같은 코드는 각각의 프로세스 내의 메모리에 저장이 되므로 프로세스간의 동기화가 일어나지 않습니다.
아래는 저희가 cluster 모듈 적용을 고려하지 않고 작성한 코드입니다.
유저의 정보를 객체로 선언하여 관리하고 있습니다. 다음과 같이 사용을 했을 경우, 프로세스 간의 메모리 공유가 일어나지 않기 때문에 정확한 현재의 상태를 반영하지 못하게 됩니다.
가령 A와 B가 접속하였을 때, 각각 다른 프로세스에서 서로의 존재를 확인할 수 없습니다. 그렇기 떄문에 큰 문제가 발생합니다.
let usersList = [];
io.on('connection', (socket) => {
socket.on('LOGIN', (userId: number) => {
usersList = usersList.push(userId);
});
socket.on('LOGOUT', (userId: number) => {
usersList = usersList.filter(el => el !== userId);
});
});
이 문제를 해결하기 위해 저희는 여러 프로세스 사이에 공유되는 자원들을 Redis를 통하여 관리하였습니다.
저희의 서비스에서 총 2가지 부분에서 redis를 사용할 계획입니다.