全部產品
Search
文件中心

ApsaraDB for MongoDB:升級MongoDB執行個體後,各分區Chunks數量不均衡

更新時間:Jul 03, 2026

將ApsaraDB for MongoDB分區叢集執行個體升級到6.0版本(小版本7.0.1及以上)或更高版本後,通過sh.status()查看分區資訊時,會發現各Shard上的Chunk數量明顯不均衡,甚至每個Shard只有1個Chunk。本文說明這一現象的原因,並介紹如何正確判斷資料均衡情況。

問題現象

使用ApsaraDB for MongoDB分區叢集執行個體時,部分使用者在將執行個體升級到6.0版本(小版本7.0.1及以上)後,通過sh.status()查看分區資訊,發現各Shard上的Chunk數量不均衡,與升級前每個Shard上Chunk數量大致相等的情況明顯不同。常見的現象包括:

  • 6.0版本(小版本7.0.1起):各Shard上的Chunk數量差異較大,不再像舊版本那樣大致相等。

  • 7.0及以上版本:各Shard上可能只有1個Chunk。

通常會產生以下疑問:

  • 資料是不是沒有均衡分布?

  • Balancer是不是沒有正常工作?

  • 是不是升級出了什麼問題?

說明

這是升級後的正常行為,資料仍然是均衡分布的,無需擔心。新版本不再以Chunk數量作為均衡標準,而是以實際資料大小為依據。

原因說明

舊版本行為(6.0版本小版本7.0.1之前)

在ApsaraDB for MongoDB6.0版本(小版本7.0.1)之前,分區叢集的資料均衡機制如下:

  1. 每個Chunk預設最大64 MB。

  2. 當資料寫入使Chunk超過64 MB時,會自動分裂(AutoSplit)為多個小Chunk。

  3. Balancer定期檢測各Shard上的Chunk數量,發現數量差異超過閾值後執行遷移(moveChunk)。

  4. 最終各Shard上會有大量Chunk,且數量大致相等。

這種機制下,您通過sh.status()能看到每個Shard上有多個Chunk,可以直觀地感受到資料是均衡分布的。

6.0版本變化(小版本7.0.1起,對應社區版6.0.3)

ApsaraDB for MongoDB從6.0版本(小版本7.0.1)開始,對應社區版MongoDB 6.0.3的Balancer改進,進行了以下重大變更:

  • 取消自動分裂(AutoSplit):Chunk寫滿後不再自動分裂,僅在遷移前進行必要的分割。

  • 均衡判斷標準改變:從基於Chunk數量改為基於實際資料大小。

  • 遷移閾值調整:當不同分區上同一集合的資料大小差異超過3倍ChunkSize(ApsaraDB for MongoDB6.0版本起預設ChunkSize為128 MB,即差異超過384 MB)時觸發遷移。

  • 術語變更:Chunk概念弱化,改稱為Range;moveChunk被moveRange取代。

  • 集合分區前不再需要執行sh.enableSharding()命令。

影響:由於取消了AutoSplit且不再以Chunk數量為均衡依據,各Shard上的Chunk數量可能不相等,這是正常現象。更多資訊,請參見sh.enableAutoSplit()。

7.0版本新增:AutoMerger自動合并

從MongoDB 7.0開始,引入了AutoMerger功能:

  • Balancer會自動將同一Shard上可合并的連續Chunk合并在一起。

  • AutoMerger作為均衡操作的一部分在後台運行,預設啟用。

  • 每隔autoMergerIntervalSecs秒進行一次自動合并。

  • 如果設定了均衡視窗,AutoMerger僅在該視窗期間運行。

影響:在7.0及以上版本中,由於AutoMerger的存在,各Shard上的Chunk最終可能合并為1個Chunk。這同樣是正常行為。更多資訊,請參見AutoMerger。

為什麼做這些改變?

舊版本基於Chunk數量做均衡判斷存在以下問題:

問題

說明

Jumbo Chunk

分區鍵區分度不足時,同一Chunk中所有文檔的分區鍵相同,Chunk無法分割,導致各Shard的Chunk數量相同但磁碟空間使用不同。

寫入傾斜

範圍分區鍵含遞增屬性時,新資料集中寫入一個Shard。

資源消耗

頻繁的AutoSplit和moveChunk消耗大量CPU資源,影響業務效能。

新版本基於實際資料大小做均衡判斷,更加準確地反映資料分布情況,同時減少了不必要的Chunk分裂和遷移操作。

版本對應關係

ApsaraDB for MongoDB本

對應社區版

Balancer行為

4.4版本

MongoDB 4.4

舊行為:AutoSplit + Chunk數量均衡

5.0版本

MongoDB 5.0

舊行為:AutoSplit + Chunk數量均衡

6.0版本(小版本7.0.0)

MongoDB 6.0.0

舊行為:AutoSplit + Chunk數量均衡

6.0版本(小版本7.0.1起)

MongoDB 6.0.3

取消AutoSplit + 資料大小均衡(Chunk數量可能不均衡)

7.0及以上版本

MongoDB 7.0+

取消AutoSplit + 資料大小均衡 + AutoMerger自動合并Chunk

版本前後對比

對比項

6.0版本(小版本7.0.1之前)

6.0版本(小版本7.0.1起)

7.0及以上版本

自動分裂(AutoSplit)

開啟,Chunk寫滿自動分裂

關閉

關閉

自動合并(AutoMerger)

無

無

開啟,自動合并Chunk

均衡判斷依據

Chunk數量

實際資料大小

實際資料大小

各Shard的Chunk數量

多個,數量大致相等

不均衡,數量可能不相等

可能合并為1個

遷移閾值

Chunk數量差異≥1(4.2+)

資料大小差異超過3倍ChunkSize

資料大小差異超過3倍ChunkSize

enableSharding命令

分區前必須執行

6.0+可跳過

可跳過

查看均衡方式

sh.status()看Chunk數量

getShardDistribution()看資料大小

getShardDistribution()看資料大小

實測資料

以下為使用YCSB工具分別向4.4、6.0、8.0版本的ApsaraDB for MongoDB分區叢集執行個體各插入5000萬條資料後的實測結果。

4.4版本(舊行為)

執行sh.status(),重點關注輸出中的chunkMetadata欄位——每個Shard上有435個Chunk,數量相等,這是舊版本AutoSplit自動分裂的結果:

mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfda6dec76b373f5eda81') }
---
shards
[
  {
    _id: 'd-uf6d*****04f784',
    host: 'mgset-100239890/10.**.**.1*9:3005,20.**.**.1*9:3002',
    state: 1
  },
  {
    _id: 'd-uf6f*****39f74',
    host: 'mgset-100***91/20.**.**.**7:3002,20.**.**.**8:3002',
    state: 1
  }
]
---
active mongoses
[ { '4.4.30': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
  'Currently enabled': 'yes',
  'Failed balancer rounds in last 5 attempts': 0,
  'Currently running': 'no',
  'Migration Results for the last 24 hours': { '947': 'Success' }
}
---
databases
[
  {
    database: {
      _id: 'ycsb',
      primary: 'd-uf6f*****39f74',
      partitioned: true
    },
    collections: {
      'ycsb.test1': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [
          { shard: 'd-uf6d*****04f784', nChunks: 435 },
          { shard: 'd-uf6f*****39f74', nChunks: 435 }
        ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  }
]

執行db.test1.getShardDistribution(),關注每個Shard的data(資料大小)和chunks(Chunk數量)欄位:

mongos> use ycsb
switched to db ycsb
mongos> db.test1.getShardDistribution()
Shard d-uf6d*****04f784 at mgset-100239890/10.**.**.1*9:3005,20.**.**.1*9:3002
{
  data: '27.2GiB',
  docs: 25014674,
  chunks: 435,
  'estimated data per chunk': '64.04MiB',
  'estimated docs per chunk': 57504
}
---
Shard d-uf6f*****39f74 at mgset-100239891/20.**.**.**7:3002,20.**.**.**8:3002
{
  data: '36.23GiB',
  docs: 33313293,
  chunks: 435,
  'estimated data per chunk': '85.29MiB',
  'estimated docs per chunk': 76582
}
---
Totals
{
  data: '63.44GiB',
  docs: 58327967,
  chunks: 870,
  'Shard d-uf6d*****04f784': [
    '42.88 % data',
    '42.88 % docs in cluster',
    '1KiB avg obj size on shard'
  ],
  'Shard d-uf6f*****39f74': [
    '57.11 % data',
    '57.11 % docs in cluster',
    '1KiB avg obj size on shard'
  ]
}

6.0版本(小版本7.0.1起)

執行sh.status(),關注chunkMetadata欄位——各Shard上的Chunk數量明顯不均衡(216 vs 1):

mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdc420578638757c1d06') }
---
shards
[
  {
    _id: 'd-uf610*****d8904',
    host: 'mgset-100239905/20.**.**.**1:3002,20.**.**.**3:3002',
    state: 1,
    topologyTime: Timestamp({ t: 1778122310, i: 2 })
  },
  {
    _id: 'd-uf6aa*****67314',
    host: 'mgset-100239903/20.**.**.**5:20.**.**.**6:3002',
    state: 1,
    topologyTime: Timestamp({ t: 1778122310, i: 9 })
  }
]
---
active mongoses
[ { '6.0.27': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
  'Currently running': 'no',
  'Currently enabled': 'yes',
  'Failed balancer rounds in last 5 attempts': 0,
  'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
  {
    database: {
      _id: 'ycsb',
      primary: 'd-uf6aa*****67314',
      partitioned: false,
      version: {
        uuid: UUID('4ee45231-9585-4dba-8f34-f624860e1a79'),
        timestamp: Timestamp({ t: 1778122930, i: 1 }),
        lastMod: 1
      }
    },
    collections: {
      'ycsb.test2': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        allowMigrations: true,
        chunkMetadata: [
          { shard: 'd-uf610*****d8904', nChunks: 216 },
          { shard: 'd-uf6aa*****67314', nChunks: 1 }
        ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  }
]

執行db.test2.getShardDistribution(),關注每個Shard的data佔比——雖然Chunk數量差異巨大(216 vs 1),但資料仍然均衡分布(50.31% vs 49.68%):

mongos> use ycsb
switched to db ycsb
mongos> db.test2.getShardDistribution()
Shard d-uf6aa*****67314 at mgset-100239903/20.**.**.**5:20.**.**.**6:3002
{
  data: '27.36GiB',
  docs: 32285618,
  chunks: 1,
  'estimated data per chunk': '27.36GiB',
  'estimated docs per chunk': 32285618
}
---
Shard d-uf610*****d8904 at mgset-100239905/20.**.**.**1:3002,20.**.**.**3:3002
{
  data: '27.01GiB',
  docs: 24841944,
  chunks: 216,
  'estimated data per chunk': '128.09MiB',
  'estimated docs per chunk': 115009
}
---
Totals
{
  data: '54.38GiB',
  docs: 57127562,
  chunks: 217,
  'Shard d-uf6aa*****67314': [
    '50.31 % data',
    '56.51 % docs in cluster',
    '1KiB avg obj size on shard'
  ],
  'Shard d-uf610*****d8904': [
    '49.68 % data',
    '43.48 % docs in cluster',
    '1KiB avg obj size on shard'
  ]
}

8.0版本(含AutoMerger)

遷移剛完成時,執行sh.status(),關注chunkMetadata欄位——各Shard上仍有多個Chunk(55 vs 1):

mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdbdd7b0e3d9551dd833') }
---
shards
[
  {
    _id: 'd-uf65a*****ac94',
    host: 'mgset-100239911/20.**.**.**7:3000,20.**.**.**6:3002',
    state: 1,
    topologyTime: Timestamp({ t: 1778122320, i: 8 }),
    replSetConfigVersion: Long('-1')
  },
  {
    _id: 'd-uf6a8*****c9b14',
    host: 'mgset-100239912/20.**.**.**8:3003,20.**.**.**9:3003',
    state: 1,
    topologyTime: Timestamp({ t: 1778122319, i: 10 }),
    replSetConfigVersion: Long('-1')
  }
]
---
active mongoses
[ { '8.0.18': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
  'Currently enabled': 'yes',
  'Failed balancer rounds in last 5 attempts': 0,
  'Currently running': 'no',
  'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
  {
    database: {
      _id: 'ycsb',
      primary: 'd-uf6a8*****c9b14',
      version: {
        uuid: UUID('98799357-048e-45bc-a472-387165e0fe74'),
        timestamp: Timestamp({ t: 1778122931, i: 2 }),
        lastMod: 1
      }
    },
    collections: {
      'ycsb.test2': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        allowMigrations: true,
        chunkMetadata: [
          { shard: 'd-uf65a*****ac94', nChunks: 55 },
          { shard: 'd-uf6a8*****c9b14', nChunks: 1 }
        ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  }
]

等待AutoMerger自動合并完成後,再次執行sh.status(),關注chunkMetadata欄位——每個Shard上的Chunk已自動合并為1個:

mongos> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('69fbfdbdd7b0e3d9551dd833') }
---
shards
[
  {
    _id: 'd-uf65a*****ac94',
    host: 'mgset-100239911/20.**.**.**7:3000,20.**.**.**6:3002',
    state: 1,
    topologyTime: Timestamp({ t: 1778122320, i: 8 }),
    replSetConfigVersion: Long('-1')
  },
  {
    _id: 'd-uf6a8*****c9b14',
    host: 'mgset-100239912/20.**.**.**8:3003,20.**.**.**9:3003',
    state: 1,
    topologyTime: Timestamp({ t: 1778122319, i: 10 }),
    replSetConfigVersion: Long('-1')
  }
]
---
active mongoses
[ { '8.0.18': 2 } ]
---
autosplit
{ 'Currently enabled': 'yes' }
---
balancer
{
  'Currently enabled': 'yes',
  'Failed balancer rounds in last 5 attempts': 0,
  'Currently running': 'no',
  'Migration Results for the last 24 hours': { '216': 'Success' }
}
---
databases
[
  {
    database: {
      _id: 'ycsb',
      primary: 'd-uf6a8*****c9b14',
      version: {
        uuid: UUID('98799357-048e-45bc-a472-387165e0fe74'),
        timestamp: Timestamp({ t: 1778122931, i: 2 }),
        lastMod: 1
      }
    },
    collections: {
      'ycsb.test2': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        allowMigrations: true,
        chunkMetadata: [
          { shard: 'd-uf65a*****ac94', nChunks: 1 },
          { shard: 'd-uf6a8*****c9b14', nChunks: 1 }
        ],
        chunks: [
          { min: { _id: MinKey() }, max: { _id: Long('-58615400192952365') }, 'on shard': 'd-uf65a*****ac94', 'last modified': Timestamp({ t: 217, i: 2 }) },
          { min: { _id: Long('-58615400192952365') }, max: { _id: MaxKey() }, 'on shard': 'd-uf6a8*****c9b14', 'last modified': Timestamp({ t: 217, i: 1 }) }
        ],
        tags: []
      }
    }
  }
]

執行db.test2.getShardDistribution(),關注每個Shard的data佔比——儘管每個Shard只有1個Chunk,資料仍然均衡分布(49.67% vs 50.32%):

mongos> use ycsb
switched to db ycsb
mongos> db.test2.getShardDistribution()
Shard d-uf65a*****ac94 at mgset-100239911/20.**.**.**7:3000,20.**.**.**6:3002
{
  data: '27.01GiB',
  docs: 24841944,
  chunks: 1,
  'estimated data per chunk': '27.01GiB',
  'estimated docs per chunk': 24841944
}
---
Shard d-uf6a8*****c9b14 at mgset-100239912/20.**.**.**8:3003,20.**.**.**9:3003
{
  data: '27.37GiB',
  docs: 35898246,
  chunks: 1,
  'estimated data per chunk': '27.37GiB',
  'estimated docs per chunk': 35898246
}
---
Totals
{
  data: '54.39GiB',
  docs: 60740190,
  chunks: 2,
  'Shard d-uf65a*****ac94': [
    '49.67 % data',
    '40.89 % docs in cluster',
    '1KiB avg obj size on shard'
  ],
  'Shard d-uf6a8*****c9b14': [
    '50.32 % data',
    '59.1 % docs in cluster',
    '1KiB avg obj size on shard'
  ]
}

結論:三個版本的實測資料表明,無論Chunk數量如何變化(870→217→2),資料始終均衡分布在各Shard上。Chunk數量的差異僅是內部管理機制的變化,不影響實際資料分布和業務。

如何正確判斷資料是否均衡

升級到6.0版本(小版本7.0.1)及以上版本後,請使用以下方式判斷資料均衡情況:

推薦方式:getShardDistribution()

串連到mongos後執行以下命令:

use <your_database>
db.<your_collection>.getShardDistribution()

該命令會返回每個Shard上該集合的資料大小、文檔數量和佔比,能真實反映資料分布情況。

輔助方式:db.stats()

use <your_database>
db.stats()

可以查看資料庫在各Shard節點的整體資料存放區情況。

不再推薦:sh.status()看Chunk數量

sh.status()仍然可以執行,但Chunk數量不再反映資料均衡情況。看到各Shard的Chunk數量不相等或只有1個Chunk都是正常的,不代表資料分布有問題。

常見問題

Q:升級後Chunk數量不均衡或變為1,資料會丟失嗎?

A:不會。Chunk只是MongoDB內部管理資料的邏輯單元,Chunk數量的變化不影響實際資料。資料仍然完整儲存在各Shard上。

Q:需要手動執行split命令來分割Chunk嗎?

A:不需要。新版本的Balancer會在需要遷移資料時自動進行必要的分割,無需手動幹預。

Q:升級後Balancer還在工作嗎?

A:是的。Balancer仍在正常工作,只是判斷標準從Chunk數量改為了資料大小。當各分區間的資料大小差異超過閾值時,Balancer會自動執行資料移轉。

Q:6.0和7.0版本升級後的Chunk表現有什麼不同?

A:6.0版本(小版本7.0.1起)取消了AutoSplit並改用資料大小均衡,各Shard的Chunk數量可能不均衡。7.0版本在此基礎上新增了AutoMerger,會自動合并Chunk,最終每個Shard可能只有1個Chunk。兩種情況下資料都是均衡分布的。

Q:遷移過程中看到多個Chunk是正常的嗎?

A:是正常的。在資料移轉期間,Balancer會對資料進行必要的分割,因此會臨時出現多個Chunk。對於7.0及以上版本,遷移完成後AutoMerger會自動合并這些Chunk;對於6.0版本,這些Chunk可能會保持不變,但不影響資料均衡。

Q:這個變化影響我的業務嗎?

A:不影響。這個改變對業務是透明的,實際上新版本減少了不必要的Chunk分裂和遷移操作,效能反而更好。

參考文檔