[MongoDB] replica sets 설정
만들고 있는 어플 기능 중에 실시간으로 데이터의 변경 사항을 뿌려줘야 하는 기능이 필요한데, 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이 정상 동작하는 걸 확인할 수 있다... 허허...