Database

[MongoDB] replica sets 설정

춘햄 2024. 3. 15. 11:07

 만들고 있는 어플 기능 중에 실시간으로 데이터의 변경 사항을 뿌려줘야 하는 기능이 필요한데, push & pull 방식보다는 DB의 실시간 변경 사항을 추적하여 ws으로 뿌려주는 게 낫겠다 싶어서, 어떻게 해야 하나... 하고 고민을 좀 하고 있었다. 

 

node의 mongoose에서 마침 해당 기능을 제공하고 있길래, "이거야! 당장 사용해보자!!!!"하고 바~로 예제 코드를 주어왔다.

 

◎ express.js의 main code

#!/usr/bin/env node

/**
 * Module dependencies.
 */
const app = require('../app');
const debug = require('debug')('happiness-stock-rest-api:server');
const http = require('http');
const mongoose = require('mongoose');
const initializeWebSocketServer = require('../ws/websocketServer');
/**
 * Get port from environment and store in Express.
 */

const port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

const server = http.createServer(app);
const wss = initializeWebSocketServer(server);
/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* DB의 변경 사항 추적(users Collection의 price Record)
* */

const db = mongoose.connection;

db.once('open', () => {
 console.log('Database connected for WebSocket');

 const changeStream = db.collection('users').watch([
   { $match: { 'updateDescription.updatedFields.price': { $exists: true } } }
 ]);

 changeStream.on('change', (change) => {
   console.log('Change detected on users collection:', change);
   // 모든 연결된 클라이언트에 변경사항 전송
   wss.clients.forEach(client => {
     if (client.readyState === WebSocket.OPEN) {
       client.send(JSON.stringify(change));
     }
   });
 });
});

wss.on('connection', function connection(ws) {
  console.log('Client connected');
});

 

 신나서 예제 코드를 짜고 실행할 때까지만 해도 몰랐지... 이걸 5시간을 붙잡고 있을줄은....

 

위와 같이 설정을 해주고, 서버를 딱! 켜니, 무슨 이상한 에러가 떴다.

 

MongoServerError: The $changeStream stage is only supported on replica sets

 

? 변경을 추적하는 changeStream 연산자는 replica sets 환경에서만 지원한다는 뜻 같긴 한데...


replica sets

 

그럼 replica sets는 뭔데? 하고 좀 찾아보니까 실시간으로 backup을 만들면서 DB 인스턴스 하나가 죽어도 다른 인스턴스가 살아 있으면서 서비스를 계속할 수 있도록 하는.. 그냥 클러스터링 개념인 거 같다.

 

여기서 2가지 선택지가 생겼다. 

 

그냥 조~금 비효율적이지만 쉬운 방식(초 간격으로 실시간 데이터를 ws에 담아 보내기 혹은 push & pull)으로 진행을 하거나, 레플리카 환경을 구축하거나였는데,

 

연습할 겸 레플리카 환경을 내 로컬 PC 한 대에 구축해 보기로 했다.


1. data 저장 디렉터리와 log 저장 디렉터리 및 로그 파일 생성

 

기존에 사용하던 1개의 인스턴스 외에 동시에 동작할 2개의 인스턴스를 새로 만들어줘야 하는 것이기 때문에 각각의 인스턴스가 사용할 data 폴더와 log 파일을 생성해 줬다.

 

data: 

 - C:\data\rs0

 - C:\data\rs1

 - C:\data\rs1

 

logs: 

 - C:\Program Files\MongoDB\Server\7.0\log\mongod0.log

 - C:\Program Files\MongoDB\Server\7.0\log\mongod1.log

 - C:\Program Files\MongoDB\Server\7.0\log\mongod2.log


2. config 파일 작성

 

config 파일도 마찬가지로 기존 인스턴스가 사용하던 config 외에 각 인스턴스가 사용할 config 파일을 따로 생성하여, 각 인스턴스의 포트 및 데이터 디렉터리, 로그 파일 위치 등을 설정해줘야 한다.

 

◎C:\Program Files\MongoDB\Server\7.0\bin\mongod1.cfg

storage:
  dbPath: C:\data\rs1
 
systemLog:
  destination: file
  logAppend: true
  path:  C:\Program Files\MongoDB\Server\7.0\log\mongod1.log
 
net:
  port: 27016
  bindIp: 127.0.0.1
 
 # 레플리카 설정
 replication:
  replSetName: rs0

 

◎C:\Program Files\MongoDB\Server\7.0\bin\mongod2.cfg

storage:
  dbPath: C:\data\rs2
 
systemLog:
  destination: file
  logAppend: true
  path:  C:\Program Files\MongoDB\Server\7.0\log\mongod2.log
 
net:
  port: 27018
  bindIp: 127.0.0.1
 
 # 레플리카 설정
 replication:
  replSetName: rs0

 

◎ C:\Program Files\MongoDB\Server\7.0\bin\mongod3.cfg

storage:
  dbPath: C:\data\rs3
 
systemLog:
  destination: file
  logAppend: true
  path:  C:\Program Files\MongoDB\Server\7.0\log\mongod3.log
 
net:
  port: 27019
  bindIp: 127.0.0.1
 
 # 레플리카 설정
 replication:
  replSetName: rs0

 

주의할 점은 반드시 각 port는 다르게 설정되어 있어야 하되, replsetName은 동일하게 설정되어야 하나의 replica set으로 사용할 수 있다는 점이다.


3. authorization(선택 사항)

 

기존 인스턴스에서 authorization을 사용했다면, 활성화시켜 주면 되는데 주의할 점은 replica sets 환경에서 authorization을 사용하기 위해서는 다중 인스턴스들의 동기화? 를 위한 keyfile이 반드시 필요하다는 점이다.

 

keyfile은 본인이 원하는 위치에 생성하면 되며, 내용은 key로 사용할 비밀번호를 적어주면 된다. 

 

후에는 각 config 파일에 아래와 같이 보안 설정을 활성화해 주면 된다.

security:
  authorization: 'enabled'
  keyFile: C:\Program Files\MongoDB\Server\7.0\key\keyfile.txt

4. 각 인스턴스 실행

 

이제 설정은 모두 끝이 났으니, 각 인스턴스를 시작해 주자.

 

아래 명령어로 실행할 수 있는데, 이때 환경변수 설정이 안 되어 있다면 mongoDB path\bin 내에 있는 mongod.exe를 cmd에서 실행시켜 주면 된다.

 

이는 반드시 각각의 cmd창에서 해야 하며 cmd창을 종료하면 인스턴스도 같이 종료되니 주의하자.

 

mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod1.cfg"

 

mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod2.cfg"

 

mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod3.cfg"

5. replica sets 초기화

 

제일... 시간을 많이 뺏기고 멘털이 갈렸던 파트...ㅋㅋㅋ 사실 진짜 별 거 아닌 그냥 메인으로 사용할 인스턴스 하나에 mongo shell로 접속하여 초기화 명령만 해주면 된다.

 

그러나... 나는 bin 폴더 안에 mongos.exe 가 mongo shell인 줄 알고 도대체가 왜!!!! replica sets 초기화된 인스턴스에만 접근할 수 있습니다.라고 뜨냐고!!!! 하면서 새벽 내내 극대노를 시전 했다...ㅋㅋㅋㅋㅋ

 

사실 mongos.exe 는 mongo shell이긴 한데, 이미 replica sets 설정이 된 인스턴스 세트만 사용이 가능한 그런... 쉘이었고, 진짜 mongo shell은 7.0 버전부터는 공홈에서 따로 다운을 받아서 사용해야 한다. (이런 건 미리 알려주면 참 좋겠다. 그렇지?)

 

아무튼, 여기에 접속하여 mongo shell을 다운로드하고 cmd에서 실행시킨 뒤에 메인으로 사용할 인스턴스를 하나 정하여 해당 포트로 접속을 한다.

 

(선택: 환경변수 설정이 귀찮다면...)

cd C:\Program Files\MongoDB\Server\mongosh-2.2.0-win32-x64\bin
.\mongosh --port 27016

 

(환경변수 좋-아)

mongosh --port 27016

 

이후에 아래와 같이 replica sets를 초기화해주면 된다.

rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27016" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
});

6. 서비스 설정 (선택 사항)

 

마지막으로 재부팅마다 replica sets를 초기화해 줄 필요는 없지만, 각 인스턴스는 켜줘야 하기 때문에 해당 인스턴스들을 서비스로 만들어서 자동으로 시작이 되도록 설정하자.

 

mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod1.cfg" --install --serviceName "MongoDB1" --serviceDisplayName "MongoDB Replica Set Instance 1"
mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod2.cfg" --install --serviceName "MongoDB2" --serviceDisplayName "MongoDB Replica Set Instance 2"
mongod --config "C:\Program Files\MongoDB\Server\7.0\bin\mongod3.cfg" --install --serviceName "MongoDB3" --serviceDisplayName "MongoDB Replica Set Instance 3"

 

net start MoggoDB1
net start MoggoDB2
net start MoggoDB3

  

 이렇게 하면 replica sets 설정이 모두 끝이 난다. 

 

주의할 점은 해당 replica set은 테스트 & 개발용 도로 1개의 PC에 설치했지만 일반적으로는 각자 다른 server에 설치된 인스턴스들이 sets로 설정이 되어야 한다는 점이다.

 

무튼, 이렇게 설정을 하고 Connection을 붙어보면...

 

약, 6시간 만에 성공한...ㅋㅋㅋㅋ replica sets이 정상 동작하는 걸 확인할 수 있다... 허허...