MongoDB更改oplog大小

小亮520cl發表於2018-06-09

【問題說明】

       在生產環境新增secondary10.9.197.6:27017 ,資料量140G,卻同步了一天還未追上資料,透過如下方式檢視同步情況:

檢視主從複製狀態命令,以下兩種方式結果是一致的:

  • 方式一:

use admin
db.runCommand( { replSetGetStatus : 1 } )

指定的值不會影響命令的輸出。此命令提供的資料來源自於包含在由副本集的其他成員傳送到當前例項的心跳中的資料。由於心跳的頻率,這些資料可能是幾秒鐘過期。詳情請參考官檔:

  • 方式二:

rs.status()


      檢視複製狀態,發現狀態是"stateStr" : "RECOVERING"。資訊為"infoMessage" : "could not find member to sync from",使用 rs.syncFrom("10.9.161.130:27017")也無法讓其繼續正常同步。具體資訊如下:

點選(此處)摺疊或開啟

  1. kk-comic-shard01:RECOVERING> rs.status()
  2. {
  3.         "set" : "kk-comic-shard01",
  4.         "date" : ISODate("2017-02-07T02:12:17.613Z"),
  5.         "myState" : 3,
  6.         "term" : NumberLong(5),
  7.         "heartbeatIntervalMillis" : NumberLong(2000),
  8.         "members" : [
  9.                 {
  10.                         "_id" : 2,
  11.                         "name" : "10.9.95.69:27017",
  12.                         "health" : 1,
  13.                         "state" : 7,
  14.                         "stateStr" : "ARBITER",
  15.                         "uptime" : 41966,
  16.                         "lastHeartbeat" : ISODate("2017-02-07T02:12:14.490Z"),
  17.                         "lastHeartbeatRecv" : ISODate("2017-02-07T02:12:15.696Z"),
  18.                         "pingMs" : NumberLong(0),
  19.                         "configVersion" : 19
  20.                 },
  21.                 {
  22.                         "_id" : 4,
  23.                         "name" : "10.9.161.130:27017",
  24.                         "health" : 1,
  25.                         "state" : 1,
  26.                         "stateStr" : "PRIMARY",
  27.                         "uptime" : 41966,
  28.                         "optime" : {
  29.                                 "ts" : Timestamp(1486433534, 636),
  30.                                 "t" : NumberLong(5)
  31.                         },
  32.                         "optimeDate" : ISODate("2017-02-07T02:12:14Z"),
  33.                         "lastHeartbeat" : ISODate("2017-02-07T02:12:14.489Z"),
  34.                         "lastHeartbeatRecv" : ISODate("2017-02-07T02:12:16.435Z"),
  35.                         "pingMs" : NumberLong(0),
  36.                         "electionTime" : Timestamp(1486103572, 783),
  37.                         "electionDate" : ISODate("2017-02-03T06:32:52Z"),
  38.                         "configVersion" : 19
  39.                 },
  40.                 {
  41.                         "_id" : 5,
  42.                         "name" : "10.9.184.101:27017",
  43.                         "health" : 1,
  44.                         "state" : 2,
  45.                         "stateStr" : "SECONDARY",
  46.                         "uptime" : 41966,
  47.                         "optime" : {
  48.                                 "ts" : Timestamp(1486433534, 629),
  49.                                 "t" : NumberLong(5)
  50.                         },
  51.                         "optimeDate" : ISODate("2017-02-07T02:12:14Z"),
  52.                         "lastHeartbeat" : ISODate("2017-02-07T02:12:14.489Z"),
  53.                         "lastHeartbeatRecv" : ISODate("2017-02-07T02:12:16.438Z"),
  54.                         "pingMs" : NumberLong(0),
  55.                         "syncingTo" : "10.9.161.130:27017",
  56.                         "configVersion" : 19
  57.                 },
  58.                 {
  59.                         "_id" : 6,
  60.                         "name" : "10.9.197.6:27017",
  61.                         "health" : 1,
  62.                         "state" : 3,
  63.                         "stateStr" : "RECOVERING",
  64.                         "uptime" : 41985,
  65.                         "optime" : {
  66.                                 "ts" : Timestamp(1486391572, 534),
  67.                                 "t" : NumberLong(5)
  68.                         },
  69.                         "optimeDate" : ISODate("2017-02-06T14:32:52Z"),
  70.                         "maintenanceMode" : 487,
  71.                         "infoMessage" : "could not find member to sync from",
  72.                         "configVersion" : 19,
  73.                         "self" : true
  74.                 }
  75.         ],
  76.         "ok" : 1
  77. }
  78. kk-comic-shard01:RECOVERING> rs.printSlaveReplicationInfo()
  79. source: 10.9.184.101:27017
  80.         syncedTo: Tue Feb 07 2017 10:15:24 GMT+0800 (CST)
  81.         0 secs (0 hrs) behind the primary
  82. source: 10.9.197.6:27017
  83.         syncedTo: Mon Feb 06 2017 22:32:52 GMT+0800 (CST)
  84.         42152 secs (11.71 hrs) behind the primary


【問題原因】


      主要的最後一個操作是從“2017-02-07T02:12:14.489Z”,而secondary最後一個操作是“2017-02-06T14:32:52Z”,大約相差12小時。該window可能會超過複製oplog window(oplog中第一個和最後一個操作條目之間的時間差)。簡單地說,在主伺服器上有太多的操作以使secondary伺服器趕不上。

      在初始同步期間,secondary同步來自的資料是給定時間點的資料。當該時間點的資料被同步時,secondary連線到oplog並應用根據oplog條目之間在所述時間點進行改變。只要oplog儲存上述時間點之間的所有操作,就可以正常同步下去。但OPLOG的大小有限,它是有上限的固定集合。因此,如果在初始同步期間主機上發生的操作比oplog可以保持的更多,最早的操作"fade out"。secondary所有的操作都可以要“構建”相同的資料作為主,拒絕完成同步,狀態一直是RECOVERY模式。


【解決辦法】

        經上面分析,有兩種解決辦法:

  • 方法一:停止應用,這樣主庫不會有操作,就不會使得oplog window小於主庫的操作。
  • 方法二:調大oplog大小

如果不能停庫的情況下,顯然方法一是不合適的,應該選擇方法二:調大oplog大小


修改oplog大小


方法1:不停服務情況下

         參考官檔:

 

1 Restart a Secondary in Standalone Mode on a Different Port

       1) db.shutdownServer()

       2) 用其他埠以單機模式重新啟動該例項,不使用--replSet引數

          方法一:根據生產環境引數檔案設定啟動mongo,即將非預設情況引數進行指定

          如下引數根據生產引數檔案來設定,情況不一:   

       /data/servers/app/mongodb-3.2.8/bin/mongod --port 37017 --dbpath /data/servers/data/mg27017/data/ --directoryperdb  --wiredTigerDirectoryForIndexes   --nojournal  &

         該方法較為麻煩,建議選擇下面的方法二:

        方法二:將引數檔案進行修改:註釋replSet部分,修改port為37017,然後以改完後的控制檔案來啟動mongo

         /data/servers/app/mongodb-3.2.8/bin/mongod -f /data/servers/data/mg27017/mongod.conf

          下面截圖顯示的是隻要更改的部分,埠號改為任意的沒被佔用的即可,此處改為37017
        


           netstat -anp | grep $port檢視埠號是否已啟動
        


 

2 Create a Backup of the Oplog (Optional)

           在單機模式(非replSet方式)下備份該37017埠已存在的oplog,oplog對應的集合為local資料庫下的oplog.rs。下面為具體命令:

        /data/servers/app/mongodb-3.2.8/bin/mongodump --db local --collection 'oplog.rs' --port 37017 --host=127.0.0.1 -uroot -p111111111 --authenticationDatabase=admin -o  /data/servers/data/mg27017/dump

【命令說明】

       -o(--out)是制定輸出目錄。該目錄需要執行備份的使用者擁有相應許可權,不用提前建立

       --authenticationDatabase是使用者名稱和密碼對應的認證資料庫,如果環境不需要密碼認證,則-u-p--authenticationDatabase不需要指定


3 Recreate the Oplog with a New Size and a Seed Entry

         儲存oplog中的最後一個條目

         登陸local資料庫

              use local

         定義物件:db

              db = db.getSiblingDB('local')

         使用temp集合來儲存最後一個條目,這個集合保證裡面沒有資料:db.temp.drop(),在刪除前確認下該資料是否可以刪除,如果不可以刪除,使用另一個集合也是一樣的。此處temp沒有資料
       


         使用 方法:找到自然順序的逆向排序後的最後一個條目,並將其儲存到一個臨時的集合裡面

             db.temp.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )

         插入後結果為
        



4 Remove the Existing Oplog Collection

        刪除local下的oplog.rs集合,結果返回為true

                 db = db.getSiblingDB('local')
                   db.oplog.rs.drop()
        



5 Create a New Oplog

        建立oplog.rs固定集合,設定大小為4G,該大小根據實際情況來定

             db.runCommand( { create: "oplog.rs", capped: true, size: (4* 1024 *1024*1024) } )


6 Insert the Last Entry of the Old Oplog into the New Oplog

        將之前儲存的oplog的最後一個條目插入到新的oplog裡

                db.oplog.rs.save( db.temp.findOne() )
       


       跟temp結果比對是一致的


7 Restart the Member

       關閉單機例項,要用admin才能關閉

              use admin

            db.shutdownServer()

      將之前更改的操作還原,啟動mongo

             /data/servers/app/mongodb-3.2.8/bin/mongod -f /data/servers/data/mg27017/mongod.conf

       檢視主從複製狀態,確保狀態正常

            db.runCommand( { replSetGetStatus : 1 } )或者rs.status()


8 Repeat Process for all Members that may become Primary

       對要更改oplog大小的所有secondary成員重複此過程。


9 Change the Size of the Oplog on the Primary

      對於主庫,需要先將主庫切成從庫,再重複上述oplog調整過程

  • 方法一:

               

  • 方法二:

              config=rs.conf()

              config.members[2].priority = 6

              rs.reconfig(config)

                   此處數字2為rs.conf()裡要變成主庫的secondary所在的次序,從0開始算,與id無關。priority數字最大即變成主庫。舊的主庫調整完後,記得要將priority變為1。


方法2:停服務情況下     

    該方法操作最為簡便,但是需要停服務。具體步驟為

1 關閉mongod例項(所有節點)

         use admin

       db.shutdownServer()

 

2 刪除local資料庫下的所有檔案(PRIMARY節點)

       rm -rf /data/servers/data/mg27017/local/*


3 刪除mongo資料目錄(secondary)

       如果不確定誰是主庫,就mv下資料目錄

       rm -rf /data/servers/data/mg27017/data/*


4 修改所有節點配置檔案(oplogsize)

        oplogSizeMB: 4096


5 重啟所有節點mongod

        /data/servers/app/mongodb-3.2.8/bin/mongod -f /data/servers/data/mg27017/mongod.conf


      該方法會導致主庫如果異常,沒有從庫可切換,不建議使用該方式


【小節】

       設定多大的oplog合適呢,可以根據現在資料大小,io和大致的oplog window時間預估一個合適的大小

rs.printReplicationInfo()

  log length start to end: 當oplog寫滿時可以理解為時間視窗

  oplog last event time: 最後一個操作發生的時間





來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29096438/viewspace-2155886/,如需轉載,請註明出處,否則將追究法律責任。

相關文章