MongoDB Replica Set (4) - 멤버 추가와 제거 및 구성변경 - Add Member Remove Member - rs.reconfig

Share

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

안녕하세요 
이번 글은 MongoDB의 Replica Set과 샤드 클러스터 환경에서의 Replica Set 멤버의 추가 및 제거 그리고 속성의 변경 등 Replica Set 멤버에 변경 관련된 내용에 대해서 알아보도록 하겠습니다. 

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

환경 정보

글의 환경 정보는 다음과 같습니다.

  • OS: CentOS 7.9
  • MongoDB : 6.0.9
  • Replica Set : 4 멤버
    • 1 Primary, 2 Secondary , 1 Arbiter


현재 Replica Set 상태 및 멤버 정보입니다.

> rs.config()

{
  _id: 'reps',
  version: 1,
  term: 1,
  members: [
    {
      _id: 0,
      host: '127.0.0.1:30001',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 1,
      host: '127.0.0.1:30002',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2, <!-- arbiter 멤버
      host: '127.0.0.1:30003',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    }
  ],
< ... 중략 ... >


같은 서버에서 포트를 달리하여 우선 3개 멤버로 Replica Set으로 구성되어 있습니다.


해당 내용은 아래 포스팅에서 이어지는, 또는 연관된 내용입니다.

Remove a Member

리플리카 셋에서 멤버를 제거하는 방법은 크게 2가지로 rs.remove를 이용하는 방법과 rs.reconfig를 이용하는 방법이 있습니다.

멤버 제거 및 추가 그리고 설정 변경 등은 Primary에서 진행해야 합니다.

프라이머리 멤버 인스턴스에서 하지 않으면 다음과 같은 에러가 발생합니다.

New config is rejected :: caused by ::
replSetReconfig should only be run on a writable PRIMARY.
Current state SECONDARY;

rs.remove

멤버를 제거하기 위해서 rs.remove명령어를 사용할 때는 다음과 같이 사용합니다.

# 구문
rs.remove("호스트 또는 IP:포트번호")

# 실행 예시
rs.remove("127.0.0.1:30003")

rs.remove("127.0.0.1:30002")


제거시 다음의 에러 메세지가 발생될 경우

Reconfig attempted to install a config that would change the implicit default write concern.
Use the setDefaultRWConcern command to set a cluster-wide write concern and try the reconfig again

다음과 같이 WriteConcern 설정 후 다시 rs.remove 를 실행합니다.

db.adminCommand({ setDefaultRWConcern: 1, defaultWriteConcern: { w: "majority" } })

rs.reconfig

rs.reconfig는 뒤에서 소개할 리플리카셋 멤버의 설정을 변경하는 용도로도 사용되며, rs.reconfig를 통해서 멤버를 제거할 수 있습니다.

rs.reconfig를 사용하는 목적 중에 또 하나는 사용 불가한 멤버를 제거시에도 사용합니다.

가령 하드웨어의 이슈 등으로 MongoDB인스턴스의 기동이 불가능한 멤버에 대해서 리플리카셋에서 제거가 필요할 경우 reconfig을 이용합니다.

현재는 멤버는 3개이며, rs.remove와 동일하게 primary 멤버 인스턴스에서 수행해야 하며, 다음과 같은 절차로 수행합니다.

 

// 현재 Replica Set 구성 가져오기
cfg = rs.conf();

 

// 멤버 설정 변경 : 첫 번째 멤버와 두 번째 멤버를 남기고 세 번째를 제거
cfg.members = [cfg.members[0] , cfg.members[1]]

여기서 멤버의 번호는 0부터 시작하고 rs.conf() 를 통해서 확인 할수있는 _id 와는 다른 member 의 인덱스 번호를 의미합니다.

예를 들어 아래와 같이 rs.conf() 결과가 있을 경우 조회된 순서 위에서 부터 0->1->2 순이 됩니다.

members: [
  {
    _id: 5,  <== Member Index : 0
    host: '127.0.0.1:30001', 
    arbiterOnly: false,
    buildIndexes: true,
    hidden: false,
    priority: 1,
    tags: {},
    secondaryDelaySecs: Long("0"),
    votes: 1
  },
  {
    _id: 2,  <== Member Index : 1
    host: '127.0.0.1:30002', 
    arbiterOnly: false,
    buildIndexes: true,
    hidden: false,
    priority: 1,
    tags: {},
    secondaryDelaySecs: Long("0"),
    votes: 1
  },
  {
    _id: 1,  <== Member Index : 2
    host: '127.0.0.1:30003',
    arbiterOnly: true,
    buildIndexes: true,
    hidden: false,
    priority: 0,
    tags: {},
    secondaryDelaySecs: Long("0"),
    votes: 1
  }

 

// 설정 적용
rs.reconfig(cfg)

또는
rs.reconfig(cfg, {force : true})

force: true 는 현재 사용이 불가능한(통신이 불가능한) 멤버 인스턴스를 제거시에 사용합니다.

 

// 적용된 사항 확인
rs.conf()

이와 같이 2가지 방법으로 멤버를 제거할 수 있습니다.

Add a Member

멤버를 추가할 때에는 rs.add 를 사용합니다.

rs.add 에서 사용할 수 있는 파라미터는 다음과 같습니다.

{
  _id: <int>,
  host: <string>, // required
  arbiterOnly: <boolean>,
  buildIndexes: <boolean>,
  hidden: <boolean>,
  priority: <number>,
  tags: <document>,
  secondaryDelaySecs: <int>,
  votes: <number>
}

이중에서 host 는 필수이고 그 외 파라미터는 옵션입니다.

멤버 추가는 rs.add 를 이용하여 다음과 같이 명령어를 수행합니다.

rs.add("127.0.0.1:30002")

또는

rs.add( { host: "127.0.0.1:30002" } )

 

추가 할 때 리플리카셋의 멤버 구성 상태에 따라서 별도의 파라미터를 지정해야 할 수 있습니다.

가령 1 Primary + 1 Secondary + 1 Arbiter 로 구성된 상황에서 1 Secondary를 제거하여 1 Primary + 1 Arbiter 인 상태에서 추가하면 다음과 같은 에러가 발생합니다.

Rejecting reconfig where the new config has a PSA topology and the secondary is electable, 
but the old config contains only one writable node. 

에러 메시지는 기존 구성원 중 쓰기 가능한 노드가 하나뿐인데 PSA 토폴로지를 가진 새 구성원이 선출 가능한 secondary 노드인 경우 재구성을 거부됨이라는 의미입니다.

이와 같은 상황에서 에러메세지를 리턴 받았다면 추가시에 우선순위(priority)를 0으로 추가해야 합니다.

rs.add( { host: "127.0.0.1:30002", priority: 0 } )


추가후에 rs.hello() 로 확인하면 다음과 같은 정보를 확인할 수 있습니다.

> rs.hello()
{
  topologyVersion: {
    processId: ObjectId("64f4a9f46da2777084c73a7d"),
    counter: Long("371")
  },
  hosts: [ '127.0.0.1:30001' ],
  passives: [ '127.0.0.1:30002' ],
  arbiters: [ '127.0.0.1:30003' ],
< ... 중략 ... >

새롭게 추가한 멤버 인스턴스가 hosts가 아닌 passives로 등록되어 있습니다.

우선순위(priority)가 0일 경우 passives 유형으로 등록되며 passives는 Primary 멤버가 선출되지 않는 멤버 유형으로 우선순위(priority)가 0일 경우 passives가 됩니다.

또다른 우선순위(priority)가 0인 유형으로 arbiters 가 있습니다.

• rs.conf() 로 멤버 정보 확인 시

> rs.conf()
<...중략...>
  members: [
    {
      _id: 0,
      host: '127.0.0.1:30001',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2,
      host: '127.0.0.1:30003',
      arbiterOnly: true, <!!---
      buildIndexes: true,
      hidden: false,
      priority: 0, <!!---
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 3,
      host: '127.0.0.1:30002',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 0, <!!---
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    }


0으로 추가 후에 1로 변경해야 하며 아래 "Replica Set 설정 변경" 에서 설명합니다.

 

추가하려는 멤버가 Arbiter 유형일 경우 rs.add 가 아닌 rs.addArb 를 사용하며 호스트:포트 정보 파라미터만 입력하여 추가합니다.

rs.addArb("127.0.0.1:30003")

 

일반 적인 3개 멤버 PSA(primary-secondary-arbiter) 토폴로지에서의 멤버 추가는 호스트:포트 정보만 입력해도 추가할 수 있습니다.

rs.add("127.0.0.1:30004")

또는

> rs.add( { host: "127.0.0.1:30004" } )
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1693767614, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("79444eefbe2b053b7071f8d2d330844e50562673", "hex"), 0),
      keyId: Long("7274628646038405125")
    }
  },
  operationTime: Timestamp({ t: 1693767614, i: 1 })
}

 

• rs.conf() 조회

> rs.conf()
{
  _id: 'reps',
  version: 17,
  term: 137,
  members: [
    {
      _id: 0,
      host: '127.0.0.1:30001',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2,
      host: '127.0.0.1:30003',
      arbiterOnly: true,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 3,
      host: '127.0.0.1:30002',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 4,
      host: '127.0.0.1:30004',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    }
  ],
< ...중략... >


이와 같은 멤버의 추가 변경은 샤드 클러스터 환경에서 각 리플리카셋에서의 멤버의 변경(추가/제거)시에도 동일하게 사용합니다.

멤버 추가 시 초기 데이터

기존 Replica Set에 새로운 멤버를 추가하기 전에 다음 2가지 중 하나의 방법으로 초기 데이터 적재 방식을 고려합니다.

1) 데이터가 없는 새로운 MongoDB 인스턴스 멤버를 기존 Replica Set에 추가하게 되면 MongoDB 복제 프로세스에 의해서 모든 데이터를 복사하게 됩니다.
해당 작업은 DBA의 별도의 설정 없이 데이터가 없는 새로운 멤버를 추가하게 되면 기존 멤버로부터 데이터를 복제합니다.
다만, 기존의 Replica Set에 데이터가 많았을 경우 데이터 복제에 상당한 시간이 소요될 수도 있습니다.

2) 기존 멤버로부터 데이터를 백업해서 수동으로 복사하는 방법입니다.
이 방법은 물리적 백업과 논리적 백업(oplog 이용)을 이용합니다. 백업에 관해서는 아래 포스팅을 참조하시면 됩니다.


기존 멤버의 데이터를 복사 및 백업을 통해서 초기데이터를 구성하게 되면 차이나는 데이터만큼만 복제를 수행하게 되어 최신 데이터를 가진 멤버가 되는데 걸리는 시간을 단축시킬 수 있습니다.

oplog와 관련된 Replica Set 멤버의 현재 상태를 확인하려면 rs.printReplicationInfo() 명령어로 상태를 확인 해보시면 됩니다.

Replica Set 설정 변경

rs.reconfig을 통해서 Replica Set에 대해서 config를 변경할 수 있습니다.

이 config 변경 통해서 여러가지 변경할 수 있으며 멤버의 설정(구성)변경 또는 멤버의 제거 등을 진행할 수 있습니다.

글에서는 멤버의 priority를 변경하는 예시에 대해서 설명합니다.

> rs.conf()
{
  _id: 'reps',
  version: 17,
  term: 137,
  members: [
    {
      _id: 0,
      host: '127.0.0.1:30001',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2,
      host: '127.0.0.1:30003',
      arbiterOnly: true,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 3,
      host: '127.0.0.1:30002',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 4,
      host: '127.0.0.1:30004',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    }
  ],
< ...중략... >


위의 조회 결과에서 두번째 멤버의 우선순위가 0 인 것을 확인할 수 있습니다.

두번째 멤버는 추가할 때 우선순위 0으로 추가된 상태임으로 1로 변경해보도록 하겠습니다.

cfg = rs.conf();
cfg.members[1].priority = 1;
rs.reconfig(cfg);

 

리플라카 셋의 설정도 변경할 수 있습니다.

예를 들어 heartbeatTimeoutSecs 설정을 변경하는 경우 다음과 같은 순서로 변경을 진행합니다.

cfg = rs.conf();
cfg.settings.heartbeatTimeoutSecs = 15;
rs.reconfig(cfg);


Replica Set의 구성 변경은 rs.conf 명령어를 통해서 현재 구성을 가져오고 그 중에서 변경하고자 하는 속성(attribute)를 수정하는 형태로 사용합니다.

 

이번 글에서는 MongoDB Replica Set에서의 멤버의 제거와 추가, 간단한 구성 변경 등을 확인해보았으며 여기에서 마무리하겠습니다.

긴 글 읽어 주셔서 감사합니다.

• 이어지는 다음 글

                 

Reference

Reference URL
mongodb.com/remove-replica-set-member
mongodb.com/method/rs.remove
mongodb.com/rs.reconfig/#mongodb-method-rs.reconfig
mongodb.com/reconfigure-replica-set-with-unavailable-members


연관된 다른 글

 

 

 

           

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