MongoDB分片集群塊分佈
我已經使用 docker-compose 部署了帶有兩個分片(兩個副本集)的 MongoDB 集群。
不幸的是,我在分片之間的塊分佈方面遇到了問題,我是 MongoDB 和數據庫的新手,所以這些問題可能是我誤解了這個話題造成的。描述問題的問題在文章的底部,下面是我的分片集群的配置。
分片集群
它包括:
- 配置副本集,三個 mongod 實例中的每一個都配置有: mongod –configsvr –replSet configReplicaSet –bind_ip 0.0.0.0 –dbpath /data/db –port 27019
- 三個 mongod 實例的第一個副本分片,每個實例配置為: mongod –shardsvr –replSet shardReplicaSet1 –bind_ip 0.0.0.0 –dbpath /data/db –port 27017
- 三個 mongod 實例的第二個副本分片,每個都配置有: mongod –shardsvr –replSet shardReplicaSet2 –bind_ip 0.0.0.0 –dbpath /data/db –port 27017
- 單個 mongos 實例,儘管 docker-compose 中有命令,但它的容器以 /bin/bash 開頭,這是雙重事實,docker 映像中定義的入口點是 /bin/bash,因此它可能會覆蓋 docker-compose
- 單個 mongo shell 實例。
這是 docker-compose.yaml:
version: '2.1' services: mongors1-1: container_name: mongors1-1 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet1 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27011:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.11 stdin_open: true tty: true mongors1-2: container_name: mongors1-2 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet1 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27012:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.12 stdin_open: true tty: true mongors1-3: container_name: mongors1-3 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet1 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27013:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.13 stdin_open: true tty: true mongors2-1: container_name: mongors2-1 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet2 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27021:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.21 stdin_open: true tty: true mongors2-2: container_name: mongors2-2 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet2 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27022:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.22 stdin_open: true tty: true mongors2-3: container_name: mongors2-3 image: mongodb-server-shard command: mongod --shardsvr --replSet shardReplicaSet2 --bind_ip 0.0.0.0 --dbpath /data/db --port 27017 ports: - 27023:27017 expose: - "27017" networks: default: ipv4_address: 172.19.0.23 stdin_open: true tty: true mongocfg1: container_name: mongocfg1 image: mongodb-server-shard command: mongod --configsvr --replSet configReplicaSet --bind_ip 0.0.0.0 --dbpath /data/db --port 27019 ports: - 2001:27019 expose: - "27019" networks: default: ipv4_address: 172.19.0.101 stdin_open: true tty: true mongocfg2: container_name: mongocfg2 image: mongodb-server-shard command: mongod --configsvr --replSet configReplicaSet --bind_ip 0.0.0.0 --dbpath /data/db --port 27019 ports: - 2002:27019 expose: - "27019" networks: default: ipv4_address: 172.19.0.102 stdin_open: true tty: true mongocfg3: container_name: mongocfg3 image: mongodb-server-shard command: mongod --configsvr --replSet configReplicaSet --bind_ip 0.0.0.0 --dbpath /data/db --port 27019 ports: - 2003:27019 expose: - "27019" networks: default: ipv4_address: 172.19.0.103 stdin_open: true tty: true mongo-client: container_name: mongo-client1 image: mongodb-client ports: - 5000:5000 expose: - "5000" networks: default: ipv4_address: 172.19.0.50 stdin_open: true tty: true mongos1: container_name: mongos1 image: mongodb-mongos command: mongos --configdb configReplicaSet/mongocfg1:27019,mongocfg2:27019 --bind_ip 0.0.0.0 ports: - 3300:3300 expose: - "3300" - "27017" networks: default: ipv4_address: 172.19.0.150 stdin_open: true tty: true # iperf3-server: # container_name: iperf3-server # image: networkstatic/iperf3 # expose: # - "5201" # command: iperf -s # networks: # default: # ipv4_address: 172.19.0.200 # stdin_open: true # tty: true # iperf3-client: # container_name: iperf3-client # image: networkstatic/iperf3 # expose: # - "5202" # command: iperf -c 172.19.0.200 # networks: # default: # ipv4_address: 172.19.0.201 # stdin_open: true # tty: true
我沒有使用官方的 docker hub 圖像,而是我自己的,它們非常簡單,基本安裝,不同之處在於例如帶有 mongod 的容器只安裝了 mongod 而不是整個 MongoDB 安裝,同樣,mongos 只安裝了 mongos。我認為這可能是問題的根源。
iperf3 容器用於測量 Docker 橋接網路的速度,它們導致超過 50 Gbites/s 的頻寬,因此它應該不是問題的根源。
集群的進一步配置如下:
- 我從 mongo-client1(使用 docker attach 之後)連接到其中一個配置伺服器並執行
rs.initiate({_id:“configReplicaSet”,configsvr:真,成員:
$$ { _id : 0, host : “mongocfg1:27019” }, { _id : 1, host : “mongocfg2:27019” }, { _id : 2, host : “mongocfg3:27019” } $$ } ) 2. 同樣,我連接到 shardReplicaSet1 mongod 實例之一併執行:
rs.initiate(
{
_id : “shardReplicaSet1”,
成員:
$$
{ _id : 0, host : “mongors1-1:27017” }, { _id : 1, host : “mongors1-2:27017” }, { _id : 2, host : “mongors1-3:27017”} $$}) 3. 以類似的方式,我啟動 shardReplicaSet2。 4. 我使用 docker attach 到 mongos1 容器並使用以下命令啟動 mongos: mongos –configdb configReplicaSet/mongocfg1:27019,mongocfg2:27019 –bind_ip 0.0.0.0
- 我從 mongo-client1 連接到 mongos1 並執行:sh.addShard(“shardReplicaSet1/mongors1-1:27017”) 和 sh.addShard(“shardReplicaSet2/mongors2-1:27017”),我不知道這是否有必要但我使用每個副本集的主要成員的主機名。
問題
- 連接到 mongos1,我使用名為“performance”的集合創建名為“key_v”的數據庫,然後在數據庫(sh.enableSharding(“key_v”))上啟用分片,然後
使用分片鍵進行集合:
sh.shardCollection(“key_v.性能”,{“地址”:1})
然後我使用 for 循環向其中插入許多文件:
for(i=0; i<=10000; i++)
{
db.collection.insert(“address”: i,“array1”:
$$ 999, “foo” $$);
} 哦,我之前將塊大小設置為 1 MB。因此,循環結束後,db.collection.getShardDistribution() 的結果顯示所有塊僅位於一個分片上,幾分鐘後實際上塊在分片之間均勻分佈。這是我的問題:mongos 是否不應該在循環執行期間在分片之間分配塊,而不是將它們全部定向到一個分片?如果可以配置,我應該如何實現?這樣? [https://docs.mongodb.com/manual/tutorial/manage-shard-zone/]
[Math Processing Error]$$ 1 $$. 也許分片鍵不正確? 2. 另一個相關案例:我嘗試使用 mongorestore 在 bson 中導入大型 MongoDB 數據庫。我是從 Docker 網路外部進行的: mongorestore –host 127.19.0.150:3300 -d import1 -c test /path/base.bson 導入效果很好,但是所有塊都位於一個分片中。此外,將這些塊遷移到第二個分片非常慢,數據庫重 1.3 GB,40 分鐘後只有 32% 的塊被遷移。數據庫數據模式由多個欄位組成,我選擇了一個 Int32 數據類型的欄位作為分片鍵,但它的基數非常低,15% 的文件具有相同的值,這可能是它的來源嗎?每個塊的估計數據為 529KiB(getShardDistribution() 方法結果)。
所有容器都在具有 32GB RAM 和 i7-6700HQ 的電腦上執行,緩慢的 HDD 是否會成為導致塊遷移如此緩慢的瓶頸?
因此,循環結束後,db.collection.getShardDistribution() 的結果顯示所有塊僅位於一個分片上,幾分鐘後實際上塊在分片之間均勻分佈。這是我的問題:mongos 是否不應該在循環執行期間在分片之間分配塊,而不是將它們全部定向到一個分片?
問題是您使用的是單調遞增的分片鍵。這將導致所有插入針對目前具有表示最高分片鍵值的塊範圍的單個分片(也稱為“熱分片”)。數據最終會重新平衡到其他分片,但這並不是將分片用於寫入擴展的有效用途。您需要選擇一個更合適的 shard key。如果您的案例不需要範圍查詢,您還可以考慮在欄位上使用散列分片鍵。
address
有關預期結果的說明,請參閱Hashed vs Ranged Sharding。另一個相關案例:我嘗試使用 mongorestore 在 bson 中導入大型 MongoDB 數據庫。我是從 Docker 網路外部進行的: mongorestore –host 127.19.0.150:3300 -d import1 -c test /path/base.bson 導入效果很好,但是所有塊都位於一個分片中。
如果結果相似(所有插入都進入單個分片,然後被重新平衡),這也表明分片鍵選擇不佳。
如果您要批量插入空的分片集合,則可以使用一種方法來最小化重新平衡:根據現有數據中分片鍵值的已知分佈預先拆分塊範圍。
數據庫數據模式由多個欄位組成,我選擇了一個 Int32 數據類型的欄位作為分片鍵,但它的基數非常低,15% 的文件具有相同的值,這可能是它的來源嗎?
低基數的分片鍵肯定會導致數據分佈問題。可能的最細粒度的塊範圍將表示單個分片鍵值。如果您的大部分文件共享相同的分片鍵值,則這些最終將導致不可分割
jumbo chunks
,這將被平衡器忽略。所有容器都在具有 32GB RAM 和 i7-6700HQ 的電腦上執行,緩慢的 HDD 是否會成為導致塊遷移如此緩慢的瓶頸?
沒有足夠的資訊來確定您的磁碟是否是最大的限制因素,但是在具有慢速 HDD 的單台電腦上執行分片集群肯定會增加資源爭用的挑戰。除非您為部署添加或刪除分片,否則選擇適當的分片鍵應最大限度地減少數據遷移的需要。
假設您使用的是最新版本的 MongoDB,預設使用 WiredTiger 儲存引擎(MongoDB 3.2+),您肯定希望顯式設置
--wiredTigerCacheSizeGB
以限制mongod
實例的內部記憶體大小。請參閱:我應該將 WiredTiger 內部記憶體設置為多大?.