MongoDB 分片集群

一、分片概念

分片(sharding )是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署。

换句话说:分片(sharding )是指将数据拆分,将其分散存在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以储存更多的数据,处理更多的负载。

具有大型数据集或高吞吐量应用程序的数据库系统可能会挑战单个服务器的容量。例如,高查询率会耗尽服务器的 CPU 容量。工作集大小大于系统的 RAM 会强调磁盘驱动器的I / O容量。

有两种解决系统增长的方法:垂直扩展和水平扩展。

垂直扩展意味着增加单个服务器的容量 ,例如使用更强大的 CPU ,添加更多 RAM或增加存储空间量。可用技术的局限性可能会限制单个机器对于给定工作负载而言足够强大。此外,基于云的提供商基于可用的硬件配置具有硬性上限。结果,垂直缩放有实际的最大值。

水平扩展意味着划分系统数据集并加载多个服务器,添加其他服务器以根据需要增加容量。虽然单个机器的总体速度或容量可能不高,但每台机器处理整个工作负载的子集,可能提供比单个高速大容量服务器更高的效率。扩展部署容量只需要根据需要添加额外的服务器,这可能比单个机器的高端硬件的总体成本更低。权衡是基础架构和部署维护的复杂性增加。

MongoDB支持通过分片进行水平扩展。

二、分片集群包含的组件

MongoDB分片群集包含以下组件:

**a、**分片(存储):每个分片包含分片数据的子集。 每个分片都可以部署为副本集。

b、mongos (路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口。

c、config servers ("调度"的配置):配置服务器存储群集的元数据和配置设置。 从MongoDB 3.4 开始,必须将配置服务器部署为副本集(CSRS)。

下图描述了分片集群中组件的交互,其中 MongoDB在集合级别对数据进行分片,将集合数据分布在集群中的分片上。

三、分片集群的架构目标

包括两个分片节点副本集(3+3)+一个配置节点副本集(3)+两个路由节点,一共 11 个节点服务。如下图所示:

四、分片节点副本集创建

4.1 第一套副本集创建

创建存放数据和日志的目录,命令如下:

bash 复制代码
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27018/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27018/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27118/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27118/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27218/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27218/data/db

新建 27018的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf

27018的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27018
replication:
  # 副本集的名称
  replSetName: myshardrs01
sharding:
  # 分片角色
  clusterRole: shardsvr

需要注意的是:clusterRole 的可选项只有 configsvr (配置服务) 和 shardsvr(分片服务),在此处我们搭建的副本集就属于分片服务。

新建 27118的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf

27118的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27118
replication:
  # 副本集的名称
  replSetName: myshardrs01
sharding:
  # 分片角色
  clusterRole: shardsvr

新建 27218的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf

27218的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27218
replication:
  # 副本集的名称
  replSetName: myshardrs01
sharding:
  # 分片角色
  clusterRole: shardsvr

依次启动三个 mongodb服务

bash 复制代码
# 启动主节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf


# 启动副本节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf

# 启动仲裁节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
ruby 复制代码
# 查看服务是否启动成功
[root@node1 db]# ps -ef | grep mongo
root      79379      1  0 23:32 ?        00:00:12 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
root      90640      1  0 20:14 ?        00:01:12 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
root      90673      1  0 20:14 ?        00:01:13 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
root      92359  62119  0 23:53 pts/1    00:00:00 grep --color=auto mongo

初始化副本集和创建主节点,使用客户端命令连接任意一个节点,但这里尽量要连接主节点,如下:

ruby 复制代码
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27018
bash 复制代码
# 初始化副本集命令
> rs.initiate()
{
	"info2" : "no configuration specified. Using a default configuration for the set",
	"me" : "192.168.229.154:27018",
	"ok" : 1
}
myshardrs01:SECONDARY> 

# 添加副本节点
myshardrs01:PRIMARY> rs.add("192.168.229.154:27118")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697439387, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697439387, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 添加仲裁节点
myshardrs01:PRIMARY> rs.addArb("192.168.229.154:27218")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697439405, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697439405, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 查看副本集的配置情况
myshardrs01:PRIMARY> rs.conf()
{
	"_id" : "myshardrs01",
	"version" : 3,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.229.154:27018",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "192.168.229.154:27118",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "192.168.229.154:27218",
			"arbiterOnly" : true,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 0,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : -1,
		"catchUpTakeoverDelayMillis" : 30000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("652cde750805d80f8574fda4")
	}
}
myshardrs01:PRIMARY> 

4.2 第二套副本集创建

创建存放数据和日志的目录,命令如下:

bash 复制代码
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27318/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27318/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27418/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27418/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27518/log
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27518/data/db

新建 27318的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf

27318的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27318
replication:
  # 副本集的名称
  replSetName: myshardrs02
sharding:
  # 分片角色
  clusterRole: shardsvr

新建 27418的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf

27418的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27418
replication:
  # 副本集的名称
  replSetName: myshardrs02
sharding:
  # 分片角色
  clusterRole: shardsvr

新建 27518的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf

27518的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # bindIp
  # 绑定的端口
  port: 27518
replication:
  # 副本集的名称
  replSetName: myshardrs02
sharding:
  # 分片角色
  clusterRole: shardsvr

依次启动三个 mongodb服务

bash 复制代码
# 启动主节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf


# 启动副本节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf

# 启动仲裁节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
ruby 复制代码
# 查看服务是否启动成功
[root@node1 db]# ps -ef | grep mongo
root      79379      1  0 Oct15 ?        00:00:22 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
root      90640      1  0 Oct15 ?        00:01:20 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
root      90673      1  0 Oct15 ?        00:01:23 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
root     102785      1  3 00:11 ?        00:00:00 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
root     102984      1  4 00:11 ?        00:00:00 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
root     103018      1  6 00:11 ?        00:00:00 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
root     103189  62119  0 00:11 pts/1    00:00:00 grep --color=auto mongo

初始化副本集和创建主节点,使用客户端命令连接任意一个节点,但这里尽量要连接主节点,如下:

ruby 复制代码
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27318
bash 复制代码
# 初始化副本集
> rs.initiate()
{
	"info2" : "no configuration specified. Using a default configuration for the set",
	"me" : "192.168.229.154:27318",
	"ok" : 1
}

# 添加副本节点
myshardrs02:SECONDARY> rs.add("192.168.229.154:27418")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697440445, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697440445, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 添加仲裁节点
myshardrs02:PRIMARY> rs.addArb("192.168.229.154:27518")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697440457, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697440457, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 查看副本集的配置情况
myshardrs02:PRIMARY> rs.conf()
{
	"_id" : "myshardrs02",
	"version" : 3,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.229.154:27318",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "192.168.229.154:27418",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "192.168.229.154:27518",
			"arbiterOnly" : true,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 0,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : -1,
		"catchUpTakeoverDelayMillis" : 30000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("652ce2b023e3bc8d21b4fd3b")
	}
}
myshardrs02:PRIMARY> 

五、配置节点副本集创建

创建存放数据和日志的目录,命令如下:

bash 复制代码
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27019/log
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27019/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27119/log
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27119/data/db

mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27219/log
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27219/data/db

新建 27019的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf

27019的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.pid"
net:
  # 服务实例绑定所有IP
  # bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # 绑定的端口
  port: 27019
replication:
  replSetName: myconfigrs
sharding:
  clusterRole: configsvr

新建 27119的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf

27119的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.pid"
net:
  # 服务实例绑定所有IP
  # bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # 绑定的端口
  port: 27119
replication:
  replSetName: myconfigrs
sharding:
  clusterRole: configsvr

新建 27219的配置文件,命令如下:

bash 复制代码
vim /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf

27219的配置文件内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
storage:
  # mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
  dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/data/db"
  journal:
    # 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
    enabled: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.pid"
net:
  # 服务实例绑定所有IP
  # bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  # 绑定的端口
  port: 27219
replication:
  replSetName: myconfigrs
sharding:
  clusterRole: configsvr

启动配置副本集:一主两副本,依次启动三个 mongod服务

bash 复制代码
# 主
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf

# 从
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf

# 从
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
bash 复制代码
# 查看服务是否启动成功
[root@node1 sharded_cluster]# ps -ef | grep mongo
root      79379      1  0 Oct15 ?        00:00:35 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
root      90640      1  0 Oct15 ?        00:01:28 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
root      90673      1  0 Oct15 ?        00:01:34 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
root     102785      1  0 00:11 ?        00:00:11 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
root     102984      1  0 00:11 ?        00:00:11 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
root     103018      1  0 00:11 ?        00:00:08 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
root     114303      1  3 00:30 ?        00:00:01 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
root     114342      1  2 00:30 ?        00:00:01 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
root     114531      1 36 00:30 ?        00:00:14 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
root     114765  62119  0 00:31 pts/1    00:00:00 grep --color=auto mongo

初始化副本集和创建主节点,使用客户端命令连接任意一个节点,但这里尽量要连接主节点:

bash 复制代码
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27019
bash 复制代码
# 初始化副本集命令
> rs.initiate()
{
	"info2" : "no configuration specified. Using a default configuration for the set",
	"me" : "192.168.229.154:27019",
	"ok" : 1,
	"$gleStats" : {
		"lastOpTime" : Timestamp(1697441587, 1),
		"electionId" : ObjectId("000000000000000000000000")
	},
	"lastCommittedOpTime" : Timestamp(0, 0)
}
myconfigrs:SECONDARY> 

# 添加第一个副本节点
myconfigrs:PRIMARY> rs.add("192.168.229.154:27119")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697441633, 1),
	"$gleStats" : {
		"lastOpTime" : {
			"ts" : Timestamp(1697441633, 1),
			"t" : NumberLong(1)
		},
		"electionId" : ObjectId("7fffffff0000000000000001")
	},
	"lastCommittedOpTime" : Timestamp(1697441628, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697441633, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 添加第二个副本节点
myconfigrs:PRIMARY> rs.add("192.168.229.154:27219")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697441639, 1),
	"$gleStats" : {
		"lastOpTime" : {
			"ts" : Timestamp(1697441639, 1),
			"t" : NumberLong(1)
		},
		"electionId" : ObjectId("7fffffff0000000000000001")
	},
	"lastCommittedOpTime" : Timestamp(1697441633, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697441639, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

# 查看副本集的配置情况
myconfigrs:PRIMARY> rs.conf()
{
	"_id" : "myconfigrs",
	"version" : 3,
	"configsvr" : true,
	"protocolVersion" : NumberLong(1),
	"writeConcernMajorityJournalDefault" : true,
	"members" : [
		{
			"_id" : 0,
			"host" : "192.168.229.154:27019",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 1,
			"host" : "192.168.229.154:27119",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		},
		{
			"_id" : 2,
			"host" : "192.168.229.154:27219",
			"arbiterOnly" : false,
			"buildIndexes" : true,
			"hidden" : false,
			"priority" : 1,
			"tags" : {
				
			},
			"slaveDelay" : NumberLong(0),
			"votes" : 1
		}
	],
	"settings" : {
		"chainingAllowed" : true,
		"heartbeatIntervalMillis" : 2000,
		"heartbeatTimeoutSecs" : 10,
		"electionTimeoutMillis" : 10000,
		"catchUpTimeoutMillis" : -1,
		"catchUpTakeoverDelayMillis" : 30000,
		"getLastErrorModes" : {
			
		},
		"getLastErrorDefaults" : {
			"w" : 1,
			"wtimeout" : 0
		},
		"replicaSetId" : ObjectId("652ce7334991027264953cb0")
	}
}
myconfigrs:PRIMARY> 

六、路由节点的创建和操作

6.1 第一个路由节点的创建和连接

准备存放数据和日志的目录,如下:

bash 复制代码
mkdir -p /usr/local/mongodb/sharded_cluster/mymongos_27017/log

新建配置文件

bash 复制代码
vi /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf

内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: /usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  #bindIp
  # 绑定的端口
  port: 27017
sharding:
  # 指定配置节点副本集
  configDB:
    myconfigrs/192.168.229.154:27019,192.168.229.154:27119,192.168.229.154:27219

启动 mongos

bash 复制代码
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf

客户端登录 mongos

bash 复制代码
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27017
bash 复制代码
# 测试是否可以写入数据
mongos> use testdata
switched to db testdata

# 此时,写不进去数据,如果写数据会报错
mongos> db.aa.insert({aa:"aa"})
WriteCommandError({
	"ok" : 0,
	"errmsg" : "unable to initialize targeter for write op for collection testdata.aa :: caused by :: Database testdata not found :: caused by :: No shards found",
	"code" : 70,
	"codeName" : "ShardNotFound",
	"operationTime" : Timestamp(1697446461, 3),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697446461, 3),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
})
mongos>

通过路由节点操作,现在只是连接了配置节点,还没有连接分片数据节点,因此无法写入业务数据。

6.2 在路由节点进行分片配置

6.2.1 添加分片

添加分片语法如下:

bash 复制代码
sh.addShard("IP:Port")
bash 复制代码
# 将第一套分片副本集添加进来
mongos> sh.addShard("myshardrs01/192.168.229.154:27018,192.168.229.154:27118,192.168.229.154:27218")
{
	"shardAdded" : "myshardrs01",
	"ok" : 1,
	"operationTime" : Timestamp(1697447335, 5),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697447335, 5),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
bash 复制代码
# 查看分片状态情况
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
  active mongoses:
        "4.0.28" : 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:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }

mongos> 
bash 复制代码
# 续将第二套分片副本集添加进来
mongos> sh.addShard("myshardrs02/192.168.229.154:27318,192.168.229.154:27418,192.168.229.154:27518")
{
	"shardAdded" : "myshardrs02",
	"ok" : 1,
	"operationTime" : Timestamp(1697447436, 4),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697447436, 4),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
bash 复制代码
# 查看分片状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  # 并未显示仲裁者的 ip
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
        {  "_id" : "myshardrs02",  "host" : "myshardrs02/192.168.229.154:27318,192.168.229.154:27418",  "state" : 1 }
  active mongoses:
        "4.0.28" : 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: 
                13 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	1011
                                myshardrs02	13
                        too many chunks to print, use verbose if you want to force print

mongos>

如果添加分片失败,需要先手动移除分片,检查添加分片的信息的正确性后,再次添加分片。移除分片参考(了解):

bash 复制代码
use admin
db.runCommand( { removeShard: "myshardrs02" } )

注意:如果只剩下最后一个 shard,是无法删除的。移除时会自动转移分片数据,需要一个时间过程。完成后,再次执行删除分片命令才能真正删除。

6.2.2 开启分片功能

语法如下:

bash 复制代码
sh.enableSharding("库名")
bash 复制代码
# 在 mongos 上的 articledb 数据库配置 sharding
mongos> sh.enableSharding("articledb")
{
	"ok" : 1,
	"operationTime" : Timestamp(1697447788, 11),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697447788, 11),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
bash 复制代码
# 查看分片状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
        {  "_id" : "myshardrs02",  "host" : "myshardrs02/192.168.229.154:27318,192.168.229.154:27418",  "state" : 1 }
  active mongoses:
        "4.0.28" : 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: 
                336 : Success
  databases:
        {  "_id" : "articledb",  "primary" : "myshardrs02",  "partitioned" : true,  "version" : {  "uuid" : UUID("14943571-dd3e-4b0b-84c4-7d3a05d5e0a0"),  "lastMod" : 1 } }
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	688
                                myshardrs02	336
                        too many chunks to print, use verbose if you want to force print

mongos>

6.2.3 集合分片

对集合分片,你必须使用 **sh.shardCollection()**方法指定集合和分片键。语法如下:

bash 复制代码
sh.shardCollection(namespace, key, unique)

|---------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Parameter | Type | Description |
| namespace | string | 要(分片)共享的目标集合的命名空间,格式: 数据库名称.集合名称 |
| key | document | 用作分片键的索引规范文档。shard 键决定 MongoDB 如何在 shard 之间分发文档。除非集合为空,否则索引必须在 shardcollection 命令之前存在。如果集合为空,则 MongoDB 在对集合进行分片之前创建索引,前提是支持分片键的索引不存在。简单的说:由包含字段和该字段的索引遍历方向的文档组成。 |
| unique | boolean | 当值为 true 情况下,片键字段上会限制为确保是唯一索引。哈希策略片键不支持唯一索引。默认是 false。 |

对集合进行分片时,你需要选择一个 片键(Shard Key ) , shard key 是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。

为了按照片键划分数据块,MongoDB 使用基于哈希 的分片方式(随机平均分配)或者基于范围 的分片方式(数值大小分配) 。用什么字段当片键都可以,如:nickname作为片键,但一定是必填字段。

分片规则一:哈希策略

对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。在使用基于哈希分片的系统中,拥有 "相近" 片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。

bash 复制代码
# 使用 nickname 作为片键,根据其值的哈希值进行数据分片
mongos> sh.shardCollection("articledb.comment",{"nickname":"hashed"})
{
	"collectionsharded" : "articledb.comment",
	"collectionUUID" : UUID("99e2298a-c8fe-49c1-b002-aed320ea6ac7"),
	"ok" : 1,
	"operationTime" : Timestamp(1697506381, 28),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697506381, 28),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
bash 复制代码
# 查看分片状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
        {  "_id" : "myshardrs02",  "host" : "myshardrs02/192.168.229.154:27318,192.168.229.154:27418",  "state" : 1 }
  active mongoses:
        "4.0.28" : 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: 
                512 : Success
  databases:
        {  "_id" : "articledb",  "primary" : "myshardrs02",  "partitioned" : true,  "version" : {  "uuid" : UUID("14943571-dd3e-4b0b-84c4-7d3a05d5e0a0"),  "lastMod" : 1 } }
                articledb.comment
                        shard key: { "nickname" : "hashed" }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	2
                                myshardrs02	2
                        { "nickname" : { "$minKey" : 1 } } -->> { "nickname" : NumberLong("-4611686018427387902") } on : myshardrs01 Timestamp(1, 0) 
                        { "nickname" : NumberLong("-4611686018427387902") } -->> { "nickname" : NumberLong(0) } on : myshardrs01 Timestamp(1, 1) 
                        { "nickname" : NumberLong(0) } -->> { "nickname" : NumberLong("4611686018427387902") } on : myshardrs02 Timestamp(1, 2) 
                        { "nickname" : NumberLong("4611686018427387902") } -->> { "nickname" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 3) 
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	512
                                myshardrs02	512
                        too many chunks to print, use verbose if you want to force print

分片规则二:范围策略

对于基于范围的分片 ,MongoDB 按照片键的范围把数据分成不同部分。假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点。MongoDB把这条直线划分为更短的不重叠的片段,并称之为数据块 ,每个数据块包含了片键在一定范围内的数据。

在使用片键做范围划分的系统中,拥有"相近"片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。

bash 复制代码
# 如使用作者年龄字段作为片键,按照点赞数的值进行分片
mongos> sh.shardCollection("articledb.author",{"age":1})
{
	"collectionsharded" : "articledb.author",
	"collectionUUID" : UUID("a8a72040-581c-4030-b152-99975eaafaac"),
	"ok" : 1,
	"operationTime" : Timestamp(1697506689, 13),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697506689, 13),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

注意:

**a、**一个集合只能指定一个片键,否则报错。

**b、**一旦对一个集合分片,分片键和分片值就不可改变。 如:不能给集合选择不同的分片键、不能更新分片键的值。

c、 根据 age索引进行分配数据。

bash 复制代码
# 查看分片状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
        {  "_id" : "myshardrs02",  "host" : "myshardrs02/192.168.229.154:27318,192.168.229.154:27418",  "state" : 1 }
  active mongoses:
        "4.0.28" : 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: 
                512 : Success
  databases:
        {  "_id" : "articledb",  "primary" : "myshardrs02",  "partitioned" : true,  "version" : {  "uuid" : UUID("14943571-dd3e-4b0b-84c4-7d3a05d5e0a0"),  "lastMod" : 1 } }
                articledb.author
                        shard key: { "age" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs02	1
                        { "age" : { "$minKey" : 1 } } -->> { "age" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 0) 

哈希策略和范围策略性能对比:

基于范围的分片方式提供了更高效的范围查询,给定一个片键的范围,分发路由可以很简单地确定哪个数据块存储了请求需要的数据,并将请求转发到相应的分片中。

不过,基于范围的分片会导致数据在不同分片上的不均衡。有时候带来的消极作用会大于查询性能的积极作用。比如,如果片键所在的字段是线性增长的,一定时间内的所有请求都会落到某个固定的数据块中,最终导致分布在同一个分片中。在这种情况下,一小部分分片承载了集群大部分的数据,系统并不能很好地进行扩展。

与此相比,基于哈希的分片方式以范围查询性能的损失为代价,保证了集群中数据的均衡。哈希值的随机性使数据随机分布在每个数据块中,因此也随机分布在不同分片中。但是也正由于随机性,一个范围查询很难确定应该请求哪些分片,通常为了返回需要的结果,需要请求所有分片。

如无特殊情况,一般推荐使用 Hash Sharding

而使用 _id 作为片键是一个不错的选择,因为它是必有的,你可以使用数据文档 _id的哈希作为片键。

这个方案能够使得读和写都能够平均分布,并且它能够保证每个文档都有不同的片键,所以数据块能够很精细。

似乎还是不够完美,因为这样的话对多个文档的查询必将命中所有的分片。虽说如此,这也是一种比较好的方案了。

理想化的shard key 可以让 documents均匀地在集群中分布:

6.3 分片后插入数据测试

6.3.1 测试哈希规则

登录 mongs 后,向 comment 循环插入1000条数据做测试

bash 复制代码
mongos> use articledb
switched to db articledb
mongos> db
articledb
# js 的语法,因为 mongo 的 shell 是一个 JavaScript 的 shell
# 从路由上插入的数据,必须包含片键,否则无法插入
mongos> for(var i=1;i<=1000;i++){db.comment.insert({_id:i+"",nickname:"BoBo"+i})}
WriteResult({ "nInserted" : 1 })
mongos> db.comment.count()
1000

分别登陆两个片的主节点,统计文档数量

bash 复制代码
/usr/local/mongodb/bin/mongo --port 27018
bash 复制代码
# 第一个分片副本集
myshardrs01:PRIMARY> use articledb
switched to db articledb
myshardrs01:PRIMARY> db.comment.count()
507

登录第二个分片副本集统计

bash 复制代码
/usr/local/mongodb/bin/mongo --port 27318
bash 复制代码
# 第二个副本集
myshardrs02:PRIMARY> use articledb
switched to db articledb
myshardrs02:PRIMARY> db.comment.count()
493

可以看到,1000 条数据近似均匀的分布到了2shard上。是根据片键的哈希值分配的。

这种分配方式非常易于水平扩展:一旦数据存储需要更大空间,可以直接再增加分片即可,同时提升了性能。

使用db.comment.stats() 查看单个集合的完整情况,mongos执行该命令可以查看该集合的数据分片的情况。

使用**sh.status()**查看本库内所有集合的分片信息。

6.3.2 测试范围规则

登录 mongs 后,向 author 循环插入 20000条数据做测试

bash 复制代码
mongos> use articledb
switched to db articledb
mongos> for(var i=1;i<=20000;i++){db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
WriteResult({ "nInserted" : 1 })

分别登陆两个片的主节点,统计文档数量

bash 复制代码
/usr/local/mongodb/bin/mongo --port 27018

/usr/local/mongodb/bin/mongo --port 27318
bash 复制代码
# 第一个分片副本集
myshardrs01:PRIMARY> use articledb
switched to db articledb
myshardrs01:PRIMARY> db.author.count()
0
bash 复制代码
# 第二个分片副本集
myshardrs02:PRIMARY> use articledb
switched to db articledb
myshardrs02:PRIMARY> db.author.count()
20000

我们发现并没有进行分片操作,是因为数据块(chunk )没有填满,默认的数据块尺寸(chunksize )是64M ,填满后才会考虑向其他片的数据块填充数据,因此,为了测试,可以将其改小,这里改为 1M,操作如下:

注意:要先改小,再设置分片。为了测试,可以先删除集合,重新建立集合的分片策略,再插入数据测试即可。

bash 复制代码
use config
db.settings.save( { _id:"chunksize", value: 1 } )

# 测试完毕后记得改回来
db.settings.save( { _id:"chunksize", value: 64 } )
bash 复制代码
mongos> use articledb
switched to db articledb
# 删除当前的集合
mongos> db.author.drop()
# 重新设置分片
mongos> sh.shardCollection("articledb.author",{"age":1})
{
	"collectionsharded" : "articledb.author",
	"collectionUUID" : UUID("91b6da9f-e87f-4041-8ec9-b7492141de4a"),
	"ok" : 1,
	"operationTime" : Timestamp(1697510782, 14),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1697510782, 14),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
# 插入 20w 条数据,要不不容易满
mongos> for(var i=1;i<=200000;i++){db.author.save({"name":"BoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBoBo"+i,"age":NumberInt(i%120)})}
WriteResult({ "nInserted" : 1 })
bash 复制代码
# 第一个副本集数量统计
myshardrs01:PRIMARY> db.author.count()
110038

# 第二个副本集数量统计
myshardrs02:PRIMARY> db.author.count()
136524

6.4 再添加一个路由节点

准备存放数据和日志的目录,如下:

bash 复制代码
mkdir -p /usr/local/mongodb/sharded_cluster/mymongos_27117/log

新建配置文件

bash 复制代码
vi /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf

内容如下:

bash 复制代码
systemLog:
  # MongoDB发送所有日志输出的目标指定为文件
  destination: file
  # mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
  path: "/usr/local/mongodb/sharded_cluster/mymongos_27117/log/mongod.log"
  # 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
  logAppend: true
processManagement:
  # 启用在后台运行mongos或mongod进程的守护进程模式。
  fork: true
  # 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
  pidFilePath: /usr/local/mongodb/sharded_cluster/mymongos_27117/log/mongod.pid"
net:
  # 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
  #bindIpAll: true
  # 服务实例绑定的IP
  bindIp: localhost,192.168.229.154
  #bindIp
  # 绑定的端口
  port: 27117
sharding:
  # 指定配置节点副本集
  configDB:
    myconfigrs/192.168.229.154:27019,192.168.229.154:27119,192.168.229.154:27219

启动 mongos,命令如下:

bash 复制代码
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf

使用 mongo 客户端登录 27117,发现,第二个路由无需配置,因为分片配置都保存到了配置服务器中了。

bash 复制代码
/usr/local/mongodb/bin/mongo --host 192.168.229.154 --port 27117
bash 复制代码
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
  	"_id" : 1,
  	"minCompatibleVersion" : 5,
  	"currentVersion" : 6,
  	"clusterId" : ObjectId("652ce7344991027264953cbe")
  }
  shards:
        {  "_id" : "myshardrs01",  "host" : "myshardrs01/192.168.229.154:27018,192.168.229.154:27118",  "state" : 1 }
        {  "_id" : "myshardrs02",  "host" : "myshardrs02/192.168.229.154:27318,192.168.229.154:27418",  "state" : 1 }
  active mongoses:
        "4.0.28" : 2
  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: 
                516 : Success
  databases:
        {  "_id" : "articledb",  "primary" : "myshardrs02",  "partitioned" : true,  "version" : {  "uuid" : UUID("14943571-dd3e-4b0b-84c4-7d3a05d5e0a0"),  "lastMod" : 1 } }
                articledb.author
                        shard key: { "age" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	8
                                myshardrs02	9
                        { "age" : { "$minKey" : 1 } } -->> { "age" : 0 } on : myshardrs01 Timestamp(2, 0) 
                        { "age" : 0 } -->> { "age" : 8 } on : myshardrs01 Timestamp(5, 2) 
                        { "age" : 8 } -->> { "age" : 17 } on : myshardrs01 Timestamp(5, 3) 
                        { "age" : 17 } -->> { "age" : 26 } on : myshardrs01 Timestamp(5, 4) 
                        { "age" : 26 } -->> { "age" : 34 } on : myshardrs01 Timestamp(4, 8) 
                        { "age" : 34 } -->> { "age" : 43 } on : myshardrs01 Timestamp(4, 9) 
                        { "age" : 43 } -->> { "age" : 52 } on : myshardrs01 Timestamp(4, 10) 
                        { "age" : 52 } -->> { "age" : 60 } on : myshardrs01 Timestamp(5, 0) 
                        { "age" : 60 } -->> { "age" : 70 } on : myshardrs02 Timestamp(5, 1) 
                        { "age" : 70 } -->> { "age" : 79 } on : myshardrs02 Timestamp(4, 7) 
                        { "age" : 79 } -->> { "age" : 83 } on : myshardrs02 Timestamp(5, 5) 
                        { "age" : 83 } -->> { "age" : 87 } on : myshardrs02 Timestamp(5, 6) 
                        { "age" : 87 } -->> { "age" : 92 } on : myshardrs02 Timestamp(5, 7) 
                        { "age" : 92 } -->> { "age" : 100 } on : myshardrs02 Timestamp(4, 2) 
                        { "age" : 100 } -->> { "age" : 109 } on : myshardrs02 Timestamp(4, 3) 
                        { "age" : 109 } -->> { "age" : 119 } on : myshardrs02 Timestamp(4, 4) 
                        { "age" : 119 } -->> { "age" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(3, 4) 
                articledb.comment
                        shard key: { "nickname" : "hashed" }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	2
                                myshardrs02	2
                        { "nickname" : { "$minKey" : 1 } } -->> { "nickname" : NumberLong("-4611686018427387902") } on : myshardrs01 Timestamp(1, 0) 
                        { "nickname" : NumberLong("-4611686018427387902") } -->> { "nickname" : NumberLong(0) } on : myshardrs01 Timestamp(1, 1) 
                        { "nickname" : NumberLong(0) } -->> { "nickname" : NumberLong("4611686018427387902") } on : myshardrs02 Timestamp(1, 2) 
                        { "nickname" : NumberLong("4611686018427387902") } -->> { "nickname" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 3) 
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                myshardrs01	512
                                myshardrs02	512
                        too many chunks to print, use verbose if you want to force print

七、SpringDataMongDB 连接分片集群

Java 客户端常用的是 SpringDataMongoDB ,其连接的是 mongs 路由,配置和单机 mongod的配置是一样的。

多个路由的时候的 SpringDataMongoDB的客户端配置参考如下:

bash 复制代码
spring:
  # 数据源配置
  data:
    mongodb:
      # 主机地址
      # host: 192.168.229.154
      # 数据库
      # database: articledb
      # 默认端口是27017
      # port: 27017
      # 也可以使用uri连接
      uri: mongodb://192.168.229.154:27017,192.168.229.154:27117/articledb

通过日志发现,写入数据的时候,会选择一个路由写入。

相关推荐
希望永不加班14 小时前
SpringBoot 整合 MongoDB
java·spring boot·后端·mongodb·spring
sR916Mecz14 小时前
MongoDB 详解、应用场景及案例分析(AI)
数据库·mongodb
吴声子夜歌19 小时前
Node.js——操作MongoDB
数据库·mongodb·node.js
爬山算法1 天前
MongoDB(80)如何在MongoDB中使用多文档事务?
数据库·python·mongodb
爬山算法2 天前
MongoDB(79)事务的特性是什么?
数据库·python·mongodb
知识分享小能手2 天前
MongoDB入门学习教程,从入门到精通,MongoDB 副本集管理完全指南(13)
数据库·学习·mongodb
爬山算法3 天前
MongoDB(78)什么是MongoDB的事务?
数据库·mongodb
知识分享小能手3 天前
MongoDB入门学习教程,从入门到精通,MongoDB从应用程序连接副本集(12)
数据库·学习·mongodb
你才是臭弟弟3 天前
MongoDB Community Server (社区版)安装流程
数据库·mongodb
你才是臭弟弟3 天前
MongoDB介绍
数据库·mongodb