MongoDB分片集群部署,使用

一、准备环境

  • 1、建议使用新安装的虚拟机,不然会报各种离谱错误。
  • 2、建议使用同一个版本的数据库,不然数据字典不一致可能导致各种问题。

1 服务器详情

1.1 服务器配置(示例)
信息
操作系统Red Hat Enterprise Linux Server release 7.8 (Maipo)
CPU1(Thread) × 1(Core) × 4(Socket)
内存4GB
磁盘40G
1.2 部署情况(示例)
服务器IPOS登录信息节点状态、部署服务及对应端口号
192.168.6.107mongod/mongodshard1,sard2,config,mongos
192.168.6.108mongod/mongodshard1,sard2,config,mongos
192.168.6.111mongod/mongodshard1,sard2,config,mongos

生产中使用的常见分片集群架构:
在这里插入图片描述

  • 数据分片:分片用于存储真正的数据,并提供最终的数据读写访问。分片仅仅是一个逻辑的概念,它可以是一个单独的mongod实例,也可以是一个复制集。图中的Shard1、Shard2都是一个复制集分片。在生产环境中也一般会使用复制集的方式,这是为了防止数据节点出现单点故障

  • 配置服务器(Config Server):配置服务器包含多个节点,并组成一个复制集结构,对应于图中的ConfigReplSet。配置复制集中保存了整个分片集群中的元数据,其中包含各个集合的分片策略,以及分片的路由表等。

  • 查询路由(mongos):mongos是分片集群的访问入口,其本身并不持久化数据。mongos启动后,会从配置服务器中加载元数据。之后mongos开始提供访问服务,并将用户的请求正确路由到对应的分片。在分片集群中可以部署多个mongos以分担客户端请求的压力。

2 版本

服务名称版本信息
MongoDB“6.0.16”

3 部署目录

名称目录位置
shard目录/data/shard/
config目录/data/config/
mongos目录/data/mongos/

二、搭建分片集群

在这里插入图片描述
图片来源:

https://s2.51cto.com/images/blog/202405/25000834_6650bb82170d373715.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=/format,webp/resize,m_fixed,w_1184

2.1、使用DNS服务解析IP

在3台虚拟机上执行以下命令,防止ip变动导致连接失败

echo "192.168.6.107  mongo1 mongo01.com mongo02.com" >> /etc/hosts
echo "192.168.6.108 mongo2 mongo03.com mongo04.com" >> /etc/hosts
echo "192.168.6.111 mongo3 mongo05.com mongo06.com" >> /etc/hosts

创建安装目录

[root@postgres /]# mkdir -p /data/shard1/db  /data/shard1/log   /data/config/db  /data/config/log
[root@postgres /]# mkdir -p /data/shard2/db  /data/shard2/log   /data/mongos/
[root@postgres /]# cd data
[root@postgres data]# ls
config  mongos  shard1  shard2

2.2、安装集群

环境准备,请参考之前的文章

2.2.1、在三个节点上执行相同的命令,安装shard1分片

[root@postgres /]# mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /data/shard1/db --logpath /data/shard1/log/mongod.log --port 27010 --fork --shardsvr
about to fork child process, waiting until server is ready for connections.
forked process: 4408
child process started successfully, parent exiting

##查看监听端口,判断数据库实例是否启动成功

[root@postgres /]# netstat -tunl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27010           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN   

登录shard1分片的mongo01节点,初始化主备复制集群

命令:

# 进入mongo shell
mongo mongo01.com:27010
#shard1复制集节点初始化
rs.initiate({
    _id: "shard1",
    "members" : [
    {
        "_id": 0,
        "host" : "mongo01.com:27010"
    },
    {
        "_id": 1,
        "host" : "mongo03.com:27010"
    },
    {
        "_id": 2,
        "host" : "mongo05.com:27010"
    }
    ]
})
#查看复制集状态
rs.status()
[root@postgres /]# mongosh mongo01.com:27010
Current Mongosh Log ID: 66a1a8f87459571da0482f8a
Connecting to:          mongodb://mongo01.com:27010/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-25T09:22:13.739+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-25T09:22:13.739+08:00: You are running this process as the root user, which is not recommended
   2024-07-25T09:22:13.739+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T09:22:13.739+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T09:22:13.739+08:00: Soft rlimits for open file descriptors too low
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.
test> rs.initiate({
    _id: "shard1",
...     _id: "shard1",
...     "members" : [
...     {
...         "_id": 0,
...         "host" : "mongo01.com:27010"
    },
...     },
    {
...     {
...         "_id": 1,
...         "host" : "mongo03.com:27010"
...     },
...     {
...         "_id": 2,
...         "host" : "mongo05.com:27010"
...     }
...     ]
... })
{ ok: 1 }

查看shard1分片的主、备集群状态信息

shard1 [direct: secondary] test> rs.status()
{
  set: 'shard1',
  date: ISODate('2024-07-25T01:24:32.227Z'),
  myState: 1,
  term: Long('1'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
    lastCommittedWallTime: ISODate('2024-07-25T01:24:25.038Z'),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
    appliedOpTime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
    durableOpTime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
    lastAppliedWallTime: ISODate('2024-07-25T01:24:25.038Z'),
    lastDurableWallTime: ISODate('2024-07-25T01:24:25.038Z')
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1721870645, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate('2024-07-25T01:23:24.996Z'),
    electionTerm: Long('1'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1721870594, i: 1 }), t: Long('-1') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1721870594, i: 1 }), t: Long('-1') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    numCatchUpOps: Long('0'),
    newTermStartDate: ISODate('2024-07-25T01:23:25.020Z'),
    wMajorityWriteAvailabilityDate: ISODate('2024-07-25T01:23:26.007Z')
  },
  members: [
    {
      _id: 0,
      name: 'mongo01.com:27010',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 139,
      optime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T01:24:25.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      lastDurableWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1721870604, i: 1 }),
      electionDate: ISODate('2024-07-25T01:23:24.000Z'),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo03.com:27010',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 77,
      optime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T01:24:25.000Z'),
      optimeDurableDate: ISODate('2024-07-25T01:24:25.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      lastDurableWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      lastHeartbeat: ISODate('2024-07-25T01:24:31.056Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T01:24:32.057Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo01.com:27010',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'mongo05.com:27010',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 77,
      optime: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721870665, i: 1 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T01:24:25.000Z'),
      optimeDurableDate: ISODate('2024-07-25T01:24:25.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      lastDurableWallTime: ISODate('2024-07-25T01:24:25.038Z'),
      lastHeartbeat: ISODate('2024-07-25T01:24:31.056Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T01:24:32.057Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo01.com:27010',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721870665, i: 1 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721870665, i: 1 })
}
shard1 [direct: primary] test> 

2.2.2、在三个节点上执行相同的命令,安装config主备集群


[root@postgres /]# mongod --bind_ip 0.0.0.0 --replSet config --dbpath /data/config/db \
--logpath /data/config/log/mongod.log --port 27019 --fork \
--configsvr

[root@postgres /]# netstat -tunl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27010           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27019           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     

初始化config主、备集群

命令:

# 进入mongo shell
mongo mongo01.com:27019
#config复制集节点初始化
rs.initiate({
    _id: "config",
    "members" : [
    {
        "_id": 0,
        "host" : "mongo01.com:27019"
    },
    {
        "_id": 1,
        "host" : "mongo03.com:27019"
    },
    {
        "_id": 2,
        "host" : "mongo05.com:27019"
    }
    ]
})
[root@postgres data]# mongosh mongo01.com:27019
Current Mongosh Log ID: 66a1bb5ca7a9cd7327482f8a
Connecting to:          mongodb://mongo01.com:27019/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-25T10:39:35.878+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-25T10:39:35.878+08:00: You are running this process as the root user, which is not recommended
   2024-07-25T10:39:35.878+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T10:39:35.878+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T10:39:35.878+08:00: Soft rlimits for open file descriptors too low
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.
test> rs.initiate({
    _id: "config",
...     _id: "config",
...     "members" : [
...     {
...         "_id": 0,
...         "host" : "mongo01.com:27019"
...     },
...     {
...         "_id": 1,
...         "host" : "mongo03.com:27019"
...     },
...     {
...         "_id": 2,
...         "host" : "mongo05.com:27019"
...     }
...     ]
... })
{ ok: 1, lastCommittedOpTime: Timestamp({ t: 1721875301, i: 1 }) }

查看config 集群状态信息

config [direct: other] test> rs.status()
{
  set: 'config',
  date: ISODate('2024-07-25T02:41:54.994Z'),
  myState: 1,
  term: Long('1'),
  syncSourceHost: '',
  syncSourceId: -1,
  configsvr: true,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
    lastCommittedWallTime: ISODate('2024-07-25T02:41:53.947Z'),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
    appliedOpTime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
    durableOpTime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
    lastAppliedWallTime: ISODate('2024-07-25T02:41:53.947Z'),
    lastDurableWallTime: ISODate('2024-07-25T02:41:53.947Z')
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1721875301, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate('2024-07-25T02:41:52.604Z'),
    electionTerm: Long('1'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1721875301, i: 1 }), t: Long('-1') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1721875301, i: 1 }), t: Long('-1') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    numCatchUpOps: Long('0'),
    newTermStartDate: ISODate('2024-07-25T02:41:52.631Z'),
    wMajorityWriteAvailabilityDate: ISODate('2024-07-25T02:41:53.740Z')
  },
  members: [
    {
      _id: 0,
      name: 'mongo01.com:27019',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 139,
      optime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:41:53.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1721875312, i: 1 }),
      electionDate: ISODate('2024-07-25T02:41:52.000Z'),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo03.com:27019',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 13,
      optime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:41:53.000Z'),
      optimeDurableDate: ISODate('2024-07-25T02:41:53.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      lastHeartbeat: ISODate('2024-07-25T02:41:54.612Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T02:41:54.119Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo01.com:27019',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'mongo05.com:27019',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 13,
      optime: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721875313, i: 6 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:41:53.000Z'),
      optimeDurableDate: ISODate('2024-07-25T02:41:53.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:41:53.947Z'),
      lastHeartbeat: ISODate('2024-07-25T02:41:54.612Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T02:41:54.121Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo01.com:27019',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  lastCommittedOpTime: Timestamp({ t: 1721875313, i: 6 }),
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875313, i: 6 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875313, i: 6 })
}
config [direct: primary] test> exit
[root@postgres data]# 

2.2.3、启动mongos路由指定config集群

##获取mongos路由组件
[root@postgres MongoDB]# cd /opt/soft/MongoDB
[root@postgres MongoDB]# ls
mongodb-org-server-6.0.16-1.el7.x86_64.rpm
[root@postgres MongoDB]# wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/development/x86_64/RPMS/mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm
--2024-07-24 17:04:12--  https://repo.mongodb.org/yum/redhat/7/mongodb-org/development/x86_64/RPMS/mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm
Resolving repo.mongodb.org (repo.mongodb.org)... 18.65.185.2, 18.65.185.40, 18.65.185.55, ...
Connecting to repo.mongodb.org (repo.mongodb.org)|18.65.185.2|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 23048860 (22M)
Saving to: ‘mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm’

100%[==============================================================================================================================>] 23,048,860  2.32MB/s   in 11s    

2024-07-24 17:04:27 (1.92 MB/s) - ‘mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm’ saved [23048860/23048860]

[root@postgres MongoDB]# ls
mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm  mongodb-org-server-6.0.16-1.el7.x86_64.rpm
[root@postgres MongoDB]# rpm -i mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm
warning: mongodb-org-mongos-6.0.16-0.1.latest.el7.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID adcea95c: NOKEY

#启动mongos,指定config复制集,在三个节点上
[root@postgres data]# mongos --bind_ip 0.0.0.0 --logpath /data/mongos/mongos.log --port 27018 --fork --configdb config/mongo01.com:27019,mongo03.com:27019,mongo05.com:27019
about to fork child process, waiting until server is ready for connections.
forked process: 3026
child process started successfully, parent exiting
[root@postgres data]# netstatus -tunl
bash: netstatus: command not found...
[root@postgres data]# netstat -tunl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27010           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27018           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:27019           0.0.0.0:*               LISTEN     

登录mongos路由,查看分片集群信息

[root@postgres MongoDB]# mongosh mongo01.com:27018
Current Mongosh Log ID: 66a0c491000cee292e482f8a
Connecting to:          mongodb://mongo01.com:27018/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16-76-g98a4071
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-24T17:07:13.580+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-24T17:07:13.580+08:00: You are running this process as the root user, which is not recommended
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.
[direct: mongos] test>


#查看mongos状态
[direct: mongos] test> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('66a0b495bbf76dae205a98f5') }
---
shards
[]
---
active mongoses
[]
---
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': 'No recent migrations'
}
---
databases
[
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {}
  }
]

登录mongos路由,添加分片集群

[root@postgres data]# mongosh mongo01.com:27018
Current Mongosh Log ID: 66a1bc855eb6cf9613482f8a
Connecting to:          mongodb://mongo01.com:27018/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16-76-g98a4071
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-25T10:43:45.052+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-25T10:43:45.052+08:00: You are running this process as the root user, which is not recommended
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.
[direct: mongos] test> sh.addShard("shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010")
{
  shardAdded: 'shard1',
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875602, i: 4 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875602, i: 4 })
}
[direct: mongos] test> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('66a1bb70e1aa48bb499ba9de') }
---
shards
[
  {
    _id: 'shard1',
    host: 'shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010',
    state: 1,
    topologyTime: Timestamp({ t: 1721875602, i: 1 })
  }
]
---
most recently active mongoses
[ { '6.0.16-76-g98a4071': 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': 'No recent migrations'
}
---
databases
[
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {}
  }
]
[direct: mongos] test> 

创建分片集合

  • 为了使集合支持分片,需要先创建数据库,开启database的分片功能:sh.enableSharding(“company”)
  • 执行shardCollection命令,对集合执行分片初始化:sh.shardCollection(“company.emp”, {_id: ‘hashed’})
  • 查询集合的数据分布,验证分片集群正常使用:db.emp.getShardDistribution()
#为了使集合支持分片,需要先开启database的分片功能

[direct: mongos] test> sh.enableSharding("company")
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875687, i: 6 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875687, i: 3 })
}
[direct: mongos] test> sh.shardCollection("company.emp", {_id: 'hashed'})
{
  collectionsharded: 'company.emp',
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875701, i: 35 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875701, i: 31 })
}
[direct: mongos] test> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('66a1bb70e1aa48bb499ba9de') }
---
shards
[
  {
    _id: 'shard1',
    host: 'shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010',
    state: 1,
    topologyTime: Timestamp({ t: 1721875602, i: 1 })
  }
]
---
most recently active mongoses
[ { '6.0.16-76-g98a4071': 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': 'No recent migrations'
}
---
databases
[
  {
    database: {
      _id: 'company',
      primary: 'shard1',
      partitioned: false,
      version: {
        uuid: UUID('22a27479-9ccc-4fe1-ae1c-91e73fd9f8d9'),
        timestamp: Timestamp({ t: 1721875687, i: 1 }),
        lastMod: 1
      }
    },
    collections: {
      'company.emp': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 2 } ],
        chunks: [
          { min: { _id: MinKey() }, max: { _id: Long('0') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 0 }) },
          { min: { _id: Long('0') }, max: { _id: MaxKey() }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) }
        ],
        tags: []
      }
    }
  },
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {}
  }
]
[direct: mongos] test> 

添加第shard2分片到分片集群


##先在三个节点上创建集群
[root@postgres data]# mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /data/shard2/db --logpath /data/shard2/log/mongod.log --port 27011 --fork --shardsvr
about to fork child process, waiting until server is ready for connections.
forked process: 4340
child process started successfully, parent exiting
[root@postgres data]# mongosh mongo06.com:27011
Current Mongosh Log ID: 66a1bd79d547ac7889482f8a
Connecting to:          mongodb://mongo06.com:27011/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-25T10:50:00.546+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-25T10:50:00.546+08:00: You are running this process as the root user, which is not recommended
   2024-07-25T10:50:00.546+08:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T10:50:00.546+08:00: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never' in this binary version
   2024-07-25T10:50:00.546+08:00: Soft rlimits for open file descriptors too low
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.


###初始化shard2分片主、备集群
rs.initiate({
    _id: "shard2",
    "members" : [
    {
        "_id": 0,
        "host" : "mongo06.com:27011"
    },
    {
        "_id": 1,
        "host" : "mongo02.com:27011"
    },
    {
        "_id": 2,
        "host" : "mongo04.com:27011"
    }
    ]
})
#查看复制集状态
rs.status()


test> rs.initiate({
    _id: "shard2",
    "members" : [
...     _id: "shard2",
...     "members" : [
    {
...     {
...         "_id": 0,
...         "host" : "mongo06.com:27011"
...     },
...     {
...         "_id": 1,
...         "host" : "mongo02.com:27011"
...     },
...     {
...         "_id": 2,
...         "host" : "mongo04.com:27011"
...     }
...     ]
... })
{ ok: 1 }

##查看shard2分片集群的主、备复制状态信息
shard2 [direct: secondary] test> rs.status();
{
  set: 'shard2',
  date: ISODate('2024-07-25T02:51:19.143Z'),
  myState: 1,
  term: Long('1'),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long('2000'),
  majorityVoteCount: 2,
  writeMajorityCount: 2,
  votingMembersCount: 3,
  writableVotingMembersCount: 3,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
    lastCommittedWallTime: ISODate('2024-07-25T02:51:12.388Z'),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
    appliedOpTime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
    durableOpTime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
    lastAppliedWallTime: ISODate('2024-07-25T02:51:12.388Z'),
    lastDurableWallTime: ISODate('2024-07-25T02:51:12.388Z')
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1721875861, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate('2024-07-25T02:51:11.993Z'),
    electionTerm: Long('1'),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1721875861, i: 1 }), t: Long('-1') },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1721875861, i: 1 }), t: Long('-1') },
    numVotesNeeded: 2,
    priorityAtElection: 1,
    electionTimeoutMillis: Long('10000'),
    numCatchUpOps: Long('0'),
    newTermStartDate: ISODate('2024-07-25T02:51:12.033Z'),
    wMajorityWriteAvailabilityDate: ISODate('2024-07-25T02:51:12.328Z')
  },
  members: [
    {
      _id: 0,
      name: 'mongo06.com:27011',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 79,
      optime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:51:12.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1721875871, i: 1 }),
      electionDate: ISODate('2024-07-25T02:51:11.000Z'),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    },
    {
      _id: 1,
      name: 'mongo02.com:27011',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 17,
      optime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:51:12.000Z'),
      optimeDurableDate: ISODate('2024-07-25T02:51:12.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      lastHeartbeat: ISODate('2024-07-25T02:51:18.018Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T02:51:18.528Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo06.com:27011',
      syncSourceId: 0,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    },
    {
      _id: 2,
      name: 'mongo04.com:27011',
      health: 1,
      state: 2,
      stateStr: 'SECONDARY',
      uptime: 17,
      optime: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
      optimeDurable: { ts: Timestamp({ t: 1721875872, i: 12 }), t: Long('1') },
      optimeDate: ISODate('2024-07-25T02:51:12.000Z'),
      optimeDurableDate: ISODate('2024-07-25T02:51:12.000Z'),
      lastAppliedWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      lastDurableWallTime: ISODate('2024-07-25T02:51:12.388Z'),
      lastHeartbeat: ISODate('2024-07-25T02:51:18.018Z'),
      lastHeartbeatRecv: ISODate('2024-07-25T02:51:17.525Z'),
      pingMs: Long('0'),
      lastHeartbeatMessage: '',
      syncSourceHost: 'mongo02.com:27011',
      syncSourceId: 1,
      infoMessage: '',
      configVersion: 1,
      configTerm: 1
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875872, i: 12 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875872, i: 12 })
}
shard2 [direct: primary] test> exit

##登录mongos路由,把shard2分片加入到分片集群中来
[root@postgres data]# mongosh mongo06.com:27018
Current Mongosh Log ID: 66a1bdef2d874ac667482f8a
Connecting to:          mongodb://mongo06.com:27018/?directConnection=true&appName=mongosh+2.2.12
Using MongoDB:          6.0.16-76-g98a4071
Using Mongosh:          2.2.12

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-07-25T10:43:45.527+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-07-25T10:43:45.527+08:00: You are running this process as the root user, which is not recommended
------


Deprecation warnings:
  - Using mongosh on the current operating system is deprecated, and support may be removed in a future release.
See https://www.mongodb.com/docs/mongodb-shell/install/#supported-operating-systems for documentation on supported platforms.

##添加shard2分片到分片集群
[direct: mongos] test> sh.addShard("shard2/mongo02.com:27011,mongo04.com:27011,mongo06.com:27011")
{
  shardAdded: 'shard2',
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721875973, i: 7 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721875973, i: 7 })
}
[direct: mongos] test> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('66a1bb70e1aa48bb499ba9de') }
---
shards
[
  {
    _id: 'shard1',
    host: 'shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010',
    state: 1,
    topologyTime: Timestamp({ t: 1721875602, i: 1 })
  },
  {
    _id: 'shard2',
    host: 'shard2/mongo02.com:27011,mongo04.com:27011,mongo06.com:27011',
    state: 1,
    topologyTime: Timestamp({ t: 1721875973, i: 5 })
  }
]
---
most recently active mongoses
[ { '6.0.16-76-g98a4071': 1 } ]
---
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': 'No recent migrations'
}
---
databases
[
  {
    database: {
      _id: 'company',
      primary: 'shard1',
      partitioned: false,
      version: {
        uuid: UUID('22a27479-9ccc-4fe1-ae1c-91e73fd9f8d9'),
        timestamp: Timestamp({ t: 1721875687, i: 1 }),
        lastMod: 1
      }
    },
    collections: {
      'company.emp': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 2 } ],
        chunks: [
          { min: { _id: MinKey() }, max: { _id: Long('0') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 0 }) },
          { min: { _id: Long('0') }, max: { _id: MaxKey() }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) }
        ],
        tags: []
      }
    }
  },
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {
      'config.system.sessions': {
        shardKey: { _id: 1 },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 1024 } ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  }
]

2.2.4、创建分片集合,测试数据在每个分片的分布情况


##创建shop数据库,开启分片功能
[direct: mongos] test> sh.enableSharding("shop")
{
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721876093, i: 3 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721876092, i: 2 })
}

##创建分片集合
[direct: mongos] test> sh.shardCollection("shop.product",{productId:"hashed"},false,{numInitialChunks:4})
{
  collectionsharded: 'shop.product',
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1721876138, i: 50 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1721876138, i: 40 })
}

##查看整个分片集群的信息
[direct: mongos] test> sh.status()
shardingVersion
{ _id: 1, clusterId: ObjectId('66a1bb70e1aa48bb499ba9de') }
---
shards
[
  {
    _id: 'shard1',
    host: 'shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010',
    state: 1,
    topologyTime: Timestamp({ t: 1721875602, i: 1 })
  },
  {
    _id: 'shard2',
    host: 'shard2/mongo02.com:27011,mongo04.com:27011,mongo06.com:27011',
    state: 1,
    topologyTime: Timestamp({ t: 1721875973, i: 5 })
  }
]
---
most recently active mongoses
[ { '6.0.16-76-g98a4071': 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': 'No recent migrations'
}
---
databases
[
  {
    database: {
      _id: 'company',
      primary: 'shard1',
      partitioned: false,
      version: {
        uuid: UUID('22a27479-9ccc-4fe1-ae1c-91e73fd9f8d9'),
        timestamp: Timestamp({ t: 1721875687, i: 1 }),
        lastMod: 1
      }
    },
    collections: {
      'company.emp': {
        shardKey: { _id: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 2 } ],
        chunks: [
          { min: { _id: MinKey() }, max: { _id: Long('0') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 0 }) },
          { min: { _id: Long('0') }, max: { _id: MaxKey() }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) }
        ],
        tags: []
      }
    }
  },
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {
      'config.system.sessions': {
        shardKey: { _id: 1 },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 1024 } ],
        chunks: [
          'too many chunks to print, use verbose if you want to force print'
        ],
        tags: []
      }
    }
  },
  {
    database: {
      _id: 'shop',
      primary: 'shard2',
      partitioned: false,
      version: {
        uuid: UUID('b019c3c1-38e2-460a-a4ee-022df7663267'),
        timestamp: Timestamp({ t: 1721876092, i: 1 }),
        lastMod: 1
      }
    },
    collections: {
      'shop.product': {
        shardKey: { productId: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [
          { shard: 'shard1', nChunks: 2 },
          { shard: 'shard2', nChunks: 2 }
        ],
        chunks: [
          { min: { productId: MinKey() }, max: { productId: Long('-4611686018427387902') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 0 }) },
          { min: { productId: Long('-4611686018427387902') }, max: { productId: Long('0') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) },
          { min: { productId: Long('0') }, max: { productId: Long('4611686018427387902') }, 'on shard': 'shard2', 'last modified': Timestamp({ t: 1, i: 2 }) },
          { min: { productId: Long('4611686018427387902') }, max: { productId: MaxKey() }, 'on shard': 'shard2', 'last modified': Timestamp({ t: 1, i: 3 }) }
        ],
        tags: []
      }
    }
  }
]
[direct: mongos] test> 

插入测试数据,查看数据在个个分片的分布

##查看数据库信息
[direct: mongos] test> show databases
admin    80.00 KiB
company  12.00 KiB
config    2.84 MiB
shop     24.00 KiB
[direct: mongos] test> use company
switched to db company

##查看集合
[direct: mongos] company> show collections;
emp

#插入测试数据
 use company
for (var i = 0; i < 10000; i++) {
    db.emp.insert({i: i});
}
#查询数据分布
db.emp.getShardDistribution()

##切换到单个分片的数据库
[direct: mongos] company> use company
already on db company
[direct: mongos] company> for (var i = 0; i < 10000; i++) {
...     db.emp.insert({i: i});
... }
DeprecationWarning: Collection.insert() is deprecated. Use insertOne, insertMany, or bulkWrite.
^CStopping execution...

##查看company数据库在分片shard1的分布情况
[direct: mongos] company> db.emp.getShardDistribution()
Shard shard1 at shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010
{
  data: '41KiB',
  docs: 1449,
  chunks: 2,
  'estimated data per chunk': '20KiB',
  'estimated docs per chunk': 724
}
---
Totals
{
  data: '41KiB',
  docs: 1449,
  chunks: 2,
  'Shard shard1': [
    '100 % data',
    '100 % docs in cluster',
    '29B avg obj size on shard'
  ]
}


##切换到有两个分片的数据库
[direct: mongos] company> use shop
switched to db shop
[direct: mongos] shop> show collections;
product

##插入数据
db=db.getSiblingDB("shop");
var count=0;
for(var i=0;i<1000;i++){
    var p=[];
    for(var j=0;j<100;j++){
        p.push({
            "productId":"P-"+i+"-"+j,
            name:"羊毛衫",
            tags:[
                {tagKey:"size",tagValue:["L","XL","XXL"]},
                {tagKey:"color",tagValue:["蓝色","杏色"]},
                {tagKey:"style",tagValue:"韩风"}
            ]
        });
    }
    count+=p.length;
    db.product.insertMany(p);
    print("insert ",count)
}



##插入数据
[direct: mongos] shop> db.getSiblingDB("shop");
for(var i=0;i<1000;i++){
shop
[direct: mongos] shop> var count=0;
    var p=[];
    for(var j=0;j<100;j++){

[direct: mongos] shop> for(var i=0;i<1000;i++){
...     var p=[];
...     for(var j=0;j<100;j++){
...         p.push({
            name:"羊毛衫",
...             "productId":"P-"+i+"-"+j,
...             name:"羊毛衫",
...             tags:[
...                 {tagKey:"size",tagValue:["L","XL","XXL"]},
...                 {tagKey:"color",tagValue:["蓝色","杏色"]},
...                 {tagKey:"style",tagValue:"韩风"}
...             ]
...         });
...     }
...     count+=p.length;
...     db.product.insertMany(p);
...     print("insert ",count)
... }
insert  100
insert  200
insert  300
insert  400
insert  500
insert  600
insert  700
insert  800
insert  900
insert  1000
insert  1100
insert  1200
insert  1300
insert  1400
insert  1500
insert  1600
insert  1700
insert  1800
insert  1900
insert  2000
insert  2100
insert  2200
insert  2300
insert  2400
insert  2500
insert  2600
insert  2700
insert  2800
insert  2900
insert  3000
insert  3100
insert  3200
^CStopping execution...

##查看分布情况
[direct: mongos] shop> db.product.getShardDistribution()
Shard shard1 at shard1/mongo01.com:27010,mongo03.com:27010,mongo05.com:27010
{
  data: '420KiB',
  docs: 1646,
  chunks: 2,
  'estimated data per chunk': '210KiB',
  'estimated docs per chunk': 823
}
---
Shard shard2 at shard2/mongo02.com:27011,mongo04.com:27011,mongo06.com:27011
{
  data: '422KiB',
  docs: 1654,
  chunks: 2,
  'estimated data per chunk': '211KiB',
  'estimated docs per chunk': 827
}
---
Totals
{
  data: '843KiB',
  docs: 3300,
  chunks: 4,
  'Shard shard1': [
    '49.87 % data',
    '49.87 % docs in cluster',
    '261B avg obj size on shard'
  ],
  'Shard shard2': [
    '50.12 % data',
    '50.12 % docs in cluster',
    '261B avg obj size on shard'
  ]
}
[direct: mongos] shop>

三 、查看分片集群的数据分布

3.1、分片集群启、停顺序

  • 启动顺序,先启动config和再启动shard最后启动mongos
##启动配置集群
mongod --bind_ip 0.0.0.0 --replSet config --dbpath /data/config/db \
--logpath /data/config/log/mongod.log --port 27019 --fork \
--configsvr

##启动分片集群
mongod --bind_ip 0.0.0.0 --replSet shard1 --dbpath /data/shard1/db \
--logpath /data/shard1/log/mongod.log --port 27010 --fork \
--shardsvr

mongod --bind_ip 0.0.0.0 --replSet shard2 --dbpath /data/shard2/db  \
--logpath /data/shard2/log/mongod.log --port 27011 --fork \
--shardsvr

##启动mongos路由
mongos --bind_ip 0.0.0.0 --logpath /data/mongos/mongos.log --port 27018 --fork \
--configdb config/mongo01.com:27019,mongo03.com:27019,mongo05.com:27019
  • 暂停顺序,必须是先停止mongos服务,再停止其它服务。
# 进入mongos命令行
mongosh mongosh01.com:27018
use admin
db.auth('admin','admin.123')
db.shutdownServer()

3.2、分片键

对集合进行分片时, 你需要选择一个 片键( Shard Key ) , shard key 是每条记录都必须包含的 , 且建立了索引的单个字段或复合字段

3.3、数据分布的逻辑,分片策略

MongoDB分片集群上创建一个数据库,开启数据库分片功能,初始化一个分片集合假设这个集合大小是1TB,那么拆分到4个分片上之后,每个分片存储256GB的数据。这个当然是最理想化的场景,实质上很难做到如此绝对的平衡。

如果这个集合很大,则集合中的数据会被切成多个chunk(数据块,默认大小为64M),一个chunk代表了集合中的“一段数据”,例如,用户集合(db.users)在切分成多个chunk之后如图所示:
在这里插入图片描述
chunk所描述的是范围区间,例如,db.users使用了userId作为分片键,那么chunk就是userId的各个值(或哈希值)的连续区间

集群在操作分片集合时,会根据分片键找到对应的chunk,并向该chunk所在的分片发起操作请求,而chunk的分布在一定程度上会影响数据的读写路径,这由以下两点决定:

chunk的切分方式,决定如何找到数据所在的chunk

chunk的分布状态,决定如何找到chunk所在的分片

3.4、分片算法,哈希分片、范围分片

默认分片方法是基于范围的分片。
  • 范围分片:

假设集合根据x字段来分片,x的完整取值范围为[minKey, maxKey]x为整数,这里的minKey、maxKey为整型的最小值和最大值),其将整个取值范围划分为多个chunk,例如:

chunk1包含x的取值在[minKey,-75)的所有文档。
chunk2包含x取值在[-75,25)之间的所有文档,依此类推。

则默认分片方法是基于范围的分片。

优点:范围分片能很好地满足范围查询的需求,比如想查询x的值在[-30,10]之间的所有文档,这时mongos直接将请求定位到chunk2所在的分片服务器,就能查询出所有符合条件的文档。

缺点:如果Shard Key有明显递增(或者递减)趋势,则新插入的文档会分布到同一个chunk,此时写压力会集中到一个节点,从而导致单点的性能瓶颈
一些常见导致递增的Key:时间值,ObjectId,自动生成的_id由时间、计数器组成,自增整数序列等。

  • 哈希分片:哈希分片会先事先根据分片键计算出一个新的哈希值(64位整数),再根据哈希值按照范围分片的策略进行chunk的切分,适用日志,物联网等高并发场景。

优点:由于哈希算法保证了随机性,所以文档可以更加离散地分布到多个chunk上,这避免了集中写问题,单点性能瓶颈问题。

缺点:在执行一些范围查询时,哈希分片并不是高效的。因为所有的范围查询都必然导致对所有chunk进行检索,如果集群有10个分片,那么mongos将需要对10个分片分发查询请求。

注意:哈希分片只能选择单个字段,而范围分片允许采用组合式的多字段作为分片键

3.5、根据文档的hash值,确定数据所在的分片位置

原理:拿到hash分片的hash值(64位整数),根据由hash值反向计算出来的整数值去锁定chunk,通过查看集合分片的状态信息获取chunk的范围,最后确认数据再哪个分片。

使用函数convertShardKeyToHashed,把hash值转换为整数值

[direct: mongos] shop>  db.product.find().limit(4)
[
  {
    _id: ObjectId('66a31a8be5ff925e894842f5'),
    productId: 'P-0-2',
    name: '羊毛衫',
    tags: [
      { tagKey: 'size', tagValue: [ 'L', 'XL', 'XXL' ] },
      { tagKey: 'color', tagValue: [ '蓝色', '杏色' ] },
      { tagKey: 'style', tagValue: '韩风' }
    ]
  },
  {
    _id: ObjectId('66a31a8be5ff925e894842f4'),
    productId: 'P-0-1',
    name: '羊毛衫',
    tags: [
      { tagKey: 'size', tagValue: [ 'L', 'XL', 'XXL' ] },
      { tagKey: 'color', tagValue: [ '蓝色', '杏色' ] },
      { tagKey: 'style', tagValue: '韩风' }
    ]
  },
  {
    _id: ObjectId('66a31a8be5ff925e894842f7'),
    productId: 'P-0-4',
    name: '羊毛衫',
    tags: [
      { tagKey: 'size', tagValue: [ 'L', 'XL', 'XXL' ] },
      { tagKey: 'color', tagValue: [ '蓝色', '杏色' ] },
      { tagKey: 'style', tagValue: '韩风' }
    ]
  },
  {
    _id: ObjectId('66a31a8be5ff925e894842f6'),
    productId: 'P-0-3',
    name: '羊毛衫',
    tags: [
      { tagKey: 'size', tagValue: [ 'L', 'XL', 'XXL' ] },
      { tagKey: 'color', tagValue: [ '蓝色', '杏色' ] },
      { tagKey: 'style', tagValue: '韩风' }
    ]
  }
]
[direct: mongos] shop> convertShardKeyToHashed( ObjectId("66a31a8be5ff925e894842f5") )
Long('1427408640070972074')
[direct: mongos] shop> convertShardKeyToHashed( ObjectId("66a31a8be5ff925e894842f4") )
Long('-9116726154908208019')
[direct: mongos] shop> convertShardKeyToHashed( ObjectId("66a31a8be5ff925e894842f7") )
Long('-5937814161811192234')
[direct: mongos] shop> convertShardKeyToHashed( ObjectId("66a31a8be5ff925e894842f6") )
Long('-2297129732306926016')
[direct: mongos] shop> 

查看数据库的chunk数据块范围,判断属于哪个分片

##数据库集合的chunk信息:
 database: {
      _id: 'shop',
      primary: 'shard2',
      partitioned: false,
      version: {
        uuid: UUID('f5d19356-e04f-4459-8c69-d8bb560fd01f'),
        timestamp: Timestamp({ t: 1721964850, i: 2 }),
        lastMod: 1
      }
    },
    collections: {
      'shop.product': {
        shardKey: { productId: 'hashed' },
        unique: false,
        balancing: true,
        chunkMetadata: [
          { shard: 'shard1', nChunks: 2 },
          { shard: 'shard2', nChunks: 2 }
        ],
        chunks: [
          { min: { productId: MinKey() }, max: { productId: Long('-4611686018427387902') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 0 }) },
          { min: { productId: Long('-4611686018427387902') }, max: { productId: Long('0') }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) },
          { min: { productId: Long('0') }, max: { productId: Long('4611686018427387902') }, 'on shard': 'shard2', 'last modified': Timestamp({ t: 1, i: 2 }) },
          { min: { productId: Long('4611686018427387902') }, max: { productId: MaxKey() }, 'on shard': 'shard2', 'last modified': Timestamp({ t: 1, i: 3 }) }
        ],
        tags: []
      }
    }

四、保持负载均衡的关键:chunk数据块的迁移

为了保证分片集群的水平扩展能力,业务数据应当尽可能地保持均匀分布。这里的均匀性包含以下两个方面:

  • 所有的数据应均匀地分布于不同的chunk上。
  • 每个分片上的chunk数量尽可能是相近的。

4.1、负载均衡器

MongoDB 负载均衡器是一个后台进程,运行于Primary Config Server(配置服务器的主节点)上,用于监控每个分片集合的每个分片上的数据量。当给定分片上的分片集合的数据量达到特定迁移阈值时,负载均衡器会尝试在分片之间自动迁移数据,并在遵从区域的前提下实现每个分片的数据量均衡。

运行时机:

  • 1、在集群中添加和删除分片,向集群添加分片会造成不平衡,因为新分片没有任何数据,可能需要一些时间才能达到平衡。从集群删除分片也会造成类似的不均衡,因为驻留在该分片的数据必须在整个集群重新分布。在此进程中,请勿关闭与已删除分片关联的服务器。

  • 2、迁移阈值,如果分片之间的数据差异(对于该集合)小于该集合配置范围大小的三倍,则该集合被认为是均衡的。如果默认范围大小为 128MB,两个分片对于给定集合的数据大小必须至少相差 384MB,才能进行迁移

##查看是否已经启用负载均衡器
sh.getBalancerState()

##检查负载均衡器是否运行
sh.isBalancerRunning()
可以使用sh.status()查看负载均衡器是否已启用。 currently-enabled字段指示负载均衡器是否已启用, currently-running字段指示负载均衡器当前是否正在运行。

安排均衡窗口,如果您处于activeWindow时间范围之外,负载均衡器则不会启动。
尤其是当数据集增长缓慢且迁移可能会影响性能时,确保负载均衡器仅在特定时间处于活动状态非常有用。

use config
确保均衡器激活状态
sh.startBalancer()

sh.getBalancerState()
修改时间活动时间
db.settings.updateOne(
   { _id: "balancer" },
   { $set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } } },
   { upsert: true }
)
##删除负载窗口
use config
db.settings.updateOne( { _id : "balancer" }, { $unset : { activeWindow : true } } )

4.2、分片键的选择,chunk数据块分裂,jumbo超大块

分片键选择标准
在选择分片键时,需要根据业务的需求及范围分片、哈希分片的不同特点进行权衡。一般来说,在设计分片键时需要考虑的因素包括:

分片键的基数(cardinality),取值基数越大越有利于扩展
以性别作为分片键 :数据最多被拆分为 2 份
以月份作为分片键 :数据最多被拆分为 12 份
分片键的取值分布应该尽可能均匀。
业务读写模式,尽可能分散写压力,而读操作尽可能来自一个或少量的分片。
分片键应该能适应大部分的业务操作。

chunk数据块的分裂
在默认情况下,chunk由配置的chunksize参数指定。如果持续地向该chunk写入数据,并导致数据量超过了chunk大小,则MongoDB会自动进行分裂,将该chunk切分为两个相同大小的chunk。如果图所示:
在这里插入图片描述

`chunk分裂是基于分片键进行的,如果分片键的基数太小,则可能因为无法分裂而会出现jumbo

jumbo超大块
chunk(超大块)的问题例如,对db.users使用gender(性别)作为分片键(这里基数为2`),由于同一种性别的用户数可能达到数千万,分裂程序并不知道如何对分片键(gender)的一个单值进行切分,因此最终导致在一个chunk上集中存储了大量的user记录(总大小超过64MB)。

jumbo chunk对水平扩展有负面作用,该情况不利于数据的均衡,业务上应尽可能避免。一些写入压力过大的情况可能会导致chunk多次失败(split),最终当chunk中的文档数大于1.3×avgObjectSize时会导致无法迁移

手动清除jumbo标记

如果 MongoDB 无法分割超过指定大小范围的数据块,则 MongoDB 会将该数据块标记为jumbo

清除数据块中jumbo标志的首选手动方法是尝试分割数据块。如果数据块可分,则 MongoDB 会在成功分割数据块后删除该标志。

步骤:

  • 找到jumbo数据块。
#运行sh.status(true)以查找标记为jumbo的数据段。
sh.status(true)

例如,sh.status(true) 的以下输出显示分片键范围为{ "x" : 2 } -->> { "x" : 4 }的数据块为jumbo 。

--- Sharding Status ---
   sharding version: {
      ...
   }
   shards:
      ...
   databases:
      ...
         test.foo
            shard key: { "x" : 1 }
         chunks:
              shard-b  2
              shard-a  2
         { "x" : { "$minKey" : 1 } } -->> { "x" : 1 } on : shard-b Timestamp(2, 0)
         { "x" : 1 } -->> { "x" : 2 } on : shard-a Timestamp(3, 1)
         { "x" : 2 } -->> { "x" : 4 } on : shard-a Timestamp(2, 2) jumbo
         { "x" : 4 } -->> { "x" : { "$maxKey" : 1 } } on : shard-b Timestamp(3, 0)
  {
    database: { _id: 'config', primary: 'config', partitioned: true },
    collections: {
      'config.system.sessions': {
        shardKey: { _id: 1 },
        unique: false,
        balancing: true,
        chunkMetadata: [ { shard: 'shard1', nChunks: 1024 } ],
        chunks: [
          { min: { _id: MinKey() }, max: { _id: { id: UUID('00400000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 1 }) },
          { min: { _id: { id: UUID('00400000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('00800000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 2 }) },
          { min: { _id: { id: UUID('00800000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('00c00000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 3 }) },
          { min: { _id: { id: UUID('00c00000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('01000000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 4 }) },
          { min: { _id: { id: UUID('01000000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('01400000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 5 }) },
          { min: { _id: { id: UUID('01400000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('01800000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 6 }) },
          { min: { _id: { id: UUID('01800000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('01c00000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 7 }) },
          { min: { _id: { id: UUID('01c00000-0000-0000-0000-000000000000') } }, max: { _id: { id: UUID('02000000-0000-0000-0000-000000000000') } }, 'on shard': 'shard1', 'last modified': Timestamp({ t: 1, i: 8 }) },
  • 分割jumbo数据块。
    使用sh.splitAt()或sh.splitFind()分割jumbo数据段。
sh.splitAt( "test.foo", { x: 3 })

成功分割数据块后,MongoDB 会删除jumbo标志

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值