MongoDB mongoshake 遷移分片到複製集合

ITPUB社群發表於2023-11-30

  來源:AustinDatabases


Mongoshake 是阿里雲自研的開源工具,實現Mongodb 資料庫之間的資料同步,資料災備,資料多活,分庫分表,版本升級無間斷。

其中需要注意的一些事項

1  Mongoshake 儘量使用較高的版本,低版本的產品有一些Bug 
2 Mongoshake 在使用中需要源庫的使用者許可權為readAnyDatabase  同時Mongoshake 會開始自動在原例項中自建自己的資料庫,來進行資料同步的事宜,目的庫需要有 readWriteAnyDatabases 的許可權
3  開源版本僅僅支援單向同步,並且在同步的全量過程中,嚴謹對資料庫的進行任何DDL的操作,包含索引,加表,刪除表,改名等操作。

下面把一些與mongoshake有關的引數進行一個學習和整理
這裡有一個注意事項,就是mongo 的賬號密碼,不能帶有 @符號,否則應用程式無法處理,密碼中也不能帶有 ,:\ /  ?等符號

1  master_quorum  一般情況下這個引數為false 開啟此引數的主要原因是,當你有兩個mongoshake 都在抽取一個源端的情況下,就需要開啟這個引數  master_quorum = true

2  log.level  = info  這個部分預設可以不動,如果熟悉mongoshake 可以將這個問題之調整為 error   log.level = error 

3  log.dir = /mongoshake/log/  存放mongoshake工作中日誌的位置
4  log.file = collector.log  存放mongoshake的日誌的名字
5  log.flush = false  這裡建議一開始使用時設定為true ,在mongoshake 工作的情況下,可以看到最新的日誌,當然這樣操作可能有一些效能的影響。
6  sync_mode = all  這裡在mongoshake 進行資料同步的情況下,一般情況下都是設定為all ,all 為全量+增量的模式,如果僅僅是全量同步可以設定為 full ,但如果僅僅是增量則設定為 incr
7  源端的讀取地址,在配置這個部分的時候,需要注意
mongo_urls =  這裡如果是複製集的形式,則需要注意你連結的地址是pimary 的還是叢集的,是否帶有 readPreference=secondary,這裡連結的格式mongoshell 的連結格式是一致的逗號分割同一個副本集內的節點,分號分割分片的例項,

mongo_urls = mongodb://username:password@10.1.1.1:1001/admin?readPreference=secondary
8 Mongo_cs_url  = 
9 Mongo_s_url = 
這兩個部分是針對mongosharding 的部分,如果是mongo sharding 遷移,則需要填寫這兩個部分。一個是mongo sharding 的config server ,一個是mongos 的地址。
10 mongo_connect_mode 這個部分和上面的連結部分是相容的,這裡secondaryPreferred 是預設的一個設定,如果這裡拉取的是分片集合,則這裡建議為primary 避免孤兒檔案。
11 tunnel = direct  direct 標識目的端對接的mongodb是 rpc,file, kafka 的情況
其他與tunnel 部分有關的都與本次的遷移無關與kafka 有關,所以這裡就不進行記錄了
12  filter.namespace 這裡需要注意的是,過濾是包含黑名單和白名單的,黑白名單中的指定的部分,不能有衝突,在白名單和黑名單都進行指定。
filter.namespace.black =
filter.namespace.white =

filter.pass.special.db = admin  這裡主要指定的是一些特殊情況下,針對 admin  system.views , mongoshake config 等資料庫在預設不遷移的情況下,因為某些問題,需要進行資料遷移的情況

filter.ddl_enable = false   這個選項是在複製中不對DDL的操作進行復制,所以資料遷移中為避免一些問題,可以使用false 而資料同步的情況就需要考慮開啟這個設定。

13  關於併發

 full_sync.reader.collection_parallel  =6 這個引數預設為 6 為一次最大併發拉取的表的數目,拉取一次過多,會導致IOPS 升高影響業務。

full_sync.reader.write_document_parallel = 8 ,對於一個表進行拉取的過程中,產生多少執行緒,來同時進行資料的拉取,這裡注意要有主鍵。

full_sync.reader.document_batch_size  一次將寫入多少檔案進行聚合 128  表示一次寫入 128個檔案進行聚合 預設值為128

14  這兩個引數是 2.6.4引入的引數,分別對於單 collation 拉取是併發的拉取數進行設定,這裡預設為 1 對於分片的部分,目前不建議設定此引數,預設為1 
full_sync.reader.parallel_thread
full_sync.reader.parallel_index

15  結構化引數

full_sync.executor.insert_on_dup_update = false 

在目的庫存在同樣的資料庫和collation 是否要進行insert to update的轉換

full_sync.executor.filter.orphan_document = false 
源端是shareding 的情況,是否要考慮過濾孤兒的檔案,預設是不考慮。

這裡是關於此次mongoshake與引數有關的部分。

關於在資料遷移中的孤兒檔案的問題,孤兒檔案的產生來自於mongoshake 全量的階段而讀取資料的方式是secondaryPreferred 的方式, 導致讀取惡劣secondary節點的資料,而secondary 節點的資料和local 的方式不同,導致讀取的資料產生問題的過程。這裡為了防止問題,在讀取的時候,如果MONGODB版本在3.6以下則讀取的readPreferred 改為primary  對於 3.6 readconcern 改為 local,或者採用full_sync.executor.insert_on_dup_update = true 來進行過濾,不過此訪問不建議。

另外還應該針對mongodb均衡器balancer 在對於分片到複製集的情況下,將其關閉,在MongoDB 5.0 之前的版本,當shard節點上的chunk 數量達到遷移閥值,banlancer對shared 節點上的chunk 進行遷移,會盡量保證shard節點的數量在各個節點是相同的。


在遷移前還要對mongodb的分片集合,做關閉balancer 的操作,透過mongos 進入到資料庫中.
use config
while( sh.isBalancerRunning() ) {
          print("waiting...");
          sleep(1000);
}
sh.stopBalancer()

當然在使用完畢後可以在儘快的 開啟balancer 功能

sh.setBalancerState(true)

啟動mongoshake 有兩種方法
1  透過start.sh 來啟動mongoshake, 如sh start.sh collector.conf
2  透過 ./collector -conf=collector.conf -verbose

下面就將整體的工作情況進行一個流程化的記錄

1  登入到分片的mongodb 中,確認當前的工作狀態

這裡可以看到,balancer 是開啟的狀態,當前並未執行

[mongos] admin> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('5e1bdb2dbd7ea0ac43') }
---
shards
[
  {
    _id: 'd-2ze2fde064',
    host: 'mgset-21218075/7:3044',
    state: 1
  },
  {
    _id: 'd-2ze77e7e4e38ad64',
    host: 'mgset-21218077/',
    state: 1
  }
]
---
active mongoses
[ { '4.2.1': 1 }, { '4.2.10': 1 } ]
---
autosplit
'Currently enabled''yes' }
---
balancer
{
  'Currently enabled''yes',
  'Currently running''no',
  'Failed balancer rounds in last 5 attempts': 0,
  'Migration Results for the last 24 hours': { '11''Success' }
}
---
databases
[
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {
      'config.system.sessions': {
        shardKey: { _id: 1 },
        unique: false,
        balancing: true,
        chunkMetadata: [
          { shard: 'd-2ze2fde06cf92d74', nChunks: 512 },
          { shard: 'd-2ze77e7e4e38ad64', nChunks: 512 }
        ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  },
  {
    database: {
      _id: 'report',
      primary: 'd-2ze77e7e4e38ad64',
      partitioned: true,
      version: {
        uuid: UUID('a3efc46e-b05f-4557-af1b-ddfeb212dd5e'),
        lastMod: 1
      }
    },
    collections: {
      'report.request_record_new': {
        shardKey: { requestId: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [
          { shard: 'd-2ze2fde06cf92d74', nChunks: 42853 },
          { shard: 'd-2ze77e7e4e38ad64', nChunks: 42852 }
        ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  }
]

[mongos] config> sh.stopBalancer()
{
  ok: 1,
  operationTime: Timestamp({ t: 1701137103, i: 45 }),
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1701137103, i: 45 }),
    signature: {
      hash: Binary.createFromBase64('9RIHAXxDGxhwvcAVNQw5N0/3w9g=', 0),
      keyId: Long('7253280536863440980')

這裡我們關閉mongo sharding 的balancer ,限制當前balancer已經關閉。
active mongoses
[ { '4.2.1': 1 }, { '4.2.10': 1 } ]
---
autosplit
'Currently enabled''no' }
---
balancer
{
  'Currently running''no',
  'Currently enabled''no',


然後我們配置mongoshake 的配置檔案,這裡需要注意,由於是分片,則需要配置三個地址,config  ,mongos ,shardings
vi collector.conf 
conf.version = 10
id = mongoshake
master_quorum = false
full_sync.http_port = 9190
incr_sync.http_port = 9190
system_profile_port = 820
log.level = info
log.dir = /mongoshake
log.file = collector.log
log.flush = false
sync_mode = all

mongo_urls = mongodb://mongosd:g_cs_1127@d-2183.mongodb.com:3797;mongodb://mongos:fe1127@d64952.mongodb.com:3797

mongo_cs_url = mongodb://mongocs:feg_cs_1127@ddee63.mongodb.rdscom:3719/admin

mongo_s_url = mongodb://ot9:%301%2318a4.mong.com:3719/admin

tunnel = direct
tunnel.address = mongodb://otg:B3X@dds-2ze220fb41051a641.moncom:377,1a642.mongodbs.com:377/admin?replicaSet=mset-73
tunnel.message = raw

tunnel.kafka.partition_number = 1
mongo_connect_mode = primary

這裡有幾個地方需要注意
1  在進行collectiion.conf 檔案的編寫中,分片作為源的情況下,需要注意需要填寫三個地址  1.1  普通連線分片的地址  1.2 config server 的primary的地址  1.3 mongos 的地址,並且注意urls 中的地址的寫法必須是每個sharding的primary的主地址,並且以 ;分號進行分割,有幾個sharding 就的寫幾個,差一個,就會丟資料。

剩下的就是啟動mongoshake 來同步資料,同步的速度比較快,尤其在開啟多執行緒的基礎上,預設是 8個,如果你的系統強悍,完全可以到16 24 只要IOPS 和CPU 可以支援的情況下。

2  在執行目錄執行 collector.linux -conf=collector.conf

在進行工作中遇到的一些問題,與相關的解答,當遇到oplog 無法進行初始化的錯誤時,同時你又是分片的情況下,請參看下面的回答。

Q: How to solve the "Oplog Tailer initialize failed: no oplog ns in mongo" error?

A: This is usually a problem with insufficient account permissions, so, please check your permission of oplog table. If the source is sharding, the account should be added into each shard because there is no local database in mongos. When source is sharding, the mongo_urls should be the shards address split by semicolon(;) like: mongo_urls: mongodb://user1:passwd1@10.1.1.1:20011,10.1.1.2:20112;mongodb://user2:passwd2@10.1.2.1:20011,10.1.2.2:20112. Since v2.0.6, MongoShake doesn't throw this error when sync mode is full sync(sync_mode = document).

在實際的工作中還有其他的問題,有時間可以繼續說,整體傳輸的速度比較快,基本在較低的配置下 4C 8G  ,每秒的傳輸效率在 0.1G左右。

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

相關文章