Mongodb replicaset 으로 구성하여 사용하던 도중에 .. master 이 올라가지 않는 문제가 발생했다.

 

시스템이 비정상 셧다운된이후였는데. 올라가는 로그를 보니 

 

쉽게 해결되긴 어려워 보였다..

 

slave 는 정상 구동중인 상태였으므로.

 

그냥 master 을 삭제하고 다시 구성하면 되지 않을까싶어 해보았다.

 

 

mongo --port 26026 -u "id" -p "Password" --authenticationDatabase "admin"

salve 권한이 있는 포트로 접속한후 

rs.remove("localhost:26016")

과감히 삭제이후 다시새로운 곳에 다음과 같이 폴더를 생성한후

mkdir /var/lib/mongo/master
mkdir /var/lib/mongo/master/log

 conf  파일을 생성

# mongod.conf

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb/master
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/lib/mongodb/master/log/mongod.log

# network interfaces
net:
  port: 26016
  bindIp: 127.0.0.1

processManagement:
  timeZoneInfo:  /usr/share/zoneinfo
  fork: true 

replication:
  replSetName: "replica"

 

 

 

이후 mongodb 에 접속하여 새로운 master 다시 추가.

rs.add( { _id:0,host:"127.0.0.1:26016",priority:2} )

 

이렇게하면 모두 완료된다..

 

 

replicaset 구성방법은 이전글을 참고하시면 됩니다.

 

https://ospetabyte.tistory.com/571?category=758411

 

MongoDB 설치 MongoDB replicaset 설정

우분투 18.04 기준으로 되어있습니다.  1. MongoDB 설치 wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add - sudo apt-get install gnupg wget -qO - https://www.mongodb.org/..

ospetabyte.tistory.com

 

 

mongoDB 백업하기(dump)

mongodump -u user_name -p user_password --authenticationDatabase=admin --out /data/backup/ --db db_name --collection collection_name --gzip 

# 옵션 설명
-u : 계정명
-p : 계정의 비밀번호
--authenticationDatabase=admin : 인증
--host : 원격 시 IP 주소 및 포트 
--out : Dump 받을 폴더 경로
--db : Dump 받을 DB 선택 (미작성 시 DB 전체)
--collection : Dump 받을 collection(table) 선택  (미작성 시 Collection 전체)
--gzip : Dump 파일 확장자

 

mongoDB 복구하기(Restore)

mongorestore -u user_name -p user_password --host 192.168.0.100:8000 --authenticationDatabase=admin --gzip --db db_name --collection collection_name /data/backup/collection.bson.gz --drop

# 옵션 설명
-u : 계정명
-p : 계정의 비밀번호
--authenticationDatabase=admin : 인증
--host : 원격 시 IP 주소 및 포트
--db : Restore 할 DB 선택 
--collection : Restore 할 collection(table) 선택
--gzip : Restore 파일 확장자
--drop : 백업에 없는 collection 삭제



 

$currentDate 필드 값을 날짜 또는 시간 소인으로 현재 날짜로 설정합니다.
$inc 필드 값을 지정된 양만큼 증가시킵니다.
$min 지정된 값이 기존 필드 값보다 작은 경우에만 필드를 업데이트하십시오.
$max 지정된 값이 기존 필드 값보다 큰 경우에만 필드를 업데이트합니다.
$mul 필드 값에 지정된 양을 곱합니다.
$rename 필드 이름을 바꿉니다.
$set 문서에서 필드의 값을 설정합니다.
$setOnInsert 업데이트로 인해 문서가 삽입되는 경우 필드 값을 설정합니다. 기존 문서를 수정하는 업데이트 작업에는 영향을 미치지 않습니다.
$unset 문서에서 지정된 필드를 제거합니다.

 

우분투 18.04 기준으로 되어있습니다.

 

 1. MongoDB 설치

 

wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -

sudo apt-get install gnupg

wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list

 

sudo apt-get update

 

sudo apt-get install -y mongodb-org=4.2.3 mongodb-org-server=4.2.3 mongodb-org-shell=4.2.3 mongodb-org-mongos=4.2.3 mongodb-org-tools=4.2.3

 

위와같이 설치할경우 리눅스에 설치된 디렉토리는

 

 

2 . 폴더 생성 및 conf 파일 생성 

 

실행파일 

/usr/bin/mongo 

 

설치경로

/var/lib/mongo

 

설치경로에 3가지의 폴더와 파일을 만들어야한다.

 

mkdir /var/lib/mongo/master
mkdir /var/lib/mongo/master/log

mkdir /var/lib/mongo/slave1
mkdir /var/lib/mongo/slave1/log

mkdir /var/lib/mongo/arbiter
mkdir /var/lib/mongo/arbiter/log

 

 

그다음 위의 경로에 아래의 conf 파일을 각각 생성해준다. 

 

 

 

master 파일.

# mongod.conf

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb/master
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/lib/mongodb/master/log/mongod.log

# network interfaces
net:
  port: 26016
  bindIp: 127.0.0.1

processManagement:
  timeZoneInfo:  /usr/share/zoneinfo
  fork: true 

replication:
  replSetName: "replica"

 

slave 파일.

# mongod.conf

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb/slave1
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/lib/mongodb/slave1/log/mongod.log

# network interfaces
net:
  port: 26026
  bindIp: 127.0.0.1

processManagement:
  timeZoneInfo: /usr/share/zoneinfo
  fork: true 

replication:
  replSetName: "replica"

 

arbiter

# mongod.conf

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb/arbiter
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/lib/mongodb/arbiter/log/mongod.log

# network interfaces
net:
  port: 26036
  bindIp: 127.0.0.1

processManagement:
  timeZoneInfo: /usr/share/zoneinfo
  fork: true 

replication:
  replSetName: "replica"

 

 

3. 실행 및 종료

 

 

 

실행명령어

/usr/bin/mongod --config /var/lib/mongodb/master/master.conf 
/usr/bin//mongod --config /var/lib/mongodb/slave1/slave1.conf 
/usr/bin/mongod --config /var/lib/mongodb/arbiter/arbiter.conf 

 

종료명령어 (종료시에만 입력)

/usr/bin/mongod --shutdown --config /var/lib/mongodb/arbiter/arbiter.conf 
/usr/bin/mongod --shutdown --config /var/lib/mongodb/slave1/slave1.conf 
/usr/bin/mongod --shutdown --config /var/lib/mongodb/master/master.conf 

 

다음과같은 Shell 이 뜨게되면 아래와 같이 입력한다.

rsconf ={_id : "replica", members:[{_id:0,host:"127.0.0.1:26016",priority:2},{_id:1,host:"127.0.0.1:26026",priority:1},{_id:2,host:"127.0.0.1:26036",priority:1,arbiterOnly:true}]};

 

이렇게 하면 셋팅완료

 

 

아래부분은 보안부분이다.


#외부 접속을 허용하기위해선 bindIp : 0.0.0.0 로 설정해야 한다.

 

#계정생성 PRIMARY 로 접속하여

> use admin
> db.createUser({
    user: 'adminId',
    pwd: 'password',
    roles: ['root']
})

 

## 암호화 설정방법.

Linux에서 mongodb 키 파일을 작성하고 모드가 600그대로있는 모든 DB 서버에 복사하십시오 .

openssl rand -base64 741 > mongodb.key

chmod 600 mongodb.key

mongod.conf

security:
    authorization: enabled
    keyFile: /var/lib/mongodb/mongodb.key

 

 

MongoDB 2.2 버전부터 collection의 index에 TTL을 지정하여,

시간이 경과하면 자동으로 삭제해주는 기능이 있음.


일단 동작원리만 간단히 설명하자면 아래와 같다.

1. TTL을 적용할 컬렉션에 expire time을 저장할 index를 만드는데, 옵션에 expireAfterSeconds 가 들어가야 함.

2. 해당 컬렉션에 데이터를 넣을 때, 만들어둔 TTL용 index 필드에는 data/time object값이 들어가야 함.

3. primary 머신에서 백그라운드로 TTL이 다 된 document를 삭제해주는 task가 돌면서 지워줌.



아래의 단서조건이 붙는다.

* TTL용 index 필드는 반드시 date BSON 타입의 데이터만 저장해야 함.

* _id 필드를 이용할 수 없다.

* 이미 index가 걸려있는 필드에 TTL constraints 부여 불가.

* 복합인덱스는 안됨.

* 만약 TTL용 필드가 배열이고 각 배열원소들이 date BSON 타입의 데이터가 저장되어 있다면 자동삭제 task는 해당 원소 중 가장 초기 date/time 값을 기준으로 삭제.

* capped collection에는 사용할 수 없음.

* 자동삭제 task는 60초에 한번씩 동작한다. 그러므로 60초 이하로 지정한 expire time은 정확한 삭제시간을 보장할 수 없다. (=오차범위 60초)



[예제]

// TTL을 적용하고자 하는 컬렉션에 TTL용 index 생성

// 예제에선 logs DB의 mylog collection이라고 가정함.

mongos> use logs

mongos> db.mylog.ensureIndex({expire:1}, {expireAfterSeconds:3600}) // TTL = 1시간


// expire값을 현재시각으로 넣은 이 데이터는 1시간 후에 자동으로 삭제됨

mongos> db.mylog.insert({name:'mytest', expire: new Date()}) 



출처: http://bloodguy.tistory.com/entry/MongoDB-document에-expire-time-적용하기-expire-TTL [Bloodguy]

1. 질의 스크립트를 생성해주세요.
query.js

1
2
3
4
5
6
7
var dbname = 'log';
var db = db.getSiblingDB(dbname);
var cursor = db.ItemLogData.find();
 
while(cursor.hasNext()) {
 printjson(cursor.next());
}

query.js의 내용중에 dbname과 collection, 질의 내용을 본인에 맞게 수정해주세요.

2 mongo 명령어를 사용해서 질의 스크립트를 실행해주시면 됩니다.
$mongo –quiet query.js > result.txt

Mongo DB를 사용하여 예약 작업 구현하기

등록할 예약 작업의 성격

  • 특정 일시에 실행되어야 하는 작업
  • ex) 2015.11.31 09:00 OO에게 메일 발송

 

스케쥴 서버의 조건

  • 예약 작업이 많아 졌을 경우, scale-out 확장이 가능해야 함

예약 작업 저장을 위한 스토리지로 Mongo DB를 선택했으며, Collection 구조는 아래와 같이 정의하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// collection
var reservedTask{
    _id: xxx, //taskId
    cmd: OOOO, // 실행할 작업
    contents: {name:'aasfdsadf'} // 작업에 필요한 내용 Object Type
    reserved: YYYY-MM-DDTHH:MM:SS, // 실행될 시간
    registered: YYYY-MM-DDTHH:MM:SS, // 등록한 시간
    status: REQUEST // 작업 실행 상태
}
// task 등록
db.reservedTasks.save({
    cmd: 'sendMail',
    registered: new Date(),
    reserved: new Date('2015-11-13T09:00:00'),
    contents: {
        to: 'abc@def.com',
        body: '.......'
    },
    status: 'REQUEST'
});

구현할 기능은 아래와 같다

  1. 예약 작업 등록
  2. 실행할 작업을 DB로 부터 읽어 옴.
  3. 실행할 작업이 있을 경우, 상태를 실행으로 변경하고 예약 작업을 실행
  4. 실행을 완료한 작업은 완료로 처리

여러 서버에서 스캐쥴러가 동작할 경우 2, 3, 4번의 과정에서 동일한 작업이 여러번 실행되는 문제가 발생할 수 있다. 만약 서버 A가 2, 3번 과정을 실행중일때, 서버 B가 2번 과정을 실행하게 되면, 동일한 작업이 두번 실행되게 된다. 이러한 문제는 MongoDB로 구현할때 findAndModify 연산을 이용하여 해결할 수 있다.

findAndModify 연산을 이용한 예약 작업 읽기

1
2
3
4
5
db.reservedTasks.findAndModify({
    query: { reserved: new Date('2015-11-13T09:00:00'), status: 'REQUEST' },
    update: { $set: { status: 'RUNNING' } },
    new: true
});

위의 쿼리를 수행하게 되면 읽기와 쓰기가 동시에 수행이 되어, 여러 서버에서 동시에 수행이 되더라도 동일한 작업이 여러번 실행되는 것을 막을 수 있다. 또한 이후 작업이 결과에 따라 status 값을 조정함으로써 완료/실패 처리가 가능하다.

문제점
findAndModify를 사용할 경우 예약된 작업을 하나씩 실행해야 한다. 만약 1000개의 예약된 작업이 있을 경우 1000번 위의 과정을 수행해야 한다. 이러한 제한은 findAndModify가 하나의 document에 대해서만 update가 가능하기 때문이다. 이를 위해서는 다른 해결책이 필요하다.

 

이중 확인을 사용한 방법(transId 추가)

  1. 실행할 작업을 DB로 부터 읽어 옴.
  2. DB로 부터 읽어 온 작업을 업데이트(상태: 실행중, transId:’transactionNum’)
  3. transId가 ‘transactionNum’인 작업을 읽음
  4. 작업 완료후 처리한 작업을 완료로 처리
1
2
3
4
5
6
7
8
9
10
11
db.reservedTasks.find({ reserved: new Date('2015-11-13T09:00:00'),
status: 'REQUEST'
}).limit(100) // ID 읽음.
db.reservedTasks.update( {_id: {$in: [/* 앞에서 읽어온 id 리스트 */]},
        status: 'REQUEST'},// 읽은 ID중 아직까지 REQUEST 상태인 것만,
    {$set: {status: 'RUNNING',
                transId: 'transactionNum'}},
// transaction Num을 부여하고, 실행중 상태로
    {multi: true}
)
db.reservedTaks.find({transId: 'transactionNum'})// 실제로 실행할 작업을 다시 읽음

위 과정중 1 번 쿼리의 필요성에 대해 고민해 볼 필요가 있다. 1번 과정은 실제로 최대 N개로 한번의 작업 횟수를 제한하는데 필요하다. 이러한 제한이 필요 없을 경우 1번 과정은 생략 가능하다


+ Recent posts