지난 블로그에서 Replica Set을 Archive 목적으로 StandAlone 으로 변경 후, 보안 이슈로 인해 Version Upgrade 도중 Local DB 관련하여 에러가 발생하여 Trouble Shooting 을 진행 하였습니다.

 

그래서 이번에는 Replica Set에서 StandAlone 으로 문제 없이 깨끗?하게 변경하는 부분에 대하여 테스트를 진행 하였습니다.

이번 테스트를 진행하면서 느낀점은, 몇몇 외국 블로그에 나온 내용들을 보면, 인증을 사용안하는 것일까 라는 의문이 생겼습니다. 왜냐하면 이번 테스트를 진행 하면서 인증(authorization) 로 인해 Local DB가 삭제가 되지 않는 이슈가 발생하였기 때문입니다.

 

글보다는 제가 진행한 방법에 대해서 이미지와 방법을 보시면 쉽게 변경 가능할 것 같습니다.

 

진행 방법

  1. Replica Set 멤버들 제거 (primary는 제거되지 않습니다. 물론 제거하는 방법도 존재-맨 하단 리플리케이션-멤버-재설정 참고)

  2. mongod.conf 에서 replication / security 모두 주석 처리 후 재 시작
  3. local DB 삭제 진행
  4. mongod.conf 에서 security 모두 원복 후 재 시작
  5. Local DB에서 startup_log collection 만 생성 되었는지 확인 및 방금 startup 로그만 존재하는 지도 확인
  6. 정상적으로 StandAlone DB 변경 완료
# 1. 멤버 삭제
# Primary 에서 진행되며, 각 멤버들만 삭제가 가능
# 기본형태 : rs.remove("host명:port")

replSet:PRIMARY> rs.remove("127.0.0.1:57018")
replSet:PRIMARY> rs.remove("127.0.0.1:57019")
----------------------------------------------------------------------------
# 2. config 수정 및 mongodb 재시작

$ vi /etc/mongod.conf

systemLog:
   destination: file
   path: /data/mongo_test/log/mongo.log
...
net:
   bindIp: 0.0.0.0
   port: 57017

#replication:
#   replSetName: "replSet"

#security:
#  authorization: enabled
#  keyFile: /data/mongo_test_repl.key


$ systemctl restart mongod.service
----------------------------------------------------------------------------
# 3. local DB 삭제 진행
$ mongo --port 57017
# 현재 standalone 으로 올라왔으며, security를 주석처리하였기 때문에 인증 없이 접속
> use local
> db.dropDatabase()

# 정상적으로 local DB가 삭제 된 것을 확인 가능
----------------------------------------------------------------------------
# 4. mongod.conf 에서 security 모두 원복 후 재시작

$ vi /etc/mongod.conf

systemLog:
   destination: file
   path: /data/mongo_test/log/mongo.log
...
net:
   bindIp: 0.0.0.0
   port: 57017

#replication:
#   replSetName: "replSet"

security:
  authorization: enabled
  keyFile: /data/mongo_test_repl.key
----------------------------------------------------------------------------
# 5. Local DB 확인 
$ mongo admin -uadmin -p --port 57017
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
> 
> use local
switched to db local

> db.startup_log.find().pretty()

----------------------------------------------------------------------------
# 6. 완료

Replica Set 멤버 삭제

Replica Set member 들
Replica Set 멤버 제거

Stand Alone 형태의 단독 Mongodb 의 초기 모습

  • 단순 local 내에는 startup_log collection 만 존재하며, 해당 collection 에는 startup 에 대한 로그들이 존재

 

Authorization 상태에서 Local DB삭제 시 다음과 같은 에러 발생

  • 참고로, 4.2 부터는 writeConcern이 majority 라서 majority를 1로 주고 진행 하더라도 에러 발생하는 것을 확인 가능 (writeConcern의 문제가 아님)

그외

  • 일부 블로그에서는 각 collection 마다 삭제하는 것도 있었는데, 실제로 삭제가 되는 collection 이 있는가 하면, 반대로 동일하게 Auth 로 인해서 삭제가 되지 않는 collection  도 존재 하는 것을 확인

 


아래 내용은 replication 재설정 관련하여 도움을 받았던 블로그 입니다.

이 부분도 실제로 진행하였는데, 자료를 남기지 않아 추후 테스트하여 공유 하도록 하겠습니다.

출처: https://knight76.tistory.com/entry/mongodb-레플리케이션-멤버-재설정하기 [김용환 블로그(2004-2020):티스토리]

 

그 외 참고

https://9to5answer.com/how-to-convert-a-mongodb-replica-set-to-a-stand-alone-server

https://adelachao.medium.com/downgrade-mongodb-replica-set-to-a-standalone-node-fc50d58addf2

https://medium.com/@cjandsilvap/from-a-replica-set-to-a-standalone-mongodb-79fda2beaaaf

 

반응형

기존 Mongodb Upgrade 와 비슷한 문서이나, Replica set 에서 Archive 목적으로 StandAlone 으로 변경 후 Upgrade 진행 중 발생한 이슈에 대한 문서 입니다.

Replica Set using rpm upgrade (3.4 to 4.2)

 

[MongoDB] 3.4 to 4.2 upgrade (rpm)

RPM 으로 설치된 Replica Set 에 대해 Upgrade 방법 입니다. 기본적으로 Downtime 을 가지고 진행 합니다. Secondary 를 standalone 형태로 변경 후, 업그레이드 한다면 Downtime 없이 가능하며, 실제로 진행한 결..

hyunki1019.tistory.com

  • mongod.conf 에서 replica set 제거
  • 해당 상태에서 stand alone 형태로 startup 진행
  • Version Upgrade 진행

 

Repo 추가 및 설정

  • 하나의 yum Repository 로도 가능하나, 별도의 repository 추가하여 진행 하였습니다. (별다른 이유는 없습니다.)
  • 여기 까지는 위의 문서와 동일
cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-3.6.repo 
$ cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-4.0.repo 
$ cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-4.2.repo
# 3.6 추가
$ vi /etc/yum.repos.d/mongodb-org-3.6.repo 

[mongodb-org-3.6] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/3.6/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc

# 4.0 추가
$ vi /etc/yum.repos.d/mongodb-org-4.0.repo 

[mongodb-org-4.0] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.0/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc

# 4.2 추가
$ vi /etc/yum.repos.d/mongodb-org-4.2.repo 

[mongodb-org-4.2] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.2/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc

# yum 초기화 진행
$ yum clean all 
$ yum update list

 

MongoDB Replica Set to Standalone 

  • 단순히 conf 파일에서 replication 관련 항목을 주석 후 진행 (<- 원인)
$ vi /etc/mongod.conf 
# 아래 replication 내역 주석 처리
...
#replication:
#   replSetName: "replSet"
...

$ systemctl stop mongod.service

 

MongoDB 3.4 to 4.2 Upgrade 진행

  • 해당 문서를 보면서 upgrade 를 진행 한다면 4.0 까지만 upgrade 진행 후 아래 모든 내용의 글을 읽으신 후에 4.2 로 진행 하시기 바랍니다.!!!!!
############ 3.6 ############
# mongo 서버 종료
$ systemctl stop mongod.service

# yum 으로 update 진행
$ yum -y update mongodb-org-3.6.23

# mongodb 서버 시작
$ systemctl start mongod.service

# mongodb 접속 후 확인
$ mongo admin -uadmin -p

# 현재값 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

# 중요!!!# featureCompatibilityVersion 수정
> db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

# 정상적으로 변경되었는지 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

############ 4.0 ############
# mongo 서버 종료
$ systemctl stop mongod.service

# yum 으로 update 진행
$ yum -y update mongodb-org-4.0.27

# mongodb 서버 시작
$ systemctl start mongod.service

# mongodb 접속 후 확인
$ mongo admin -uadmin -p

# 현재값 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

# 중요!!!# featureCompatibilityVersion 수정
> db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } )

# 정상적으로 변경되었는지 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

############ 4.2 ############
# mongo 서버 종료
$ systemctl stop mongod.service

# yum 으로 update 진행
$ yum -y update mongodb-org-4.2.18

# mongodb 서버 시작
$ systemctl start mongod.service
############################### 에러 발생하면서 startup 이 안되는 이슈 발생

 

발생 이슈

  • 전제 : 기존 Replica Set에서 StandAlone 형태로 변경 후 버전 업그레이드 진행
    • cf) Replica set 에서 업그레이드 진행시 다음과 같은 문제는 발생하지 않음
  • 문제 : 4.0 에서 4.2로 업그레이드 진행 후 startup 진행 시 startup 이 되지 않는 이슈
  • 에러 내역 (로그)
    • 주요 에러 내역
      • shutting down with code:100
      • exception in initAndListen: Location40415: BSON field 'MinValidDocument.oplogDeleteFromPoint' is an unknown field., terminating
$ systemctl start mongod.service
-> error 발생하면서 startup 이 되지 않음

mongod.log

2022-07-01T17:02:59.368+0900 I  CONTROL  [main] ***** SERVER RESTARTED *****
2022-07-01T17:02:59.370+0900 I  CONTROL  [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
2022-07-01T17:02:59.373+0900 W  ASIO     [main] No TransportLayer configured during NetworkInterface startup
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] MongoDB starting : pid=36325 port=27017 dbpath=/data/mongo/repl_0 64-bit host=192.168.0.1
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] db version v4.2.21
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] git version: b0aeed9445ff41af57e1f231bce990b3
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.2k-fips  26 Jan 2017
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] allocator: tcmalloc
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] modules: none
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] build environment:
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten]     distmod: amazon2
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten]     distarch: x86_64
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten]     target_arch: x86_64
2022-07-01T17:02:59.373+0900 I  CONTROL  [initandlisten] options: { config: "/etc/mongod.conf", net: { bindIp: "0.0.0.0", port: 27017 }, processManagement: { fork: true, pidFilePath: "/var/run/mongodb/mongod.pid" }, security: { authorization: "enabled" }, storage: { dbPath: "/data/mongo/repl_0", journal: { enabled: true } }, systemLog: { destination: "file", logAppend: true, path: "/var/log/mongodb/mongod.log", quiet: true } }
2022-07-01T17:02:59.373+0900 I  STORAGE  [initandlisten] Detected data files in /data/mongo/repl_0 created by the 'wiredTiger' storage engine, so setting the active storage engine to 'wiredTiger'.
2022-07-01T17:02:59.373+0900 I  STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=7360M,cache_overflow=(file_max=0M),session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000,close_scan_interval=10,close_handle_minimum=250),statistics_log=(wait=0),verbose=[recovery_progress,checkpoint_progress],
2022-07-01T17:02:59.914+0900 I  STORAGE  [initandlisten] WiredTiger message [1656662579:914502][36325:0x7ff6d143a080], txn-recover: Recovering log 71644 through 71645
2022-07-01T17:02:59.985+0900 I  STORAGE  [initandlisten] WiredTiger message [1656662579:985670][36325:0x7ff6d143a080], txn-recover: Recovering log 71645 through 71645
...
2022-07-01T17:03:00.247+0900 I  STORAGE  [initandlisten] WiredTiger message [1656662580:247926][36325:0x7ff6d143a080], txn-recover: Set global recovery timestamp: (0, 0)
2022-07-01T17:03:00.258+0900 I  RECOVERY [initandlisten] WiredTiger recoveryTimestamp. Ts: Timestamp(0, 0)
2022-07-01T17:03:00.260+0900 I  STORAGE  [initandlisten] No table logging settings modifications are required for existing WiredTiger tables. Logging enabled? 1
2022-07-01T17:03:00.267+0900 I  STORAGE  [initandlisten] Starting OplogTruncaterThread local.oplog.rs
2022-07-01T17:03:00.267+0900 I  STORAGE  [initandlisten] The size storer reports that the oplog contains 44774827 records totaling to 53269933556 bytes
2022-07-01T17:03:00.267+0900 I  STORAGE  [initandlisten] Sampling the oplog to determine where to place markers for truncation
2022-07-01T17:03:00.269+0900 I  STORAGE  [initandlisten] Sampling from the oplog between Jun 12 09:53:56:57 and Jun 30 10:45:36:1 to determine where to place markers for truncation
2022-07-01T17:03:00.269+0900 I  STORAGE  [initandlisten] Taking 992 samples and assuming that each section of oplog contains approximately 451255 records totaling to 536871395 bytes
2022-07-01T17:03:00.743+0900 I  STORAGE  [initandlisten] Placing a marker at optime Jun 12 13:10:49:4
2022-07-01T17:03:00.743+0900 I  STORAGE  [initandlisten] Placing a marker at optime Jun 12 17:58:42:4
....
2022-07-01T17:03:00.743+0900 I  STORAGE  [initandlisten] Placing a marker at optime Jun 30 08:04:48:175
2022-07-01T17:03:00.743+0900 I  STORAGE  [initandlisten] WiredTiger record store oplog processing took 475ms
2022-07-01T17:03:00.744+0900 I  STORAGE  [initandlisten] Timestamp monitor starting
2022-07-01T17:03:00.771+0900 I  STORAGE  [initandlisten] exception in initAndListen: Location40415: BSON field 'MinValidDocument.oplogDeleteFromPoint' is an unknown field., terminating
2022-07-01T17:03:00.771+0900 I  REPL     [initandlisten] Stepping down the ReplicationCoordinator for shutdown, waitTime: 10000ms
2022-07-01T17:03:00.771+0900 I  SHARDING [initandlisten] Shutting down the WaitForMajorityService
2022-07-01T17:03:00.771+0900 I  NETWORK  [initandlisten] shutdown: going to close listening sockets...
2022-07-01T17:03:00.771+0900 I  NETWORK  [initandlisten] Shutting down the global connection pool
2022-07-01T17:03:00.771+0900 I  STORAGE  [initandlisten] Shutting down the FlowControlTicketholder
2022-07-01T17:03:00.771+0900 I  -        [initandlisten] Stopping further Flow Control ticket acquisitions.
2022-07-01T17:03:00.771+0900 I  STORAGE  [initandlisten] Shutting down the PeriodicThreadToAbortExpiredTransactions
2022-07-01T17:03:00.771+0900 I  STORAGE  [initandlisten] Shutting down the PeriodicThreadToDecreaseSnapshotHistoryIfNotNeeded
2022-07-01T17:03:00.771+0900 I  REPL     [initandlisten] Shutting down the ReplicationCoordinator
2022-07-01T17:03:00.771+0900 I  SHARDING [initandlisten] Shutting down the ShardingInitializationMongoD
2022-07-01T17:03:00.771+0900 I  REPL     [initandlisten] Enqueuing the ReplicationStateTransitionLock for shutdown
2022-07-01T17:03:00.771+0900 I  -        [initandlisten] Killing all operations for shutdown
...
2022-07-01T17:03:01.196+0900 I  STORAGE  [initandlisten] WiredTiger message [1656662581:196670][36325:0x7ff6d143a080], txn-recover: Set global recovery timestamp: (0, 0)
2022-07-01T17:03:01.335+0900 I  STORAGE  [initandlisten] shutdown: removing fs lock...
2022-07-01T17:03:01.335+0900 I  -        [initandlisten] Dropping the scope cache for shutdown
2022-07-01T17:03:01.335+0900 I  CONTROL  [initandlisten] now exiting
2022-07-01T17:03:01.335+0900 I  CONTROL  [initandlisten] shutting down with code:100

 

해결 방안

  • 4.0 Downgrade 진행 및 local DB의 replset.minvalid 컬렉션의 oplogDeleteFromPoint 필드 unset 진행
# 4.0 Downgrade 진행
$ yum -y downgrade mongodb-org-4.0.27

# mongodb startup 진행
$ systemctl start mongod.service

# mongodb 접속 후 확인
$ mongo admin -uadmin -p

# local 에서 replset.minvalid Collection 의 oplogDeleteFromPoint 필드 $unset 진행
> use local
switched to db local

> db.replset.minvalid.find({}).pretty ();
{
        "_id" : ObjectId("5ec3b7c56db7b066b3f5d5e3"),
        "ts" : Timestamp(1643225280, 1),
        "t" : NumberLong(7),
        "oplogDeleteFromPoint" : Timestamp(0, 0)
}

# update 진행 검색 조건은 _id 결과로 $unset 진행
> db.replset.minvalid.update(
...  { "_id" : ObjectId("5ec3b7c56db7b066b3f5d5e3")},
...    { $unset: { oplogDeleteFromPoint: ""} }
... );
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

# 해당 필드 값 확인
> db.replset.minvalid.find({}).pretty ();
{
        "_id" : ObjectId("5ec3b7c56db7b066b3f5d5e3"),
        "ts" : Timestamp(1643225280, 1),
        "t" : NumberLong(7)
}
> exit

# 이후 다시 mongodb 4.2 upgrade 진행
# mongo 서버 종료
$systemctl stop mongod.service

# yum 으로 update 진행
yum -y update mongodb-org-4.2.18

# mongodb 서버 시작
$ systemctl start mongod.service

# mongodb 접속 후 확인
$ mongo admin -uadmin -p

# 현재값 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

# 중요!!!# featureCompatibilityVersion 수정
> db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } )

# 정상적으로 변경되었는지 확인
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

 

발생 원인

  • Replica set 을 정상적으로 삭제 하지 않고 단순 config 파일에서 수정 후 진행하다가 발생한 이유
  • mongodb 4.2에서 MinValidDocument.oplogDeleteFromPoint dependency (예상)

 

발생 방지 방법

  • MongoDB Replica set 에서 StandAlone 으로 변경 시 정상적인 방법으로 진행
# 1. 모든 Secondary 삭제 진행
repl_set:PRIMARY> rs.remove("Secondary 호스트 이름:27017")
repl_set:PRIMARY> rs.remove("Arbiter 호스트 이름:27018")

# 2. config 파일에서 replication 주석 처리 또는 제거
$ vi /etc/mongod.conf
...
#replication:
#   replSetName: "replSet"
...

# 3. mongodb 재시작(Primary)
$ systemctl restart mongod.service

# 4. local database 삭제
# mongodb 접속 시 현재 standalone 상태
> use local
> db.dropDatabase()

# 5. mongodb 깔끔하게 확인차 재시작(Primary)
$ systemctl restart mongod.service

 

결론

  • Replica Set의 동작 방식 뿐만 아니라 각 DB(Local, admin 등)들의 역할에 대해서 다시 한번 공부가 필요
  • MongoDB에 대한 공부 공부 공부!!!

 

해당 문제를 해결하는 과정에 많은 도움을 주신 TechPM 박경배 팀장님에게 감사 인사 드립니다.

반응형
  • RPM 으로 설치된 Replica Set 에 대해 Upgrade 방법 입니다.
  • 기본적으로 Downtime 을 가지고 진행 합니다.
    • Secondary 를 standalone 형태로 변경 후, 업그레이드 한다면 Downtime 없이 가능하며, 실제로 진행한 결과 문제 없이 업그레이드 진행 하였습니다. 
    • 이 부분에 대해서는 별도로 문서는 만들지 않았습니다. 
  • PSA 구조로 진행하였으며, PSS 구조로 진행 한다면 Arbiter 업그레이드 대신 Secondary 진행한 그대로 대신 진행 하면 됩니다.
  • MongoDB 3.4 to 4.2 로 진행 합니다.
  • aws ec2 - amazon2 에서 진행 하였습니다.

 

Repo 추가 및 설정

  • 하나의 yum Repository 로도 가능하나, 별도의 repository 추가하여 진행 하였습니다. (별다른 이유는 없습니다.)
cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-3.6.repo 
$ cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-4.0.repo 
$ cp /etc/yum.repos.d/mongodb-org-3.4.repo /etc/yum.repos.d/mongodb-org-4.2.repo
# 3.6 추가
$ vi /etc/yum.repos.d/mongodb-org-3.6.repo 

[mongodb-org-3.6] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/3.6/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc

# 4.0 추가
$ vi /etc/yum.repos.d/mongodb-org-4.0.repo 

[mongodb-org-4.0] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.0/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc

# 4.2 추가
$ vi /etc/yum.repos.d/mongodb-org-4.2.repo 

[mongodb-org-4.2] 
name=MongoDB Repository 
baseurl=https://repo.mongodb.org/yum/amazon/2/mongodb-org/4.2/x86_64/ 
gpgcheck=1 
enabled=1 
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc

# yum 초기화 진행
$ yum clean all 
$ yum update list

 

MongoDB 3.6 Upgrade 진행

  • Secondary -> Arbiter -> Primary 순으로 진행 합니다.
############ Secondary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-3.6.23 

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 

# replica 접속 되었는지 확인 
repl_set:SECONDARY> rs.status()

############ Arbiter ############
# mongo 서버 종료 
$ systemctl stop mongod_arb.service 

# yum 으로 update 진행 
$ yum update mongodb-org-3.6.23 

# mongodb 서버 시작 
$ systemctl start mongod_arb.service 

# mongodb 접속 후 확인 
$ mongo --port 27018 

# replica 접속 되었는지 확인 
repl_set:ARBITER> rs.status()

############ Primary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-3.6.23 

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 
# replica 접속 되었는지 확인 
repl_set:PRIMARY> rs.status() 

############ 중요!!! ############
# featureCompatibilityVersion 수정 
repl_set:PRIMARY> db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } ) 
# 정상적으로 변경되었는지 확인 
repl_set:PRIMARY> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

 

 

MongoDB 4.0 Upgrade 진행

  • Secondary -> Arbiter -> Primary 순으로 진행 합니다.
############ Secondary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.0.27 

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 

# replica 접속 되었는지 확인 
repl_set:SECONDARY> rs.status()

############ Arbiter ############
# mongo 서버 종료 
$ systemctl stop mongod_arb.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.0.27 

# mongodb 서버 시작 
$ systemctl start mongod_arb.service 

# mongodb 접속 후 확인 
$ mongo --port 27018 

# replica 접속 되었는지 확인 
repl_set:ARBITER> rs.status()

############ Primary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.0.27 

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 
# replica 접속 되었는지 확인 
repl_set:PRIMARY> rs.status() 

############ 중요!!! ############
# featureCompatibilityVersion 수정 
repl_set:PRIMARY> db.adminCommand( { setFeatureCompatibilityVersion: "4.0" } ) 
# 정상적으로 변경되었는지 확인 
repl_set:PRIMARY> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

 

MongoDB 4.2 Upgrade 진행

  • Secondary -> Arbiter -> Primary 순으로 진행 합니다.
############ Secondary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.2.18

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 

# replica 접속 되었는지 확인 
repl_set:SECONDARY> rs.status()

############ Arbiter ############
# mongo 서버 종료 
$ systemctl stop mongod_arb.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.2.18

# mongodb 서버 시작 
$ systemctl start mongod_arb.service 

# mongodb 접속 후 확인 
$ mongo --port 27018 

# replica 접속 되었는지 확인 
repl_set:ARBITER> rs.status()

############ Primary ############
# mongo 서버 종료 
$ systemctl stop mongod.service 

# yum 으로 update 진행 
$ yum update mongodb-org-4.2.18

# mongodb 서버 시작 
$ systemctl start mongod.service 

# mongodb 접속 후 확인 
$ mongo admin -uadmin -p 
# replica 접속 되었는지 확인 
repl_set:PRIMARY> rs.status() 

############ 중요!!! ############
# featureCompatibilityVersion 수정 
repl_set:PRIMARY> db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } ) 
# 정상적으로 변경되었는지 확인 
repl_set:PRIMARY> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

 

  • 반복 작업이지만, MongoDB는 순차적으로 upgrade 하는 것이 권고 사항 입니다.
  • 또한, featureCompatibilityVersion 을 수정하지 않는 경우 다음 version upgrade 이후 startup 이 되지 않는 이슈가 발생 합니다.
  • 이 때, 이전 version으로 downgrade 이 후, featureCompatibilityVersion 수정 후 다시 업그레이드를 하게 되면 진행이 가능합니다.
    • 모든 upgrade 작업은 백업은 필수! 입니다.
    • 가령, 문제가 발생하여 repair 명령어를 이용하여 startup 을 하게 되면, 모든 collection repair 및 index rebuild 까지 진행 하기 때문에 데이터 size 가 작은 사이트에서는 크게 이슈가 발생하지 않겠지만, 저희처럼 테라바이트 단위라면 repair 시간을 예측 하기 힘든 상황이 발생 합니다. (6테라 size의 db를 repair 로 만 하루 넘어가도 끝나지 않아 포기하고 기존 ec2 snapshot 으로 복구 진행 하였습니다.)
  • 이후, 다른 글에서 upgrade 과정에서 MinValidDocument.oplogDeleteFromPoint is an unknown field 이슈에 대해 해결 방법을 공유 하도록 하겠습니다.
반응형
  1. 개요 및 아키텍처
    1. 개요
      1. 메모리 DB (높은 처리량 - Replication 읽기 및 쓰기, 대기 시간 등 높은 처리 가능)
      2. 레디스와 호환이 되며, 레디스 관련한 것들을 모두 사용 가능 (v6.2)
      3. Multi-AZ 를 지원하여 빠르게 failover 및 복구, 재시작이 가능
    2. 특징
      1. Primary / Replica 간의 강력한 일관성 보장
      2. ms 단위의 읽기,쓰기 지연시간 (클러스터당 최대 1억6천만 tps)
      3. redis 호환
      4. 빠른 데이터 복구 및 재시작 제공 (multi-az, transaction log )
      5. multi-az를 통한 자동 페일오버 및 노드 fail에 대한 감지 및  복구
      6. replication 및 shard를 이용한 노드 추가, scale out, scale up-down 가능
      7. primary 에 대한 read/write 일관성 보장 및 복제 노드에 대한 일관성 보장 가능(read / write concern으로 예상)
      8. 사용자 인증 및 네트워크 인증, 암호화 기능 제공
      9. s3로 자동 스냅샷 (최대 35일 - rds 와 동일)
      10. 하나의 클러스터로 최대 500개 노드 및 100tb 이상의 storage 지원(레플리카 포함)
      11. AWS KMS keys를 사용한 TLS 암호화(8번과 동일)
      12. Redis를 통한 사용자 인증 및 권한 부여(ACL)(8번과 동일)
      13. AWS Graviton2 인스턴스 유형 지원
      14. VPC, Cloudwatch, CloudTrail, AWS SNS 서비스와의 통합
      15. 완전 관리형 소프트웨어 패치 및 업그레이드 지원
      16. 관리 API를 위한 AWS IAM(Identity and Access Management) 통합 및 태그 기반 액세스 제어
    3. 주요 기능
      1. Cluster
        1. MemoryDB 서비스를 운영하는 하나 이상의 노드 모음 (서비스의 개념)
        2. Shard는 Memory DB Set 단위들의 모임으로 Cluster 내에 존재
          1. Noes ⊂ Shard ⊂ Cluster  = 서비스 DB
        3. Memory DB Set 에는 하나의 Primary 와 최대 5개의 Replica 노드들을 보유 가능
        4. Primary 는 read/write 가능하며, Replica node들은 only read 만 처리
        5. Primary 장애 시 replica node들 중 하나를 primary 로 승격
        6. cluster 생성 시 redis 버전을 지정
        7. cluster 내 Memory DB 기능
          1. cluster 추가
          2. cluster 수정
          3. cluster 스냅샷 가져오기
          4. cluster 삭제
          5. cluster 내 요소 보기
          6. cluster 에 비용 할당 태그 추가 / 삭제
      2. Nodes
        1. MemoryDB 구성 중 가장 작은 단위 (EC2 기반)
        2. 클러스터에 속하며, cluster 생성 시 정해진 버전의 엔진 기반
        3. 필요한 경우 클러스터의 노드를 다른 유형으로 up / down 가능
        4. 단독으로 up / down 가능은 체크 필요
      3. Shards
        1. 하나의 샤드에는 1~6개의 노드로 구성되며, primary 1개에 5개의 replica 로 구성
        2. MemoryDB Cluster는 항상 적어도 하나의 샤드로 구성
        3. 클러스터 내 최대 500개의 샤드를 생성 가능
          1. 최대 500개 노드를 가질 수 있으므로, 1샤드=1 Primary 노드로 하는 경우 500샤드 구성 가능
          2. 단, IP주소가 충분한지 체크 필요
      4. Parameter groups
        1. parameter group 을 적용함으로써 각기 다른 parameter 를 적용 가능
        2. RDS 와 동일 개념
      5. Subnet Groups
        1. VPC 내 subnet group 으로 구성
      6. Access Control Lists
        1. Redis ACL 규칙을 적용 가능 (Access Control List)
      7. Users
        1. 이름과 암호를 가진 User를 생성하여 접속 가능

        2. 2. 사용자는 ACL 구성원
  2. Redis vs Elasticache Redis vs MemoryDB for Redis
    1. 성능 : Elasticache 가 Memory DB 보다 쓰기 읽기 성능이 더 좋음
  Redis ElastiCache for Redis MemoryDB for Redis
내구성 AOF, RDB 로 내구성 처리
(AOF 파일에 쓰기 전 장애 시 데이터 손실 발생 가능성)
Primary 리턴 응답이라, Replica node에 데이터 적재 전 장애 시 손실 발생 가능성 존재
Redis 데이터구조 및 API
내구성이 뛰어난 Inmemory DB (장애 시 무손실 복구)
(Transaction log 까지 작성 후 응답이기 때문에 무손실 가능)
Redis 데이터구조 및 API
성능 12만/sec read/write : μs (마이크로초) read : μs (마이크로초)
write : ms (한자리 Millisecond)
Cluster mode Cluster mode 활성화 비활성화 모두 가능 cluster mode 활성화, 비활성화 모두 가능 cluster mode 활성화 필수
접속 redis-cli 로 접속
백업
  • 조건부 RDB 백업 가능
  • AOF 로 모든 DML 쿼리 저장
  • 24시간 동안 20개까지 스냅샷 생성 제한
    • cluster mode에서만 백업
  • 해당 Region에서 수동 스냅샷 보유 개수 제한은 없음
  • 24시간 동안 20개까지 스냅샷 생성 제한
    • cluster mode에서만 백업
  • 해당 Region에서 수동 스냅샷 보유 개수 제한은 없음
복원
  • RDB 시점 복원 가능
  • AOF 이용하여 원하는 명령문까지 복원 가능
  • RDB 스냅샷 복원
  • 별도의 Replica node가 없을 경우 유실(마지막 스냅샷 이후 부터 유실)
  • RDB 스냅샷 복원
  • 특정시점복원은 불가 (Point in  time Recovery 불가)
  • Transaction log를 이용하여 장애 최종 복원 가능
고가용성 replica
shard 구성
Replica
Shard 구성
 
replica node의 복제가 실패하는 경우
  • 실패 노드를 감지하여 오프라인 전환 및 동일한 AZ에 교체노드를 실행하여 동기화 진행
MemoryDB Multi-AZ primary 장애
  • MemoryDB에서 Primary 오류 감지하면, replica node들 중 primary 정합성체크 후 primary 승격 후 다른 AZ에 있는 primary를 spin up 이후 동기화 진행
    (다른 AZ의 primary 를 spin up 이후 동기화 하는 것보다 더 빠름)
복제 replica 구성
  • async 복제
    • rdb로 먼저 전체 복제
    • 복제 버퍼 내용 복제
replica 구성
  • async 복제
    • rdb 전체 복제
    • (Reserved Memory) 내용 복제
transaction log를 사용하는 async 복제
  • transaction log에 저장(영구저장)하므로 데이터 손실될 위험이 없음
  • Multi-AZ 강력히 권장
  1. 가격 및 Region
    1. 가격
      1. https://aws.amazon.com/ko/memorydb/pricing/ 참고
      2. Elastic Cache 보다 하루 1달러 더 비싸다고 공유 받음
    2. 지원 region
      1. 현재 지원하고 있는 내역 리스트
      2. US East (N. Virginia), US East (Ohio), US West (Oregon), US West (Northern California), EU (Ireland), EU (London), EU (Stockholm), Asia Pacific (Mumbai), Asia Pacific (Seoul), Asia Pacific (Singapore), Asia Pacific (Sydney), Asia Pacific (Tokyo),  Canada (Central), and South America (Sao Paulo)  - 21년10월 정보

 

참고

https://docs.aws.amazon.com/memorydb/latest/devguide/what-is-memorydb-for-redis.html
https://docs.aws.amazon.com/memorydb/latest/devguide/components.html

Elasticache vs MemoryDB 성능 : https://www.sentiatechblog.com/benchmark-series-amazon-memorydb-and-how-it-stands-compared-to-amazon
https://youtu.be/Jbq_XZMZEKY

반응형
  1. 개요 및 아키텍처
    1. 개요
      1. 메모리 DB (높은 처리량 - Replication 읽기 및 쓰기, 대기 시간 등 높은 처리 가능)
      2. 레디스와 호환이 되며, 레디스 관련한 것들을 모두 사용 가능 (v6.2)
      3. Multi-AZ 를 지원하여 빠르게 failover 및 복구, 재시작이 가능
    2. 특징
      1. Primary / Replica 간의 강력한 일관성 보장
      2. ms 단위의 읽기,쓰기 지연시간 (클러스터당 최대 1억6천만 tps)
      3. redis 호환
      4. 빠른 데이터 복구 및 재시작 제공 (multi-az, transaction log )
      5. multi-az를 통한 자동 페일오버 및 노드 fail에 대한 감지 및  복구
      6. replication 및 shard를 이용한 노드 추가, scale out, scale up-down 가능
      7. primary 에 대한 read/write 일관성 보장 및 복제 노드에 대한 일관성 보장 가능(read / write concern으로 예상)
      8. 사용자 인증 및 네트워크 인증, 암호화 기능 제공
      9. s3로 자동 스냅샷 (최대 35일 - rds 와 동일)
      10. 하나의 클러스터로 최대 500개 노드 및 100tb 이상의 storage 지원(레플리카 포함)
      11. AWS KMS keys를 사용한 TLS 암호화(8번과 동일)
      12. Redis를 통한 사용자 인증 및 권한 부여(ACL)(8번과 동일)
      13. AWS Graviton2 인스턴스 유형 지원
      14. VPC, Cloudwatch, CloudTrail, AWS SNS 서비스와의 통합
      15. 완전 관리형 소프트웨어 패치 및 업그레이드 지원
      16. 관리 API를 위한 AWS IAM(Identity and Access Management) 통합 및 태그 기반 액세스 제어
    3. 주요 기능
      1. Cluster
        1. MemoryDB 서비스를 운영하는 하나 이상의 노드 모음 (서비스의 개념)
        2. Shard는 Memory DB Set 단위들의 모임으로 Cluster 내에 존재
          1. Noes ⊂ Shard ⊂ Cluster  = 서비스 DB
        3. Memory DB Set 에는 하나의 Primary 와 최대 5개의 Replica 노드들을 보유 가능
        4. Primary 는 read/write 가능하며, Replica node들은 only read 만 처리
        5. Primary 장애 시 replica node들 중 하나를 primary 로 승격
        6. cluster 생성 시 redis 버전을 지정
        7. cluster 내 Memory DB 기능
          1. cluster 추가
          2. cluster 수정
          3. cluster 스냅샷 가져오기
          4. cluster 삭제
          5. cluster 내 요소 보기
          6. cluster 에 비용 할당 태그 추가 / 삭제
      2. Nodes
        1. MemoryDB 구성 중 가장 작은 단위 (EC2 기반)
        2. 클러스터에 속하며, cluster 생성 시 정해진 버전의 엔진 기반
        3. 필요한 경우 클러스터의 노드를 다른 유형으로 up / down 가능
        4. 단독으로 up / down 가능은 체크 필요
      3. Shards
        1. 하나의 샤드에는 1~6개의 노드로 구성되며, primary 1개에 5개의 replica 로 구성
        2. MemoryDB Cluster는 항상 적어도 하나의 샤드로 구성
        3. 클러스터 내 최대 500개의 샤드를 생성 가능
          1. 최대 500개 노드를 가질 수 있으므로, 1샤드=1 Primary 노드로 하는 경우 500샤드 구성 가능
          2. 단, IP주소가 충분한지 체크 필요
      4. Parameter groups
        1. parameter group 을 적용함으로써 각기 다른 parameter 를 적용 가능
        2. RDS 와 동일 개념
      5. Subnet Groups
        1. VPC 내 subnet group 으로 구성
      6. Access Control Lists
        1. Redis ACL 규칙을 적용 가능 (Access Control List)
      7. Users
        1. 이름과 암호를 가진 User를 생성하여 접속 가능

        2. 2. 사용자는 ACL 구성원
  2. Redis vs Elasticache Redis vs MemoryDB for Redis
    1. 성능 : Elasticache 가 Memory DB 보다 쓰기 읽기 성능이 더 좋음
  Redis ElastiCache for Redis MemoryDB for Redis
내구성 AOF, RDB 로 내구성 처리
(AOF 파일에 쓰기 전 장애 시 데이터 손실 발생 가능성)
Primary 리턴 응답이라, Replica node에 데이터 적재 전 장애 시 손실 발생 가능성 존재
Redis 데이터구조 및 API
내구성이 뛰어난 Inmemory DB (장애 시 무손실 복구)
(Transaction log 까지 작성 후 응답이기 때문에 무손실 가능)
Redis 데이터구조 및 API
성능 12만/sec read/write : μs (마이크로초) read : μs (마이크로초)
write : ms (한자리 Millisecond)
Cluster mode Cluster mode 활성화 비활성화 모두 가능 cluster mode 활성화, 비활성화 모두 가능 cluster mode 활성화 필수
접속 redis-cli 로 접속
백업
  • 조건부 RDB 백업 가능
  • AOF 로 모든 DML 쿼리 저장
  • 24시간 동안 20개까지 스냅샷 생성 제한
    • cluster mode에서만 백업
  • 해당 Region에서 수동 스냅샷 보유 개수 제한은 없음
  • 24시간 동안 20개까지 스냅샷 생성 제한
    • cluster mode에서만 백업
  • 해당 Region에서 수동 스냅샷 보유 개수 제한은 없음
복원
  • RDB 시점 복원 가능
  • AOF 이용하여 원하는 명령문까지 복원 가능
  • RDB 스냅샷 복원
  • 별도의 Replica node가 없을 경우 유실(마지막 스냅샷 이후 부터 유실)
  • RDB 스냅샷 복원
  • 특정시점복원은 불가 (Point in  time Recovery 불가)
  • Transaction log를 이용하여 장애 최종 복원 가능
고가용성 replica
shard 구성
Replica
Shard 구성
 
replica node의 복제가 실패하는 경우
  • 실패 노드를 감지하여 오프라인 전환 및 동일한 AZ에 교체노드를 실행하여 동기화 진행
MemoryDB Multi-AZ primary 장애
  • MemoryDB에서 Primary 오류 감지하면, replica node들 중 primary 정합성체크 후 primary 승격 후 다른 AZ에 있는 primary를 spin up 이후 동기화 진행
    (다른 AZ의 primary 를 spin up 이후 동기화 하는 것보다 더 빠름)
복제 replica 구성
  • async 복제
    • rdb로 먼저 전체 복제
    • 복제 버퍼 내용 복제
replica 구성
  • async 복제
    • rdb 전체 복제
    • (Reserved Memory) 내용 복제
transaction log를 사용하는 async 복제
  • transaction log에 저장(영구저장)하므로 데이터 손실될 위험이 없음
  • Multi-AZ 강력히 권장
  1. 가격 및 Region
    1. 가격
      1. https://aws.amazon.com/ko/memorydb/pricing/ 참고
      2. Elastic Cache 보다 하루 1달러 더 비싸다고 공유 받음
    2. 지원 region
      1. 현재 지원하고 있는 내역 리스트
      2. US East (N. Virginia), US East (Ohio), US West (Oregon), US West (Northern California), EU (Ireland), EU (London), EU (Stockholm), Asia Pacific (Mumbai), Asia Pacific (Seoul), Asia Pacific (Singapore), Asia Pacific (Sydney), Asia Pacific (Tokyo),  Canada (Central), and South America (Sao Paulo)  - 21년10월 정보

 

참고

https://docs.aws.amazon.com/memorydb/latest/devguide/what-is-memorydb-for-redis.html
https://docs.aws.amazon.com/memorydb/latest/devguide/components.html

Elasticache vs MemoryDB 성능 : https://www.sentiatechblog.com/benchmark-series-amazon-memorydb-and-how-it-stands-compared-to-amazon
https://youtu.be/Jbq_XZMZEKY

반응형

해당 문서는 "Real Mysql 8.0" 서적을 참고하여 도출한 내용 입니다.

(아래 링크는 전혀 수익의 댓가가 없습니다. 오로지 공유 목적 입니다.)

https://book.naver.com/bookdb/book_detail.nhn?bid=20877661 

 

Real MySQL 8.0 1

MYSQL 서버를 활용하는 프로젝트에 꼭 필요한 경험과 지식을 담았습니다!《REAL MYSQL 8.0》은 《REAL MYSQL》을 정제해서 꼭 필요한 내용으로 압축하고, MYSQL 8.0의 GTID와 INNODB 클러스터 기능들과 소프트

book.naver.com

 

  • General log 는 모든 쿼리가 남아 쿼리의 내역을 모두 확인이 힘든 경우 발생
  • Percona의 pt-query-digest 를 이용하여 general log를 분석 가능
  • RDS MySQL 5.7.19에서 발생한 General log 를 이용하여 아래 테스트를 진행
Real Mysql 8.0 (151 page)
Percona에서 개발한 Percona Toolkit 의 pt-query-digest 스크립트를 이용하면 쉽게 빈도나 처리 성능별로 쿼리를 정렬해서 살펴볼 수 있다.

현재 Local machine이 Windows 라 percona toolkit 을 바로 설치할 수 없었고, WSL 를 이용하여 진행 했습니다.

percona tookit 설치 진행

Percona-toolkit : https://www.percona.com/doc/percona-toolkit/3.0/installation.html

 

Installing Percona Toolkit

Installing Percona Toolkit

www.percona.com

WSL 설치

https://docs.microsoft.com/ko-kr/windows/wsl/install

 

WSL 설치

wsl --install 명령을 사용하여 Linux용 Windows 하위 시스템을 설치합니다. Ubuntu, Debian, SUSE, Kali, Fedora, Pengwin, Alpine 등 원하는 Linux 배포판에서 실행되는 Windows 머신에서 Bash 터미널을 사용할 수 있습니

docs.microsoft.com

percona-toolkit 설치

이렇게 설치까지 끝나고 나면 직접 General log를 AWS RDS 에서 다운받고 분석 진행 하면 됩니다.

 

여기서 WSL 로 파일 복사는 간단합니다.

windows 폴더에서 아래 위치를 찾아가서 옮기면 됩니다.

 

C:\Users\<컴퓨터명>\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_<고유번호?>\LocalState\rootfs\home\<유저>

General log를 복붙하면 쉽게 파일 옮겨진 것을 확인 가능

general log를 pt-query-digest 로 분석 진행 합시다.

명령어 : pt-query-digest --type='genlog' General로그파일명 > 분석파일명
$ pt-query-digest --type='genlog' mysql-general.log.2021-10-28.0 > db5-2-general.log

실재 실행한 내역

  • 실행하면 아래와 같이 분석 완료까지 얼마나 남았는지 시간과 비율을 보여줘서 좋더군요.

Output 파일 내용

General log 분석에 많은 도움이 되었습니다!

 

Slow query 의 경우에는 아래 명령어로 진행 하면 됩니다. 

(Real Mysql 8.0 서적 152page 참고)

 

pt-query-digest --type='slowlog' mysql-slow.log > slowlog.log

 

 

반응형

능력이 부족하여 초심으로 돌아가 Real Mysql 8.0 공부를 시작합니다. 

Real MySQL 8.0 은 모두 2권으로 구성되어 있기 때문에, 1, 2부로 나누어서 진행 합니다.

빠르게 1회 완독을 하려고 합니다.

 

1차 (1부)

Start : 2021-10-19

Goal : 2021-10-31

End : 2021-11-02 (완료)

With : https://m.blog.naver.com/PostList.naver?blogId=tpgpfkwkem0 

 

닷닷이의 DB공간 : 네이버 블로그

[Profile] DB엔지니어 3년 , DBA 3년 아직 할 껏도 많고 배울것도 많다고 느낍니다. 틀린 점 있으시면 언제든지 지적해주시고 궁금한 점이 있으시면 언제든지 댓글로 남겨주세요. #여행 #IT #리뷰 #DB #

m.blog.naver.com

 

1차 (2부)

Start : 2021-11-04

Goal : 2021-11-26

 

2차 (1부)

- 정리 하면서 조금 더 디테일하게 진행 합니다.

- 중요한 부분만 캐치 하는 형태로 진행 합니다.

Start : 2021-11-08

Goal : 2021-12-31

 

2차 (2부)

반응형
  • MongoDB 보안
    • MongoDB 는 보안 관점으로 크게 5가지로 정리를 할 수 있으며, 해당 문서에서는 인증과 권한, 테스트한 내역만 작성
    • 인증(Authentication)
    • 권한(Authorization)
    • 암호화(Encryption) - TDE - Mongo DB Enterprise 에서 제공
    • 감사 (Auditing) - MongoDB Enterprise 및 Percona 제공
    • 데이터 관리 (Data Governance) - 데이터의 일관성을 유지라 해당 서적에서는 언급 안함

 

  1. 인증(Authentication)
    • 내부 인증
      • MongoDB와 MongoDB 라우터 서버 간(레플리카 셋에서 각 멤버간)의 통신을 위해서 사용되는 인증
      • 내부 인증은 키 파일과 x.509인증서 2가지 방식을 선택 가능
        • 인증 활성화 하기 위해서 설정파일에서 인증과 관련된 옵션 활성화 해야 함
$ /etc/mongod.conf

security : 
  authorization: enabled   # 내부 및 사용자 인증까지 모두 활성화(내부/사용자 인증을 개별로 설정 못함) 

#key 파일 생성은 기존 문서로 대체 합니다. 
#기존 key 파일 생성 및 auth 내용
  clusterAuthMode : keyFile
  keyFile : /etc/mongod.key
      • keyFile은 평문의 단순 문자열로 구성된 비밀번호 파일을 MongoDB 서버(OS)가 내부 인증으로 사용하도록 하는 방식
      • keyFile 생성할 때 주의점
        • 해당 파일은 클러스터에 참여하는 모든 MongoDB가 공유해야함-동일한 파일을 모든 멤버의 서버에 복사해서 사용해야 함
      1. keyFile 은 MongoDB 서버 프로세스가 읽을 수 있어야 함
      2. keyFile의 접근권한은 반드시 600, 700으로 파일의 소유주만 접근할 수 있어야 함
      3. keyFile의 내용에서 공백문자는 자동으로 무시
      4. keyFile은 6개 이상 1024개 이하의 문자로 구성돼야 하며, Base-64셋에 포함되는 문자만 사용할 수 있음

 

    • 사용자 인증
      • MongoDB서버 외부의 응용 프로그램이 MongoDB 클라이언트 드라이버 이용해서 접속 시도할 때
      • 사용자를 생성할 때 반드시 특정 데이터베이스로 이동해서 생성해야 함 > 인증 데이터베이스라고 함(Authentication Database)
        • 여러 DB에 대해 권한을 가질 수 있지만, 인증 데이터베이스(로그인을 위한)는 하나만 가질 수 있음 (admin 에서 생성 하고, test 에서 또 권한을 주더라도 test를 인증하는 데이터베이스로 할수 없고 로그인할 때는 무조건 admin으로 먼저 접속)
        • 활성화기 위해서 /etc/mongod.conf 파일을 수정. 클러스터 멤버 간 통신의 인증을 위해서 clusterAuthMode 및 keyFile 옵션을 추가 더 사용해야 함
        • db.system.users.find().pretty() 명령 으로 유저 정보를 확인 가능
        • 동일한 계정명과 패스워드를 하더라도 다음과 같이 생성하면 두 계정은 mongoDB에서는 서로 다른 계정으로 인식함
        • 만약 하나의 사용자 계정이 여러 데이터베이스 대해서 권한을 가지도록 한다면 다음과 같이 해야 함
단순 사용자 인증을 위한 설정

security:
   authorization : enabled
use mysns
db.createUser({user:"user",pwd:"password", roles:["readWrite" ] })

use myblog
db.createUser({user:"user",pwd:"password", roles:["readWrite" ] })

#유저 생성 여부 확인
show users
use mysns
db.createUser({user:"user",pwd:"password", roles:[ "readWrite", {role:"readWrite", db:"myblog" }  ] })

또는
use mysns
db.createUser({user:"user",pwd:"password", roles:["readWrite" ] })
db.grantRolesToUser("user", [{ role:"readWrite", db:"myblog" }])

생성된 유저 확인
db.system.users.find().pretty()
This article will walk you through using the SASL library to allow your Percona Server for MongoDB instance to authenticate with your company’s Active Directory server. Percona Server for MongoDB includes enterprise level features, such as LDAP authentication, audit logging and with the 3.6.8 release a beta version of data encryption at rest, all in its open source offering.

  1. 권한 (Authorization)
    1. 액션
      • 명령이 처리되는 동안 발생하는 각 단위 작업을 나누어서 MongoDB의 명령들이 하나 이상의 단위 액션들의 집합으로 처리되는 개념
      • 버전에 따라 미리 정의해 둔 액션의 종류는 매우 다양하고 개수도 많으며, 추가/제거되는 명령도 많기 때문에 MongoDB에서 직접 체크가 필요
      • 최소 단위의 권한으로 일반적인 명령어를 실행하기 위해서는 여러 액션의 권한이 필요 (aggregate라는 명령어를 실행하기 위해서는 find / insert / bypassDocumentValidation이라는 3가지 액션이 필요)
    2. 내장된 역할(Role)
      • MongoDB에서 내부적으로 default로 만든 role로 여러 액션들의 집합체
      • ex) read 라는 내장된 롤에는 collStats, dbHash, dbStats, find, killCursors, listIndexes, listCollections 의 액션으로 만들어짐
      • mysns 데이터베이스에 대해서 readWrite 역할을 가지고 myblog 데이터베이스에 대해서 read 역할만 가지는 사용자 계정 생성
mongodb > use mysns
Mongodb > db.createUser({user:"mysns_user",pwd:"mypassword",roles:["readWrite",{role:"read",db:"myblog"}]})

cf ) User 생성 시 인증 DB를  admin 으로 하되, 권한은 DB 단위의 권한만 부여 되는지 여부

        • 생성 시 아래와 같은 방법으로 생성 추가 가능
        • 로그인 시 admin 으로 로그인만 가능. 그 외 부여된 권한에 대해서만 진행 가능
mongodb > use admin
mongodb > db.createUser({user:"testadmin",pwd:"testadmin!23",roles:[{ role:"readWrite", db:"test" }]})

또는 

mongodb > db.createUser({user:"testadmin",pwd:"testadmin!23",roles:[]})
mongodb > db.grantRolesToUser("testadmin", [{ role:"readWrite", db:"test" }])

  • dbowner : DB 관리조치를 수행할 수 있으며, readWrite, dbAdmin, userAdmin 역할이 부여한 권한을 결합
  •  -> dbOwner를 admin database에 부여하면 슈퍼유저를 가질 수 있음 (userAdmin동일)
  • dbadmin : 스키마 관련 작업 등을 할 수 있지만 권한 부여는 못함
  • userAdmin : 현재 데이터베이스에서 역할 및 사용자를 작성 수정 기능. 사용자에게 권한 부여 , admin에서 userAdmin을 부여하면 슈 퍼유저 액세스 가능(db/cluster)
  • -> userAdminAnyDatabase를 포함하여 클러스터 전체 역할 또는 권한 부여 가능


결론 :  dbOwner  ⊇ userAdmin ≠ dbadmin  Superuser >


Superuser > root : readWriteAnyDatabase, dbAdminAnyDatabase, userAdminAnyDatabase, clusterAdmin, restore, and backup combined.
Role type Role Role 설명 제외되는 role 상세 내역 확인 사항
Database User Roles read 읽기 system collection 제외 changeStream, collStats, dbHash, dbStats, find, killCursors, listIndexes, listCollections 등과 같은 명령어를 처리
readWrite 읽기 + 쓰기 system collection 제외 read에 해당하는 명령어에 convertToCapped, createCollection, dropCollection, createIndex, dropIndex, emptycapped, insert, remove, renameCollectionSameDB, update 와 같은 명령어를 처리
Database Administration Roles

dbAdmin indexing, gathering, statistics 등 역할을 할 수 있으며 user와 role에 대한 management는 제외 collStats, dbHash, dbStats, find, killCursors, lisstIndexes, listCollections

dropCollection, createCollection on system.profile only
기술PM : dbAdmin + readWrite 권한 부여
dbOwner readWrite + dbAdmin + userAdmin


userAdmin 해당 DB에 대한 user의  roles를 생성하거나 변경을 수행하며, admin에 대한 userAdmin 권한을  받았을 경우 superuser를 생성 가능 WARNING


It is important to understand the security implications of granting the userAdmin role: a user with this role for a database can assign themselves any privilege on that database. Granting the userAdmin role on the admin database has further security implications as this indirectly provides superuser access to a cluster. With admin scope a user with the userAdmin role can grant cluster-wide roles or privileges including userAdminAnyDatabase.
changeCustomData
changePassword
createRole
createUser
dropRole
dropUser
grantRole
revokeRole
setAuthenticationRestriction
viewRole
viewUser

Cluster Administration Roles



clusterAdmin 클러스터에 대한 최대 권한 부여자


clusterManager + clusterMonitor + hostManager + dropDatabase  권한(action)


dbOwner 가 cluster권한 포함 ㅇㅕ부(포함한다면 ㅎㅐ당 권한 사용 안함)


dbadmin > clusterManager 이다면 dbadmin만 pm에게 권한 부여
clusterManager config, local database에 접속할 수 있는 권한
cluster action 에 대한 management와 monitoring을 제공

  • Cluster 에 대한 권한 appendOplogNotecleanupOrphanedlistSessions (New in version 3.6)removeShardreplSetGetConfigreplSetStateChange
  • resync
  • replSetGetStatus
  • replSetConfigure
  • listShards
  • flushRouterConfig
  • applicationMessage
  • addShard
  • All databases in the cluster 에 대해서 다음과 같은 권한 부여moveChunksplitVector
  • splitChunk
  • enableSharding

clusterMonitor Monitor에만 국한되며 read only 의  access 보유
  • Cluster에 대한 권한connPoolStatsgetLoggetShardMapinproglistSessions (New in version 3.6)netstatreplSetGetStatussetFreeMonitoring (New in version 4.0)top
  • shardingState
  • serverStatus
  • replSetGetConfig
  • listShards
  • listDatabases
  • hostInfo
  • getParameter
  • getCmdLineOpts
  • checkFreeMonitoringStatus (New in version 4.0)
  • all databases in the cluster :dbStatsindexStats
  • useUUID (New in version 3.6)
  • getShardVersion
  • collStats

hostManager 각각의 서버에 대한 monitor와 manage 역할을 수행
  • Cluster 권한closeAllDatabasescpuProfilerfsynckillAnyCursor (New in version 4.0)killopresyncshutdownunlock
  • touch
  • setParameter
  • logRotate
  • killAnySession (New in version 3.6)
  • invalidateUserCache
  • flushRouterConfig
  • connPoolSync
  • applicationMessage
  • all databases in the cluster
  • killCursors

Backup and Restoration Roles backup mongodump 등으로 backup 수행


restore mongorestore 등으로 restore 수행 system.profile collection data는 제외

All-Database Roles



readAnyDatabase



readWriteAnyDatabase



userAdminAnyDatabase



dbAdminAnyDatabase dbAdmin 과 동일한 권한(local and config 제외)


Superuser Roles root superuser 권한 restore 제외라고 어떤 블로그에 공유되었지만, 공식 문서에는 restore 권한도 포함 되어 있음
(The root role includes privileges from the restore role.)
  • dbOwner 권한을 admin 에 지정한 경우
  • userAdmin 권한을 admin 에 지정한 경우
  • userAdminAnyDatabase 권한

Internal Role __system 어떠한 database any object에 any action을 취할 수 있으나, 일반적으로 사람들에게 지정되는 것이 아니라 application이나 human administrators 에게 부여되는 권한이다.


  1. 사용자 정의 role
    • 사용자가 자신의 서비스나 요건에 맞게 새로운 역할을 정의해서 사용할 수 있도록 가능
    • 2가지 범위를 가짐 > 사용자 정의 역할을 어느 데이터베이스에서 생성했느냐에 따라 구분
    • 전역 역할
      • admin DB에서 생성하면 전역 역할
    • 데이터베이스 단위 역할
      • admin DB이외에서 생성하면 해당 DB 단위로만 역할을 부여
      • db.createRole() 로 생성 db.grantPrivilegesToRole() / db.revokePrivilgesFromRole() 로 제거
      • 내장된 역할 또는 이미 정의된 역할을 부여하는 방법은 db.grantRolesToRole() 과 db.revokeRolesFromRole() 로 추가 제거가 가능
MongoDB > use admin
MongoDB > db.createRole({
   role: "dev_mysns".
   privileges: [
     { resource: { db: "mysns", collection: ""}, actions: ["find", "update", "insert", "remove"]},
     { resource : {db: "myblog", collection: ""}, actions: ["find"]}
   ], roles: []
})

MongoDB > use admin
MongoDB > db.createRole({
   role: "dev_mysns",
   privileges: [],
   roles: [
      {role : "readWrite", db:"mysns"}
      ,{role : "read", db:"myblog"}
   ]
})
  • 정의된 롤 확인
MongoDB > use admin
MongoDB > db.system.roles.find().pretty()
    • 유저 생성 및 사용자 정의 롤 부여
MongoDB > use admin
MongoDB > db.createUser({user : "user", pwd: "mypassword", roles:["dev_mysns"] })

 

 

  1. 테스트 내역
    • 유저 생성 및 접속 체크
# gadmin root admin (DB : admin) 

MongoDB Enterprise > use admin 
switched to db admin 

MongoDB Enterprise > db.createUser({user:"gadmin",pwd:"gadmin",roles:["root"]}) 
Successfully added user: { "user" : "gadmin", "roles" : [ "root" ] } 

# test db book collection document  
MongoDB Enterprise > use test 
switched to db test 

MongoDB Enterprise > db.book.insert({"name":"mongodb", "author":"hyungi"}) 
WriteResult({ "nInserted" : 1 }) 

MongoDB Enterprise > show dbs 
test 0.000GB 

MongoDB Enterprise > db.book.find() 
{ "_id" : ObjectId("5ddb78f35f326d0194f85cbc"), "name" : "mongodb", "author" : "hyungi" } 

# test DB lgtest readWrite  
MongoDB Enterprise > use test; 
MongoDB Enterprise > db.createUser({user:"lgtest",pwd:"lgtest!23",roles:["readWrite"]})

# test2 DB lgtest2 readWrite
MongoDB Enterprise > use test2
MongoDB Enterprise > db.book.insert({"name":"python", "author":"aca"})
MongoDB Enterprise > db.createUser({user:"lgtest2",pwd:"lgtest2!23", roles:["readWrite",{role:"readWrite",db:" test"}]})

# user
MongoDB Enterprise > show users

    • 인증 DB는 test2 로 생성하였기 때문에, test DB로 로그인 인증 시도 시 실패 확인

    • 기존 인증 DB인  test2 로 접근은 가능 확인
      • 로그인 후 로그인 한 dbs 확인 시 test 로 확인이 되어, 이 부분에 대해서는 체크가 필요 ( db.system.getDB() ) 로 확인 가능

      • admin 으로 다시 로그인 후 확인했더니 test 로 접속

    • Role Test
MongoDB Enterprise > db.createRole({
  role: "role_test",
  privileges: [
    { resource: { db: "test", collection: ""}, actions: ["find", "update", "insert", "remove"]},
    { resource : {db: "test2", collection: ""}, actions: ["find"]}
  ], roles: []
})
MongoDB Enterprise > db.system.roles.find().pretty()
      • 다른 DB에서는 role  부여가 안되고 admin 에서만 부여가 되는 것을 확인
MongoDB > use admin
MongoDB > db.createUser({user : "lgtest3", pwd: "lgtest3!23", roles:["role_test"] })
MongoDB > db.book.insert({"name":"mongodb2","author":"bkkim"})
MongoDB > db.book.insert({"name":"mysql2","author":"bkkim"})
      • 인증 DB는 admin 하지만 권한들은 test(read/write),test2(read)

      • 당연히 인증은 admin 만 되고 막상 접속하면 db는 test 로 접속되어 있음

      • 부여한 롤은 시스템 정보를 모르고 있기에 알고 있는 정보로만 find 해야함...
        • collection  / dbs 정보 들을 확인할 수 없음

      • role 은 정상 동작
    • userAdmin role
      • userAdmin 은 readWrite 등의 dml 권한은 없지만, 유저 권한 부여 등은 가능
      • 해당 부분에 대한 테스트
MongoDB Enterprise > use test
MongoDB Enterprise > db.createUser({user:"useradmin",pwd:"useradmin!23",roles:["userAdmin"]})
$> mongo -u "useradmin" -p --authenticationDatabase "test"

 

Test 내역
  1. show dbs
  2. show collections
  3. db.book.find()
  4. db.book.insert({"name":"useradmin","author":"roles"})
  5. db.createUser({user:"roletest",pwd:"roletest!23", roles:["read"]})
      • dbs / collections 확인 불가

      • find / insert 진행 불가

      • 유저 생성 권한 부여 가능

    • dbAdmin Role
      • dbAdmin 은 인덱싱 등 통계 수집같은 관리 작업을 수행
      • 참고로 아래 테스트는 userAdmin 권한을 가진 useradmin 계정으로 권한을 부여 (userAdmin은 dbAdmin 권한을 부여 가능)
MongoDB Enterprise > use test
MongoDB Enterprise > db.createUser({user:"dbadmin",pwd:"dbadmin!23",roles:["dbAdmin"]})
$> mongo -u "useradmin" -p --authenticationDatabase "test"

 

  • Test 내역
  1. show dbs
  2. show collections
  3. db.book.find()
  4. db.book.insert({"name":"useradmin","author":"roles"})
  5. db.book.createIndex({name:1})
  6. db.createUser({user:"adminroletest",pwd:"adminroletest!23", roles:["read"]})
      • userAdmin을 가진 계정이 dbAdmin 의 롤을 가진 유저 생성 가능
        • userAdmin 은 계정 생성 및 user 생성 되었는지 확인 가능

      • db 조회는 안되지만, collection 조회는 가능

      • find 및 insert 불가

      • index 생성 가능

      • 유저 생성은 불가
        • 관리의 관점에서 진행하기 위해 dbAdmin을 생성하여 사용

    • dbOwner role
      • dbOwner 은 readWrite, dbAdmin, userAdmin role 을 보유하며, DB 관리 조치를 수행 가능
      • 참고로 아래 테스트는 userAdmin 권한을 가진 useradmin 계정으로 권한을 부여 (userAdmin은 dbOwner 권한을 부여 가능)
      • 더불어 test2 DB 에서는 계정 추가가 안되는 것을 확인(참고로 useradmin는 test에 대해서만 userAdmin 권한을 보유)
MongoDB Enterprise > use test
MongoDB Enterprise > db.createUser({user:"dbowner",pwd:"dbowner!23",roles:["dbOwner"]})
$> mongo -u "dbowner" -p --authenticationDatabase "test"
  • Test 내역
  1. show dbs
  2. show collections
  3. db.book.find()
  4. db.book.insert({"name":"dbowner","author":"one of the role"})
  5. db.book.createIndex({author:-1})
  6. db.createUser({user:"ownerroletest",pwd:"ownerroletest!23", roles:["read"]})
      • userAdmin을 가진 계정이 dbOwner 의 롤을 가진 유저 생성 가능
        • userAdmin 롤을 가진 계정은, 계정 생성 및 user 생성 되었는지 확인 가능
        • userAdmin 는 자신이 할당 받은 DB에 대해서만 권한 부여가 가능

      • db 조회는 되지 않지만 collection 조회는 가능

      • collection 내 Document 조회도 가능하며, Insert 도 가능

      • Index 생성 가능하며, 다른 유저 또한 생성 가능

 

결론

  1. 인증 DB로 로그인 가능
  2. userAdmin의 권한은 함부로 부여 해서는 안됨
    • 자기 자신이 무언가를 하기는 힘들지만, 자신이 가진 권한으로 상위 권한을 부여 가능(dbOwner라는 권한을 부여하여 자신의 DB 컨트롤 가능)
  3. dbAdmin 권한은 Insert 권한이 없는 그저 관리의 목적으로 사용될 수 있지만, drop권한이 있어서 잘 숙지하고 권한 부여 해야 함
  4. dbOwner 권한은 해당 DB의 최 상위 권한이지만, userAdmin과 함께 Admin DB에만 부여 안한다면 QA DB셋팅 시 개발사에게 권한 위임의 용도로 유용
    • 운영 DB에서는 readWrite 권한이면 충분
  5. 가장 중요한 것은 DB Schema 별로 최대 dbOwner까지만 부여하고 Admin DB에는 절대 부여하면 안됨
반응형

Document 관계 유형

  • 1:N 관계
    • 예시) 게시판과 게시글 관계
    • 임베디드 방식으로 관계를 표현 가능
샘플
{
    _id:ObjectId()
    , 이름 : 자유게시판
    , 게시글 : [ { no : 1
        , 제목 : 첫번째글
        , 내용 : 편하네요
        } ,
        { no : 2
        , 제목 : 두번째글
        , 내용 : 편하네요2
        }
    ]
}
    • 하지만 하나의 Document 크기가 커지면 이 때 2개의 Collection으로 1:N 관계로 변경을 고려.
  • N:N 관계
    • 예시) 게시글과 사용자 관계
    • 조회를 해야 하는 경우 별도의 조회용 Collection 을 생성하여 조회를 해야하는 정보들을 미리 저장하고 있다가, 해당 Collection 조회 결과 값을 이용하여 찾는 방식
    • 이렇게 하면 별도의 조회용 Collection과 게시글 또는 사용자와 관계가 1:N 관계로 엮임
    • 또는 게시글 Document에 조회  field를 생성하여 배열로 구성 가능
  • 1:1 관계
    • 예시)사용자와 포인트 관계
    • 이럴 때에는 사용자 Document에 포인트 정보를 포함하면 간단. (조인을 줄이는게 목적)
    • 하지만 하나의 Document 크기가 커지면 이 때 2개의 Collection으로 1:1 관계로 변경을 고려.

MongoDB 모델링

 

Atomicity of Write(원자성) 작업

  • 하나의 Document에 대해서는 원자성을 보장
  • updateMany 의 경우 처럼 여러 (multiple) document에 수정을 할 때 하나씩(single) document에 대해서는 원자성을 보장하지만, 전체에 대해서는 원자성을 보장하지 않음 (하나하나씩 진행 하기 때문)
  • Multiple 에 대해 원자성을 보장받기 위해서는 Transaction 을 이용하여 진행이 필요
    • Transaction 을 사용 시 성능이 떨어지기 때문에 가급적 Transaction 사용을 최소화가 필요

 

MongoDB 모델링 시 고려사항 정리

  • Data와 Business 중심의 설계
    • Application의 쿼리 중심 설계를 의미
    • 비즈니스 요구사항에 맞춰서 비정규화(Embedded), 데이터 중복 허용
  • Document 관계 데이터 저장 유형
    • Embedded vsReferences 
      • 자식 객체가 자신의 부모 객체 외부에 절대 나타나지 않는 경우라면 포함시키고, 그렇지 않다면 별도의 collection 을 만들어 저장.
        • 조인이 필요한 경우라면 포함 시키고, 필요 없다면 collection 으로 개발을 추천하는 의미로 해석
      • Embedded
        • 16Mb 제한
        • 빈번한 업데이트, 크기가 증가하는 업데이트일 경우 권장하지 않음 (단편화 발생)
        • 읽기 속도 향상 : 한번의 쿼리로 원하는 데이터 추출 가능
      • References
        • 복잡하지만 유연한 데이터 구조
        • 데이터 크기 제한 없음
        • 상대적으로 강한 일관성 제공 가능
        • 해당 Document만 삭제,수정,추가만 하면 되기 때문

 

Embedded

  • Document 내에 존재
  • 1개의 Document 데이터를 다른 Document key 의 value 에 저장하는 방법
// Person
{
   _id: "joe",
   name: "Joe Bookreader",
   address: {
      street: "123 Fake Street",
      city: "Faketon",
      state: "MA",
      zip: "12345"
  }
}


// Address
{
   pataron_id: "joe",
   street: "123 Fake Street",
   city: "Faketon",
   state: "MA",
   zip: "12345"
}

Database References

  • 하나의 Document 내에 저장되는 비 정규화된 데이터 모델에 최적 (경우에 따라 별도의 Document에 저장이 바람직한 경우도 존재)
  • Pointer 개념으로 이해하면 쉬움 (Embedded 의 경우 Document를 통채로 저장하는 반면, Reference의 경우 ID 를 저장하는 것)
  • 하나의 Document 내에 embeded 형태 보다 더 유연한 방식
  • 3.2 에서는 $lookup 파이프라인을 이용하여 동일 DB 내 샤드 되지 않은 Collection에 left outer join 가능
  • 3.4 이후부터 $graphLookup 파이프라인을 이용하여 샤드 되지 않은 Collection에 재귀 검색을 수행 가능 (자신의 collection의 의미로 해석)
  • 2가지 방법을 이용하여 Document 참조 가능
    • Manual 참조
      • 참조할 Document의 _id 필드를 다른 Collection 내 Document에 하나의 key(필드)로 참조 저장
db.places.insert({
    name: "Broadway Center",
    url: "bc.example.net"
})
db.people.insert({
    name: "Erin",
    places_id: db.places.findOne({name: "Broadway Center"})._id,
    url:  "bc.example.net/Erin"
})

> var peopleDoc = db.people.findOne({name: "Erin"});
> var placeID = peopleDoc.places_id;
> var placesDoc = db.places.findOne({_id: placeID});
> placesDoc.url
bc.example.net

# 또는

> db.places.findOne({ _id: db.people.findOne({name: "Erin"}).places_id }).url
bc.example.net

  •  DBRefs
    • 참조할 Document의 "_id" 필드의 값과 옵션으로서의 DB 이름을 이용하여 어느 하나의 Document가 다른 Document를 참조하는 것
    • 여러 Collection에 위치한 Document를 단일 Collection Document에서 쉽게 연결하여 조회 가능
    • DBRef는 3개의 인자를 가지는데, 처음 두 개는 필수 인자이며($ref, $id), 세 번째 인자는 옵션 인자($db)
    • $ref
      • 참조할 Document가 존재하는 Collection 이름
    • $id
      • 참조된 Document 내 _id 필드 값
    • $db
      • 참조할 Document가 존재하는 DB 이름

출처 : 맛있는MongoDB

MongoDB 인 액션

https://blog.voidmainvoid.net/241

 

NoSQL강의) mongoDB에서 data 모델링하는 방법. 예제포함.

MongoDB 주요 특징 Secondary Index ▪ 다른 NOSQL 보다 secondary index 기능이 발달되어 있음 샤드키 지정 ▪  _id : 키 필드 ▪  Shard Key <> _id - 대부분의 NOSQL은 Row Key = Shard Key 임 Document 기..

blog.voidmainvoid.net

https://cinema4dr12.tistory.com/375

 

[MongoDB] Database References

by Geol Choi | March 10, 2014 이번 글에서는 "데이터베이스 간 참조"에 대하여 알아보도록 하겠다. 도큐먼트를 참조하는 방법은 크게 두 가지가 있는데, 하나는 수동 참조(Manual Reference)이며 다른 하나

cinema4dr12.tistory.com

https://devhaks.github.io/2019/11/30/mongodb-model-relationships/

 

반응형

Lock 매커니즘과 Transaction

  • 4.0 이하에는 지원하지 않음
  • Two Phase Commit
    • 상태 값을 부여하여 진행하고 해당 로그를 다른곳에 저장하여 상태 검증할 수 있게 함.
    • 상태 검증해서 완벽하게 끝났다면, 상태 로그값을 삭제.
    • 결론은 계속 양쪽으로 상태를 체크해야함.
  • MongoDB에서 명시적으로 Lock은 Global Lock(Instance를 Lock) 만 가능(3.4 에서는 Global Lock외에는 모두 묵시적 Lock만 지원) > fsyncLock 명령어 이용
    • Global Lock을 사용하면 읽기는 막지 않음 / 쓰기는 Blocking 때문에 이후의 데이터 읽기나 변경이 모두 멈춤(주의)
    • fsyncLock을 사용한 connection에 대해서는 닫지 말고 유지 하라고 권고(다른 connection에서 unlock명령어가 실행 안될 가능성이 존재
  • Intention Lock(인덴션 락) 은 IS(Intent Shared Lock) + IX (Intent Exclusive Lock) 의도된 잠금을 묶어서 하는 말
    • Intention Lock의 경우 Collection - DB - Global까지 가능 / Document의 경우 불가( 묵시적 Exclusive lock만 가능)

 

General Transaction

  • WiredTiger Storage Engine 을 기반으로 작성
    • 최고 레벨의 격리 수준은 Snapshot (=Repeatable-read) / Serializable 격리 수준은 제공하지 않음
      • Transaction Log(General Log, Redo Log), CheckPoint를 이용하여 영속성(Durability) 보장
      • Transaction Log가 없어도 마지막 Checkpoint 시점의 데이터를 복구 가능
      • 하지만 격리 수준을 제공할 뿐 선택해서 사용 못함
    • SNAPSHOT(REPEATABLE-READ)
      • MongoDB Wired Storage Engine의 기본 격리수준
      • Transaction을 시작한 시점 부터 commit / rollback 완료될때까지 자신이 처음 검색한 데이터를 완료될때까지 같은 결과
      • 명시적 Transaction을 지원하지 않으며, 단일 Document에 대해서만 지원
    • Transaction Commit과 Checkpoint 2가지 형태로 영속성(Durability) 보장
    • Commit되지 않은 변경 데이터는 공유 캐시 크기보다 작아야 함
      • Commit 이 되어야만 디스크로 저장하기에 Transaction 내 변경 데이터 사이즈가 공유 캐시 크기보다 작아야 함
    • DML 발생 시 Lock이 발생하면 외부적으로는 기다리는 것으로 나오지만 내부 로직은 재시도를 함 (WriteConflict Exception ->  Error를 발생시켜 재시도를 하는 내부 Exception처리 -> 사용자는 Waiting 한다고 생각하면 됨)
      • WriteConflict Exception 작업은 cpu 사용량을 높이며, db.serverStatus() 명령으로 확인 가능
      • db.serverStatus() 의 writeConflicts 수치가 증가할수록 하나의 Document에 DML시도가 많은 것이므로 로직 변경을 고려해 보자
      • Find 명령어는 writeConflicts 와는 무관 (X-Lock을 걸지 않으므로)
    • 여러 문장을 하나의 문장으로 명령하더라도, MongoDB 내부에서는 잘게 짤라 각각의 문장으로 처리
      • db.users.inser({_id:1, name : 'ABC'},{_id:2, name:'DEF'}) -> db.users.insert({_id:1 ,name:'ABC'}) /  db.users.insert({_id:2 ,name:'DEF'})
      • 그렇기 때문에 insert 중간에 에러 발생한면, 에러 발생하기 직전까지는 Insert 완료, 이 후의 데이터는 실행 안됨
      • db.collection.bulkWrite([],{ordered:false}) 로 하여 실행 도중 에러 발생하는 경우 데이터 저장 관련 확인하기 힘듦
    • 한 문장에 여러 Document가 변경 되더라도(multi:true) 내부에서는 한건씩 update 가 진행(중간에 에러 발생해도 롤백 안됨)
    • 데이터 읽기의 경우 건건이가 아닌 일정 단위로 트랜잭션을 시작하고 완료(스냅샷 유지하여 읽음)
      • 일관성에 문제가 발생할 수 있음
      • 스냅샷 유지 요건(해당 요건이 모두 충족되어야 스냅샷 해제 및 삭제, 새로운 스냅샷 생성)
        • 쿼리가 지정된 건수의 Document를 읽은 경우 (internalQueryExecYieldIterations = 128)
          • Document 128건을 읽은 경우
        • 쿼리가 지정된 시간 동안 수행된 경우 (internalQueryExecYieldPeriodMS = 10)
          • 10 밀리 세컨드  이상을 쿼리가 실행되는 경우
    • 대량의 데이터를 읽는 경우 해당 데이터가 버퍼에 존재(스냅샷에서)하며, 그것을 가져와서 보여주기 때문에, find하는 도중에 보여준 데이터를 삭제 하더라도 그 전에 find한 데이터는 계속 보여줌
      • 정렬을 사용하게 되면 정렬 버퍼에 해당 데이터가 적재된 후, 적재된 데이터를 보여줌
      • 커서에 정렬된 데이터를 남겨둔 채 (모든 데이터를 클라이언트에 안보내고 중단하는 경우) 커서를 닫지 않으면, 메모리 누수가 발생 가능성(MongoDB에서 자동으로 닫기 전까지)
      • 원하는 데이터를 모두 봤다면 반드시 커서를 닫아 주도록 하자

 

    • (Transaction-level) Write Concern
      • 사용자의 변경 요청에 응답하는 시점을 결정하는 옵션을 Write Concern
      • DML 상황에서만 적용(Update / Delete / Insert에 대해서)
      • Client, Database, Collection 레벨에서 Write Concern을 결정 가능
      • 단일 노드 동기화 제어
        • 4가지가 존재 옵션 존재
        • UNACKNOWLEDGED
          • 클라이언트가 MongoDB서버로 전송된 명령이 정상적으로 처리 됐는지 아니면 에러가 발생해서 중간에 작업이 멈췄는지 관심 없이 무시
          • 에러 여부를 전혀 알수가 없음
          • 실무에서는 거의 사용하지 않음
        • ACKNOWLEDGED (최근 MongoDB의 Default)
          • 메모리상에 변경된 데이터의 적재 여부를  통보
          • 다른 Session 또는 자신의 Session에서 변경 값 조회 시 변경값 확인 가능
          • 메모리에서 Disk로 적재 하기 전에 장애 발생 시 손실의 위험 존재
        • JOURNALED
          • General Log 까지(Disk) 작성되어야 결과 반환 (General Log 활성 여부가 먼저 선행으로 체크해야 사용 가능함 / 3.6에서 부터는 반드시 General Log가 활성화 됨-비활성화 불가)
          • 장애 발생하더라도 언제든 복구가 가능
          • 레플리카 셋을 사용하는 경우 단일 MongoDB서버를 사용할 때에는 발생하지 않는 새로운 문제가 발생(동기화가 안되는 경우 문제 발생 가능성을 사전에 알기 힘듦)
          • 3.6에서 부터는 General Log 가 무조건 사용되기에 JOURNALED를 사용 가능하지만, ACKNOWLEDGED 모드와 차이가 없으며 JOURNALED 방식으로 작동)
        • FSYNC (MMapv1)
          • General Log가 없던 버전에서 사용했던 방식
          • 디스크의 데이터파일까지 모두 작성된 후에 결과 반환하는 방식으로 높은 비용의 작업
          • 제거가 될 기능
      • 레플리카 셋 간의 동기화 제어
        • Primary가 장애 발생 시 Secondary들에게 최신 OpLog를 전달하지 못한 경우 롤백되어 손실이 발생할 수 있는 점을 보완하기 위하여 설정 제어 방식
        • "{w:?}" 으로 Option을 줄 수 있으며, ? 에는 숫자 또는 문자가 들어가는데 해당 값에 따라 방식이 변경
        • {w:2}
          • 3개의 멤버 중 2개(Primary + Secondary 1) 의 멤버가 변경 요청을 필요한 수준까지 처리 했을 때 성공, 실패 여부를 반환
          • ACKNOWLEDGED + {w:2}  (기본이라 생략도 가능)
          •  JOURNALED + {w:2}
        • {w:"majority"}
          • 위의 숫자를 작성하게 되면 멤버수가 변경될 때마다 변경해 줘야함(하드 코딩)
          • "majority" 로 작성하게 되면 멤버수의 상관 없이 과반 수 이상일 경우 결과 반환
          • Read할 때에도 멤버 서로의 OpLog의 적용 위치를 알기 때문에, majority 로 하면 OpLog가 적용이 덜 된 곳의 멤버에는 접근하지 않음
        • "Tag-set name"
          • 각 멤버들에게 Tag를 할당 가능하며, 해당 Tag를 가진 멤버에게 체크
    • (Transaction-level) ReadConcern (https://docs.mongodb.com/manual/core/transactions/#std-label-transactions-write-concern)
      • Replica 간 동기화 과정 중에 데이터 읽기를 일관성 있게 유지할 수 있도록 MongoDB서버에서 옵션으로 제공(일관성 목적)
      • Option에 따라 다르겠지만, 쿼리 실행 시 기본적으로 세컨드리 멤버들이 OpLog를 원하는 옵션 수준 까지 동기화될 때까지 기다린다
      • 3가지 옵션이 존재( local, majority, linearizable )하며 Client Level, Database Level, Collection Level에서 설정 가능
      • Local : Default 로 가장 최신의 데이터를 반환하는 방식. 주로 Primary에서 가져가며, 장애 발생 시 해당 데이터가 롤백되어 Phantom Read가 발생 가능성 존재
        • Local 을 제외한 나머지 옵션에 대해서는 기본적으로 maxTimeMS 설정을 권장
        • 4.4 fCV 가 적용된 경우 Transaction 내에서 Index를 생성할 수 있으며, 명시적으로 생성하는 경우 local 로 설정하여 진행해야 함
      • majority : 다수의 멤버들이 최신 데이터를 가지고 있는 경우에 읽기 결과가 반환, 모든 DB가 장애 발생 시 데이터가 롤백되어 Phantom Read가 발생 가능성이 존재하지만, 롤백으로 인해 사라지는 경우 가능성이 가장 낮음
MongoDB --enableMajorityReadConcern .........

또는 MongoDB.conf 에서

...
setParameter :
   enableMajorityReadConcern: true
...
      • snapshot
        •  
      • linearizable : 모든 멤버가 가진 변경 사항에 대해서만 쿼리 결과 반환. 모든 DB가 장애가 발생하더라도 롤백은 일어나지 않음. 3.4부터 지원. 쿼리 응답시간이 자연스럽게 지연될 가능성이 존재. 무재한 기다릴 수 있기 때문에 쿼리 타임 아웃 설정은 필수.
        • db.runCommand({ find:"users", filter: {name:"matt"}, readConcern: {level: "linearizable"}, maxTimeMS:5000 })

 

    • Read Preference
      • 클라이언트의 쿼리를 어떤  DB 서버로 요청해서 실행할 것인지 결정하는 옵션(분산 목적)
      • 서버에 접속하는 시점에 설정되기에 컨넥션 생성하는 즉시 Read  Preference 옵션을 설정
      • Find쿼리만 영향이 미치며 5가지가 존재
        • db.getMongo().setReadPref('primaryPreferred')
        • db.users.find({name:"matt"}).readPref('primaryPreferred')
      • Primary (Default)
        • Primary로만 쿼리 실행하며, Primary가 없으면 쿼리 실행은 실패(장애 발생하고 fail over 이전)
      • PrimaryPreferred
        • 가능하면 Primary로 전송하며 장애로 Primary가 없는 경우 Secondary 로 요청
      • Secondary
        • Secondary 멤버로만 전송하며, Primary로는 요청하지 않음. 멤버가 2개 이상일 경우 적절히 분산하여 요청
        • Secondary가 없는 경우 실패 발생
      • secondaryPreferred
        • Secondary와 동일하지만 없는 경우 Primary로 요청
      • nearest
        • 쿼리 요청 응답시간이 가장 빠른 멤버로 요청 (Primary, Secondary 고려 안함)
        • 동일한 대역에서는 미흡하지만, 레플리카 셋이 글로벌하게 분산되어 멤버들간의 응답시간이 차이가 나는 경우 적절

 

    • 샤딩 환경의 중복 Document 처리
      • 샤딩된 클러스터는 2가지 경우에만 Document 샤드의 소유권(Ownership)을 체크
        • 쿼리에 샤드의 메타 정보 버전이 포함된 경우
        • 쿼리의 조건에 샤드 키가 포함된 경우
      • 청크가 이동될 때마다 컨피그 서버의 메타 정보가 변경됨(메타 정보의 버전이 1씩 증가)
      • 버전 정보를 쿼리 실행시마다 전달하는데, 버전이 포함된 쿼리를 'Versioned Query'라고 명칭
        • 청크가 이동되더라도 한 시점의 일괄된 데이터를 보장하는 이유가 버전 정보를 포함하고 있기 때문
        • 하지만 Primary에서 실행한 경우만 Versioned Query를 사용하며 Secondary에서는 버전 정보를 포함하지 않음(Unversioned Query)
      • Shard key를 포함한 쿼리의 경우 특정 샤드로만 쿼리가 전달되므로 해당 샤드가 가진 청크에 포함된 Document만 반환
      • Shard Key가 없으며, Secondary에서 조회하는 경우 Document의 중복이 발생 가능성 존재

 

[ Multi-Document Transaction]

  • Mongodb Client API도 반드시 4.2 버전으로 사용
  • 4.4 부터 명시적으로 Transaction 내에서 collection 을 생성 가능(Client API 또한 4.4로 사용해야 가능)
  • MongoDB 버전 4.0부터 제공되었지만, Replica Sets 환경에서 만 지원되었으며 4.2부터 Shard-Cluster 환경에서도 지원
  • Multi-Document Transation 은 여러 작업, Collection, DB에 적용할 수 있으며 Transaction 이 Commit 되면 변경된 모든 데이터를 저장하고 Rollback 되면 모든 데이터 변경을 취소
  • Commit 이 확정될 때까지 변경 중인 데이터는 누구도 참조할 수 없음( dirty_read : no)
  • Embedded Document 및 Array 구조와 같은 단일-Dcoument Transaction 에 비해 성능지연 문제가 발생할 가능성이 있기 때문에, 이를 대체해서 사용하면 안됨
  • FeatureCompatibility Version(fCV) 4.0 이후 환경에서 사용할 수 있으며 wiredTiger Storage Engine과 In-Memory Storage Engine에서 만 사용할수 있음(admin DB에서 설정 가능)db.adminCommand({ getParameter:1, featureCompatibilityVersion:1})
  • db.adminCommand({ setFeatureCompatibilityVersion : "4.2"})
  • Config, admin, local DB의 Collection 을 읽기/쓰기할 수 없으며 system.* Collection은 쓰기 작업을 수행할 수 없음. 또한 Multi Transaction 이 진행 중인 Collection은 인덱스를 추가 및 삭제할 수 없음
  • Transaction 총 크기가 16 Mb 이상인 경우에도 필요한 만큼의 Oplog를 생성하여 처리할 수 있음
  • Transaction 을 진행하기 전에 안전하게 write concern을 Majority 설정하는 것이 좋음
  • Wired Tiger인 Primary Server와  In-Memory 인 Secondary Server환경에서도 Transaction 을 지원

 

반응형

+ Recent posts