MongoDB Replica Set (5) - MongoDB 복제 연결토폴로지 방식과 복제 지연

Share

Last Updated on 1월 1, 2024 by Jade(정현호)

안녕하세요

이번 글에서는 MongoDB의 Replica Set에서의 복제 구성 연결 방식 토폴로지 및 복제 지연에 대한 내용을 확인해 보도록 하겠습니다.

MongoDB Replica Set 연재 글로 아래 포스팅에서 이어지는 글입니다.

복제 연결 토폴로지

MongoDB의 Replica Set(리플리카 셋) 환경에서 rs.status() 또는 db.adminCommand({replSetGetStatus:1}) 를 통해서 복제에 관한 다양한 정보를 확인할 수 있습니다.

> rs.status()

또는 

> db.adminCommand({replSetGetStatus:1})


[참고] 포스팅 글의 시스템에서는 MongoDB 6.0 이며 4개 멤버로 구성되어 있고 같은 서버에서 포트를 달리하여 구성되어 있습니다.

127.0.0.1:30001 , 127.0.0.1:30002,  127.0.0.1:30003, 127.0.0.1:30004

4개 멤버 중에서 1개 멤버는 Arbiter 로 구성되어 있습니다. 

syncSourceHost(syncingTo: Removed in MongoDB 4.4) 필드에서 각 멤버 별로 복제 소스(Source) 정보를 확인할 수 있습니다. 이는 멤버가 복제를 수행하는 호스트 정보를 의미합니다.

{
  _id: 3,
  name: '127.0.0.1:30002',
  health: 1,
  state: 2,
  stateStr: 'SECONDARY',
  uptime: 24,
  optime: { ts: Timestamp({ t: 111111111111, i: 2 }), t: Long("2057") },
  optimeDurable: { ts: Timestamp({ t: 111111111111, i: 2 }), t: Long("2057") },
  optimeDate: ISODate("2023-12-xxxx:33:15.000Z"),
  optimeDurableDate: ISODate("2023-12-xxxx:33:15.000Z"),
  lastAppliedWallTime: ISODate("2023-12-xxxx:33:15.393Z"),
  lastDurableWallTime: ISODate("2023-12-xxxx:33:15.393Z"),
  lastHeartbeat: ISODate("2023-12-xxxx:33:20.582Z"),
  lastHeartbeatRecv: ISODate("2023-12-xxxx:33:20.581Z"),
  pingMs: Long("0"),
  lastHeartbeatMessage: '',
  syncSourceHost: '127.0.0.1:30001', <!!--
  syncSourceId: 4,
  infoMessage: '',
  configVersion: 46366,
  configTerm: 2057
},

해당 정보를 바탕으로 각 세컨더리 멤버가 복제 동기화 대상을 통해서 복제 연결 토폴로지를 그려볼 수 있습니다.

세컨더리 멤버와 멤버가 바라보는 복제 소스 정보만 조회하기 위해서는 다음과 같이 수행합니다.

> db.adminCommand({
  "replSetGetStatus": 1
}).members.filter(function(member) {
  return member.stateStr === "SECONDARY"
}).map(function(member) {
  return { 
    name: member.name, 
    syncSourceHost: member.syncSourceHost
  }; })

(결과)
[
  { name: '127.0.0.1:30002', syncSourceHost: '127.0.0.1:30001' },
  { name: '127.0.0.1:30004', syncSourceHost: '127.0.0.1:30002' }
]


-- primary 정보 조회
> rs.hello()
{
  topologyVersion: {
    processId: ObjectId("6575b5f8de2ed9182f2e9937"),
    counter: Long("386")
  },
  hosts: [ '127.0.0.1:30001', '127.0.0.1:30002', '127.0.0.1:30004' ],
  arbiters: [ '127.0.0.1:30003' ],
  setName: 'reps',
  setVersion: 46366,
  isWritablePrimary: false,
  secondary: true,
  primary: '127.0.0.1:30001', <!!---
<..중략..>


위의 결과로 보면 프라이머리 멤버는 30001 포트이고, 세컨더리 포트는 30002, 30004 입니다.
(4개 중 1개는 Arbiter 임으로 표시되지 않습니다.)

30002 포트 세컨더리는 프라이머리인 30001 포트를 바라보면서 복제 동기화가 수행 중이고, 30004 포트 세컨더리는 다른 세컨더리인 30002 포트를 바라보면서 복제 동기화를 수행 중입니다.

MongoDB Replica Set에서 Ping 시간을 기준으로 동기화할 대상을 자동 결정하는 것이 기본 설정 값입니다. 그래서 이와 같이 세컨더리 멤버의 복제 소스가 다른 세컨더리 멤버가 될 수 있습니다.

멤버는 다른 멤버에 Heartbeat를 보낼 때, 요청이 처리되기까지 시간을 잽니다. MongoDB는 이러한 평균 실행 시간을 기록합니다.

동기화할 멤버를 선택할 때, 멤버는 가장 가깝고 복제 동기화에서 시점이 자신보다 앞서 있는 멤버를 찾습니다. 즉, 복제는 자신보다 앞서 있는 프라이머리 멤버나 세컨더리 멤버를 통해서 복제 동기화를 하며 그러므로 보통의 상황에서는 순환복제 형태가 발생하지 않습니다.


만약에 데이터 센터를 나눠서 다음의 그림1과 같이 센터별로 나눠서 복제 구성이 되어있는 환경이 있다고 가정한다면

[그림1]


기존에 세컨더리 멤버가 있는 데이터 센터에 새로운 세컨더리 멤버 인스턴스를 구성한다면 프라이머리가 있는 데이터 센터의 멤버보다 세컨더리 멤버가 있는 데이터 센터의 다른 멤버와 동기화할 가능성이 높습니다.

이러한 체이닝 복제 유형에는 몇 가지 단점이 있을 수 있습니다.

복제 홉(replication hop)이 많을수록 모든 서버에 쓰기를 복제 동기화하는 데 시간이 좀 더 오래 걸릴 수 있습니다.

[그림2]


예를 들어 모든 멤버가 하나의 데이터 센터에 있지만 그림2 처럼 세컨더리 멤버의 복제가 일렬로 복제가 되는 상황이라면 체이닝 홉이 가장 먼 멤버는 복제 동기화 시간에 오래 걸리고 데이터의 차이가 있을 수 있습니다.

이와 같이 체이닝 형태의 복제 유형은 아주 희박하지만 불가능한 상황은 아닙니다. 그러나 이런 구성은 당연히 바람직하지는 않습니다. 그래서 이러한 체이닝 복제 형태로 되어 있는 경우 replSetSyncFrom 명령어를 이용하여 복제 소스 멤버를 변경해서 이 문제를 해소할 수 있습니다.

복제 소스 멤버를 변경하려면 해당 세컨더리 멤버 인스턴스에 직접 접속하여 다음과 같이 명령어를 수행합니다.

### 명령어 예시
> secondary.adminCommand({"replSetSyncFrom": "member0:27017"})


복제 동기화 소스 멤버 전환에는 수 초 이상이 소요될 수 있으며, 완료된 후 다시 rs.status()를 실행하면 "syncingTo" 필드가 이제 "member0:27017" 로 변경된 것을 확인할 수 있습니다.
          

체이닝 복제 비활성화

체이닝 복제 유형은 위에서 설명한 내용과 같이 세컨더리 멤버의 복제 대상 멤버가 프라이머리가 아닌 다른 세컨더리 멤버인 경우를 발생하게 됩니다.

MongoDB는 기본 설정 값으로 복제 소스 멤버를 자동으로 결정하게 되며 그 대상이 다른 세컨더리 멤버가 될 수 있습니다.

관련해서 설정은 "channingAllowed" 이며 기본값은 true 입니다.

해당 설정을 false 로 하면 모든 세컨더리 멤버의 복제 대상은 프라이머리 멤버로만 되게 되며, 그에 따라 체이닝 복제 복제 형태의 복제 토폴로지는 구성되지 않게 됩니다.

"channingAllowed"false로 설정 시 모든 세컨더리 멤버는 프라이머리 멤버에서 복제 동기화를 수행하며 프라이머리가 이용 불가능한 상태가 되면 세컨더리 멤버와 동기화 됩니다.

• Disable Chained Replication
비활성화하기 위해서 primary 멤버에 접속하여 다음과 같이 수행합니다.

> cfg = rs.config()
> cfg.settings.chainingAllowed = false
> rs.reconfig(cfg)


• Re-enable Chained Replication
다시 활성화하기 위해서는 다음과 같이 진행합니다.

> cfg = rs.config()
> cfg.settings.chainingAllowed = true
> rs.reconfig(cfg)

              

MongoDB 지연시간 확인

MongoDB나 다른 복제 기능을 지원하는 데이터 저장소에서는 복제 타겟인 세컨더리(또는 Replica)가 소스(Source)에 대해서 얼마나 복제를 잘 따라가고 있는지가 중요 합니다.

복제 지연(Replication Lag)은 세컨더리 멤버가 복제 동기화 측면에서 얼마나 뒤처져 있는지를 나타내는 지표로 MongoDB에서는 프라이머리 멤버가 마지막으로 수행한 연산과 세컨더리 멤버가 마지막으로 적용한 연산의 타임스탬프의 차이를 의미합니다.

rs.status()를 사용해 멤버의 복제 상태를 확인할 수 있으며, rs.printReplicationInfo()나 rs.printSecondaryReplicationInfo()를 통해 빠른 요약 정보를 얻을 수 있습니다.

[참고] rs.printSlaveReplicationInfo 는 4.4.1 버전부터 Deprecated 되어서 rs.printSecondaryReplicationInfo 로 대체되었습니다.


먼저 rs.printReplicationInfo()는 복제에서 처리하는 크기와 날짜 범위 정보를 포함한 프라이머리 oplog 정보 내용을 제공합니다.

> rs.printReplicationInfo();

(결과)
actual oplog size
'250 MB'
---
configured oplog size
'250 MB'
---
log length start to end
'8269385 secs (2297.05 hrs)'
---
oplog first event time
'Wed Sep xx 2023 21:34:17 GMT+0900 (대한민국 표준시)'
---
oplog last event time
'Mon Dec xx 2023 14:37:22 GMT+0900 (대한민국 표준시)'
---
now
'Mon Dec xx 2023 14:37:22 GMT+0900 (대한민국 표준시)'


조회 결과인 테스트 시스템에서는 oplog이 약 250MB이며, 많이 사용되는 실제 운영 환경에서는 이보다 더 커야 할 수 있습니다. 해당 수치는 예제 테스트 시스템의 예시 수치입니다.


다음으로 rs.printSecondaryReplicationInfo()는 각 멤버의 syncedTo 값과 마지막 oplog 항목이 세컨더리에 기록된 시간을 가져올 수 있습니다.

> rs.printSecondaryReplicationInfo()

(결과)
source: 127.0.0.1:30001
{
  syncedTo: 'Mon Dec xx 2023 14:41:55 GMT+0900 (대한민국 표준시)',
  replLag: '0 secs (0 hrs) behind the primary '
}
---
source: 127.0.0.1:30002
{
  syncedTo: 'Mon Dec xx 2023 14:41:55 GMT+0900 (대한민국 표준시)',
  replLag: '0 secs (0 hrs) behind the primary '
}


Replica Set 멤버의 지연은 절대적인 시간이 아니라 프라이머리를 기준으로 상대적으로 계산된다는 점을 기억해야 합니다.

각 세컨더리 멤버의 syncedTo 필드는 프라이머리 멤버와 동기화된 시간을 나타내며, 이 시간은 프라이머리 멤버로부터의 상대적인 지연시간을 나타냅니다.
즉, 지연시간은 프라이머리 멤버로부터의 기준으로 상대적으로 계산됩니다.

 

보통은 문제가 되지 않지만 프라이머리에서 쓰기 작업이 매우 드물게 수행하는 시스템에서는 유령 복제 지연을 의미하는 트래픽의 급격한 증가(spike) 현상을 발생이 될 수 있습니다.

예를 들어 프라이머리에서 한시간에 한번 쓰기를 수행한다고 할 때 쓰기 바로 직후 복제되기 전에 세컨더리는 프라이머리보다 한 시간 뒤처진 것처럼 보이게 됩니다. 그러나 그 한시간 정도의 지연(Lag)은 몇 밀리초 안에 복제를 따라잡을 수 있습니다. 그래서 이처럼 처리량이 낮은 시스템에서는 복제 지연(Lag) 모니터링시에는 때때로 혼동을 일으킬 수 있습니다.

rs.printSecondaryReplicationInfo()가 실행될 때 간혹 replLag 정보에서 음수(-) 시간 값으로 표시될 수 있습니다.

이는 rs.printSecondaryReplicationInfo()이 실행되는 시점에 세컨더리 멤버의 쓰기가 없는 시점에서 프라이머리가 쓰기 작업이 이루어 진후 세컨더리 멤버가 primary 장치로부터 최신의 optim 하트비트를 수신하기 전에 실행되는 경우 나타날 수 있습니다.

## 예시
> rs.printSecondaryReplicationInfo()

source: 127.0.0.1:30001
{
  syncedTo: 'Mon Dec xx 2023 14:40:24 GMT+0900 (대한민국 표준시)',
  replLag: '-21 secs (-0.01 hrs) behind the primary '
}
---
source: 127.0.0.1:30002
{
  syncedTo: 'Mon Dec xx 2023 14:40:24 GMT+0900 (대한민국 표준시)',
  replLag: '-21 secs (-0.01 hrs) behind the primary '
}

           

Reference

Reference Book
몽고DB 완벽 가이드 3판(번역서)

Reference URL
mongodb.com//manage-chained-replication
mongodb.com/rs.printSecondaryReplicationInfo

연관된 다른 글 

 

 

 

               

0
글에 대한 당신의 생각을 기다립니다. 댓글 의견 주세요!x