๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
MongoDB/์šด์˜

MongoDB Oplog ํฌ๊ธฐ ๋ณ€๊ฒฝํ•˜๊ธฐ

by ๐ŸŒปโ™š 2023. 5. 8.

MongoDB ๋ณต์ œ ๊ตฌ์„ฑ์—์„œ Primary๋กœ๋ถ€ํ„ฐ ๋ฐœ์ƒํ•œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋‹ค๋ฅธ Secondary ๋ฉค๋ฒ„์— ๋ณต์ œํ•˜๊ธฐ ์œ„ํ•ด Oplog๋ผ๋Š” Capped Collection์„ ์‚ฌ์šฉํ•œ๋‹ค. Capped Collection์€ ํฌ๊ธฐ๊ฐ€ ์ œํ•œ ๋œ Collection์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 10GB์˜ Capped Collection์„ ์ƒ์„ฑํ•˜๋ฉด 10GB๋ฅผ ๋„˜์–ด์„œ๋Š” ์ˆœ๊ฐ„ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๋Š” FIFO ๊ตฌ์กฐ์˜ Collection์ด๋‹ค.

 

 

MongoDB์˜ ์ƒํƒœ๊ฐ€ ์ •์ƒ์ผ ๋•Œ๋Š” oplog๋ฅผ ํ†ตํ•ด ๊ธˆ๋ฐฉ ๋ณต์ œ๋ฅผ ๋”ฐ๋ผ๊ฐ„๋‹ค. ๊ทธ๋ž˜์„œ Oplog์˜ Capped ํฌ๊ธฐ๊ฐ€ ์ƒ๊ด€์—†์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์˜์™ธ๋กœ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ด์œ ์— ์˜ํ•ด ํฌ๊ธฐ๋ฅผ ์กฐ์ ˆํ•ด์ค˜์•ผํ•œ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๋ฉด

  • ์„œ๋ฒ„ ์ ๊ฒ€์ด ์˜ค๋ž˜ ๊ฑธ๋ ค์„œ ๋‹ค์‹œ ์ •์ƒ์œผ๋กœ ๋Œ์•„์™”์„ ๋•Œ, initial sync๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ๋ณต์ œ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ ์œ„ํ•ด oplog ํฌ๊ธฐ๋ฅผ ๋Š˜๋ ค์ค€๋‹ค.
  • ํŒŒ์ผ ๋ณต์‚ฌ ํ˜•ํƒœ์˜ ๋ฐฑ์—… ์ •์ฑ…์„ ๊ฐ–๊ณ  ์žˆ์–ด์„œ ๋ฐฑ์—…ํ•˜๋Š” ๋™์•ˆ Fsync Lock์„ ๊ฑธ์–ด์ฃผ๋Š”๋ฐ, ๋ฐฑ์—… ์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ ค์„œ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ oplog ํฌ๊ธฐ๋ฅผ ๋Š˜๋ ค์ค€๋‹ค.
  • ๋งค์ผ ์ •๊ธฐ์ ์œผ๋กœ ๋ฐฐ์น˜ ํ˜•ํƒœ์˜ ํŠธ๋ž˜ํ”ฝ์ด ๋ฐœ์ƒํ•ด์„œ Oplog Window Hour๊ฐ€ 0์— ์ˆ˜๋ ดํ•˜๋Š” ๊ฒฝ์šฐ
  • ์ผ๋ฐ˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๊ณต๊ฐ„์ด ํ•„์š”ํ•ด์„œ Oplog ํฌ๊ธฐ๋ฅผ ์ค„์ด๋Š” ๊ฒฝ์šฐ

 

 

rs_1 [direct: secondary] test> rs.printReplicationInfo()
actual oplog size
'10000 MB'
---
configured oplog size
'10000 MB'
---
log length start to end
'6943753 secs (1928.82 hrs)'
---
oplog first event time
'Fri Feb 17 2023 11:23:12 GMT+0900 (__REGIEON__ Standard Time)'
---
oplog last event time
'Mon May 08 2023 20:12:25 GMT+0900 (__REGIEON__ Standard Time)'
---
now
'Mon May 08 2023 20:12:33 GMT+0900 (__REGIEON__ Standard Time)'

๋“ฑ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์šด์˜์š”์†Œ๋“ค์ด ์žˆ๋‹ค. Oplog Window Hour๋Š” oplog์˜ ๊ฐ€์žฅ ์ฒ˜์Œ๊ณผ ๋งˆ์ง€๋ง‰ ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์‹œ๊ฐ„ ์ฐจ์ด๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๋Œ€๋žต์ ์œผ๋กœ ์–ผ๋งˆ๋‚˜ ๋ณต์ œ๊ฐ€ ์ง€์—ฐ๋˜์–ด๋„ oplog๋ฅผ ํ†ตํ•ด ๋”ฐ๋ผ๊ฐˆ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์น˜์ด๋‹ค.

 

 

๊ทธ๋ž˜์„œ ๋ฐœ์ƒํ•˜๋Š” DML ํŠธ๋ž˜ํ”ฝ์— ๋”ฐ๋ผ ์œ„์™€ ๊ฐ™์ด ์˜ค๋ฅด๊ณ  ๋‚ด๋ฆฌ๊ณ ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋ˆŒ๋ฆผ๋ชฉ์ด ์žˆ๋Š” ๋ถ€๋ถ„์€ ํŠธ๋ž˜ํ”ฝ์ด ํ‰์†Œ๋ณด๋‹ค ๋งŽ์€ ๊ฒฝ์šฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์—ฌํ•˜ํŠผ, ์šด์˜ํ•˜๋Š” ๊ด€์ ์—์„œ Oplog ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์ฃผ์˜์‚ฌํ•ญ๋„ ์•Œ๊ณ  ์žˆ์–ด์•ผํ•œ๋‹ค.

 

 

Oplog ์ˆ˜์ •

Distribution : 3 Member Replica set
Version : MongoDB 5.0.13

Oplog ์„ค์ •์€ mongod ํ”„๋กœ์„ธ์Šค๋ฅผ ์ตœ์ดˆ์— ์˜ฌ๋ฆด ๋•Œ, ์˜ต์…˜ ํ˜น์€ config file๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ๊ธฐ์กด์— oplog size ์„ค์ •์ด ์•ˆ๋˜์–ด ์žˆ์—ˆ๋‹ค๋ฉด MongoDB์—์„œ ์ž๋™์œผ๋กœ ๋ช‡ ๊ฐ€์ง€ ๊ณ„์‚ฐ์„ ํ†ตํ•ด ์„ค์ •ํ•œ๋‹ค. Oplog๋Š” Online ์ƒํƒœ์—์„œ ๋ช…๋ น์œผ๋กœ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ํ˜ผ๋™์ด ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์€ oplog๊ฐ€ ํ•œ๋ฒˆ ์„ค์ •๋˜๊ณ  ๋‚˜์„œ config file์ด๋‚˜ ์˜ต์…˜์„ ์ˆ˜์ •ํ•˜๊ณ  ์žฌ๊ธฐ๋™ํ•ด๋„ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ด๊ฒŒ ํ—ท๊ฐˆ๋ ค์„œ oplog ์ˆ˜์ •ํ•˜๋ฉด ๊ธฐ๋™ ์˜ต์…˜์ด๋‚˜ config file๋„ ํ•จ๊ป˜ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

 

 

Oplog ๋Š˜๋ฆฌ๊ธฐ

์ค„์ด๋Š”๋ฐ๋Š” Primary์™€ Secondary ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ๋‹ค. ๋Š˜๋ฆฌ๋Š”๊ฒฝ์šฐ, ์ˆœ์„œ๋‚˜ ๋ณ‘๋ ฌ ์ž‘์—… ๋“ฑ ์ƒ๊ด€์—†๋‹ค.

rs_1 [direct: secondary] test> use local
switched to db local
rs_1 [direct: secondary] local> db.oplog.rs.stats().maxSize
2097152000

๋จผ์ € ์„ค์ •๋œ Oplog Size๋ฅผ ํ™•์ธํ•œ๋‹ค. 2GB๋กœ ์„ค์ •๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 

[root@__HOST__:/root/mongodb/data]$ du -sh *
340K    admin
348K    config
200M    diagnostic.data
300M    journal
188M    local
...
...

 

local database์˜ ๋ฌผ๋ฆฌ์ ์€ ํฌ๊ธฐ๋„ ํ™•์ธํ•ด์„œ ์ผ์ • ์ˆ˜์น˜ ์ดํ›„๋กœ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•ด๋ณด์ž.

 

 

function makeTxt(length) {
    let result = '';
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const charactersLength = characters.length;
    let counter = 0;
    while (counter < length) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
      counter += 1;
    }
    return result;
}

for(var i=0; i<10; i++){
	var arr = [];
    for(var j=0; j<10000; j++){
    	arr.push({a: j, txt: makeTxt(100)})
    };
    db.test.insertMany(arr);
};

์œ„์™€ ๊ฐ™์ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—ฌ๋Ÿฟ ๋ฐœ์ƒํ•˜๋„๋ก ์‹คํ–‰ํ•ด๋ณด์ž. ์ตœ๋Œ€ ํฌ๊ธฐ๊นŒ์ง€ ๋„๋‹ฌํ•˜๋„๋ก ์ˆ˜์ •ํ•  ์˜ˆ์ •์ด๋‹ค. MongoDB๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์••์ถ•ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌผ๋ฆฌ์ ์ธ ํฌ๊ธฐ๊ฐ€ Oplog์˜ ์ตœ๋Œ€์น˜๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, Oplog์˜ ์„ค์ • ํฌ๊ธฐ๋Š” ์••์ถ•ํ•˜๊ธฐ ์ด์ „์ธ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ํฌ๊ธฐ์ด๋‹ค. oplog๋ฅผ ๋‹ค ์‚ฌ์šฉํ–ˆ๋Š”์ง€๋Š” collection์˜ ์„ธ๋ถ€ ์ •๋ณด์™€ ๋ณต์ œ์ •๋ณด๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

rs_1 [direct: primary] local> rs.printReplicationInfo()
actual oplog size
'2000 MB'
---
configured oplog size
'2000 MB'
---
log length start to end
'463.9999930858612 secs (0.13 hrs)'
---
oplog first event time
'Mon May 08 2023 20:52:21 GMT+0900 (__REGIEON__ Standard Time)'
---
oplog last event time
'Mon May 08 2023 21:00:05 GMT+0900 (__REGIEON__ Standard Time)'
---
now
'Mon May 08 2023 21:00:05 GMT+0900 (__REGIEON__ Standard Time)'

rs_1 [direct: primary] local> db.oplog.rs.stats().maxSize
2097152000
rs_1 [direct: primary] local> db.oplog.rs.stats().size
2091786256

๋ฌผ๋ฆฌ์ ์ธ ํฌ๊ธฐ๋„ ํ™•์ธํ•˜๋ฉด ์–ด๋Š์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋Š˜์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. oplog collection์— ๋Œ€ํ•œ Stat์„ ํ™•์ธํ•ด๋ณด๋ฉด ์ตœ๋Œ€ํฌ๊ธฐ๊นŒ์ง€ ์‚ฌ์šฉํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๊ณ  Oplog Window Hour๋„ ํฌ๊ฒŒ ์ค„์–ด๋“  ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋” ๋‹ด์„ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์น˜๋ฅผ ๋Š˜๋ ค๋ณด๊ฒ ๋‹ค.

 

 

rs_1 [direct: primary] test> db.adminCommand({replSetResizeOplog: 1, size: Double(3000)})
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1683547464, i: 2 }),
    signature: {
      hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
      keyId: Long("0")
    }
  },
  operationTime: Timestamp({ t: 1683547464, i: 2 })
}

rs_1 [direct: primary] local> db.oplog.rs.stats().maxSize
Long("3145728000")
rs_1 [direct: primary] local> db.oplog.rs.stats().size
2091791838

MB ๋‹จ์œ„๋กœ ๊ฐ’์„ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ  ๋ณ€๊ฒฝ ์ดํ›„์—๋„ maxSize๊ฐ€ ๋Š˜์–ด๋‚œ ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

 

 

Oplog ์ค„์ด๊ธฐ

Oplog๋ฅผ ์ค„์ผ ๋•Œ๋Š” ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค. Secondary ๋จผ์ € ์ค„์—ฌ์ฃผ๊ณ  ์ดํ›„ Primary๋ฅผ ์ค„์—ฌ์ค˜์•ผํ•œ๋‹ค. ํฌ๊ธฐ๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ์ˆœ์„œ๋„ ์ƒ๊ด€์—†์ง€๋งŒ, ์ค„์ธ ํ›„ ์•„๋ฌด๋Ÿฐ ๋ณ€๊ฒฝ์ด ์—†์œผ๋ฉด ๋ฐ์ดํ„ฐ ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚จ์•„ ํ•ด๋‹น ๊ณต๊ฐ„์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๊ทธ๋ž˜์„œ compaction๊นŒ์ง€ ์ˆ˜ํ–‰ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด secondary์—์„œ ๋จผ์ € ์‹คํ–‰ํ•˜๊ณ  stepdown ํ›„, ๋‚˜๋จธ์ง€ ๋ฉค๋ฒ„๋„ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค.

  1. Secondary ๋จผ์ € oplog ์ค„์ธ๋‹ค.
  2. Secondary์—์„œ compaction ๋ช…๋ น ์ˆ˜ํ–‰ํ•œ๋‹ค.
  3. Primary Stepdown
  4. Stepdownํ•œ  Primary๋„ oplog๋ฅผ ์ค„์ธ๋‹ค.
  5. ๋‹ค์‹œ compaction

 

 

[root@__HOST__:/root/mongodb/data]$ du -sh local
449M    local

ํ˜„์žฌ ๋ฌผ๋ฆฌ์ ์ธ ํฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜๊ณ  Secondary๋ถ€ํ„ฐ Oplog ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค.

 

 

# Secondary ์ˆ˜ํ–‰
rs_1 [direct: secondary] test> db.adminCommand({replSetResizeOplog: 1, size: Double(990)})
rs_1 [direct: secondary] test> use local
rs_1 [direct: secondary] local> db.runCommand({ "compact" : "oplog.rs" } )

# Primary ์ˆ˜ํ–‰
rs_1 [direct: primary] test> rs.stepDown()
rs_1 [direct: secondary] test> db.adminCommand({replSetResizeOplog: 1, size: Double(990)})

์ž‘์—…์€ ๊ฐ„๋‹จํ•˜๋‹ค. Primary์—์„œ๋„ Compaction ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ „์— ๋ฌผ๋ฆฌ์ ์ธ ํฌ๊ธฐ๋ฅผ ํ™•์ธํ•˜์ž. ์œ„์™€ ๋™์ผํ•˜๊ฒŒ ๋ฌผ๋ฆฌ์ ์ธ ํฌ๊ธฐ๋Š” ์ค„์–ด๋“ค์ง€ ์•Š์€ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

rs_1 [direct: secondary] test> use local
rs_1 [direct: secondary] local> db.runCommand({ "compact" : "oplog.rs" } )

### ๋ฌผ๋ฆฌ์  ํฌ๊ธฐ ํ™•์ธ
[root@__HOST__:/root/mongodb/data]$ du -sh local
268M    local

compact ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‚˜์„œ์•ผ ๋ฌผ๋ฆฌ์  ๋ฐ์ดํ„ฐ ํŒŒ์ผ ํฌ๊ธฐ๊ฐ€ ์ค„์–ด๋“  ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. compaction์€ ์„ ํƒ์ ์ด์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฅผ ๋” ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์šฉ๋Ÿ‰ํ™•๋ณด๋ฅผ ๋ฏธ๋ฆฌ ํ•ด๋†“๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๊ผญ ํ•จ๊ป˜ ์ˆ˜ํ–‰ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

๋Œ“๊ธ€