MongoDB windows环境下搭建高可用分片集群示例

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

本文参考至:https://zhuanlan.zhihu.com/p/84406822 感谢知乎作者的无私奉献。

视频讲解:https://www.bilibili.com/video/av52570271/

分片理论:https://www.cnblogs.com/ddbear/p/7746076.html

mongodb相关指令:https://www.cnblogs.com/chenmh/p/8434419.html

本篇博客旨在提供更详细的搭建说明;

1 Mongodb集群介绍

在官方文档的介绍中,MongoDB集群有三种形式:Replica Set(副本集),Sharding(分片集群),Master-Slaver(主从)。那么该如何选择某种集群应用

呢?其实可以从官方的文档介绍中可以得出结论,副本集和主从的模式仅是读写分离与容灾的体现,对于真正到达海量数据时,我们需要的是能将数据按照一定规

则分配至不同服务器进行存储和查询等,这就是分片集群要做的事情,聪明的你肯定已经猜到了,这种模式也囊括了副本集和主从,既然要做集群,那么我们就搭

最顶级的分片集群,本文主要介绍分片集群的搭建,以及分片集群模式下的安全认证处理配置。

2 分片集群的组件介绍

分片集群中主要有三个组件:

  • Routers(前端路由器),mongos充当查询路由器,提供客户端应用程序和分片集群之间的接口。客户端通过驱动选择连接某一个mongs作为集群入口,执行
    数据查询和写入。没错,它也是多个,当然官方要求至少一个,但为了防止单点故障,我们选择3台。
  • Config Servers (配置服务器),config servers配置服务器存储群集的元数据和配置设置。从MongoDB 3.4开始,必须将配置服务器部署为副本集。它主要记录了
    shard的配置信息,元信息,如数据存储目录,日志目录,端口号,chunk信息,是否开启了journal等信息,为了保证它的高可用,官方要求必须是副本集,如果
    配置器一旦整体无法使用,则集群无法使用,所以,它也是3台。
  • Shard (分片服务器),每个分片包含分片数据的子集。每个分片都可以部署为副本集。实际储存数据的载体服务,一个shard角色应该是一个ReaplicaSet组,本
    此我们采用3个Shard,每个shard一个副本集,副本集中会有主节点,从节点,仲裁节点。

组件交互图:

3 集群搭建 环境准备

mongo1(127.0.0.1) mongo2(127.0.0.1) mongo3(127.0.0.1)

config1(端口:27018) config2(端口:27028) config3(端口:27038)

mongos1(端口:27019) mongos2(端口:27029) mongos3(端口:27039)

Shard1(端口:27001) Shard1(端口:27021) Shard1(端口:27031)

Shard2(端口:27002) Shard2(端口:27022) Shard2(端口:27032)

Shard3(端口:27003) Shard3(端口:27023) Shard3(端口:27033)

实际当中,个人觉得mong1,mongo2 ,mongo3应当是在三台不同的服务器,mongos应当与config部署在不同的服务器,各shard组副本集应当部署在不同的服务器,

config可以与shard片部署在同一服务器,也就是说要达到性能最优,至少应当有6台服务器,mongos用3台,config和3组Shard用3台。本文中就以本地Windows7环境为例,

用不同的端口作为伪服务器演示搭建配置过程。MongoBD zip安装包下载地址:

Downloads for win32​dl.mongodb.org

注意,集群下不要使用msi安装。本文采用 mongodb-win32-x86_64-2012plus-v4.2-latest.zip

解压之后重命名为mongo,内部目录如下:

在此目录下创建伪服务器目录文件夹:

mongo1(服务器1),mongo2(服务器2),mongo3(服务器3)。如图:

然后在mongo1下分别创建文件夹data(用于存储数据),log(日志文件存放),conf(配置文件存放):

在data下再创建3个文件夹:

在conf下创建三个配置文件(config.conf、mongos.conf、shard1.conf、shard2.conf、shard3.conf):

在log下创建三个日志文件,(config.log、mongos.log、shard1.log、shard2.log、shard3.log),忽略图片中的mongos.diagnostic.data文件夹,这是服务运行时产生的。

好,至此,mong1中的环境准备工作已经结束,将mong1下的所有文件夹拷贝到mongo2和mongo3下。

集群配置编辑:

首先编辑mong1的config的配置文件:config.conf

net:
  port: 27018  #config1的端口,mongo2下的为27028,mongo3下的为27038
  bindIp: 0.0.0.0  #允许连接地址,这里统一设置为允许任何ip连接
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo1\log\config.log  #config的日志存储地址,mongo2,mongo3下路径调整即可
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo1\data\config   #config的数据存储地址,mongo2、mongo3下做相应的调整
  journal:
    enabled: true #数据故障恢复和持久化,肯定是开启
#processManagement:
#  fork: true    #linux下打开此设置,Windows环境下后台启动需要注册服务,
#  pidFilePath: /mongo/config/run/mongod.pid
#副本集名称设置
replication:
  replSetName: configs
#分片集群角色,配置服务器的固定值
sharding:
  clusterRole: configsvr
#这里是集群安全认证配置,首次配置启动集群不打开此配置,先留着,后面再说
#security: 
  #keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file
  #authorization: enabled
View Code

然后编辑shard1.conf:

net:
  port: 27001   #mongo1下其他两个分片shard2为27002,shard3为27003,mongo2、mongo3下对应上面的服务编排表设置端口
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo1\log\shard1.log #mongo1下其他两个分片shard2为shard2.log,shard3为shard3.log,mongo2、mongo3下对应做调整
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard1  #mongo1下其他两个分片shard2为shard2,shard3为shard3,mongo2、mongo3下对应做调整
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard1/run/mongod.pid
replication:
  replSetName: shard1  #副本集名称,下其他两个分片对应调整shard2为shard2,shard3为shard3
sharding:
  clusterRole: shardsvr #集群中角色归属
View Code

shard2.conf:

net:
  port: 27002
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo1\log\shard2.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard2
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard2/run/mongod.pid
replication:
  replSetName: shard2
sharding:
  clusterRole: shardsvr
View Code

shard3.conf:

net:
  port: 27003
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo1\log\shard3.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo1\data\shard3
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard3/run/mongod.pid
replication:
  replSetName: shard3
sharding:
  clusterRole: shardsvr
View Code

配置mongos.conf:

systemLog:
  destination: file
  logAppend: true
  path:  D:\tool\mongodbmy\mongo\mongo1\log\mongos.log #mongos没有数据存储地址,只有日志输出地址,mongo2、mongo3下做对应的地址调整
# network interfaces
net:
  port: 27019 # mongos1的端口,mongos2为27029,mongos3为27039
  bindIp: 0.0.0.0
setParameter:
  enableLocalhostAuthBypass: false
#注意!此处配置的连接地址为配置服务器config Serve的副本集名称和所在服务器地址以及端口
sharding:
  configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
View Code

其次编辑mong2的config的配置文件:config.conf

net:
  port: 27028  #config1的端口,mongo2下的为27028,mongo3下的为27038
  bindIp: 0.0.0.0  #允许连接地址,这里统一设置为允许任何ip连接
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo2\log\config.log  #config的日志存储地址,mongo2,mongo3下路径调整即可
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo2\data\config   #config的数据存储地址,mongo2、mongo3下做相应的调整
  journal:
    enabled: true #数据故障恢复和持久化,肯定是开启
#processManagement:
#  fork: true    #linux下打开此设置,Windows环境下后台启动需要注册服务,
#  pidFilePath: /mongo/config/run/mongod.pid
#副本集名称设置
replication:
  replSetName: configs
#分片集群角色,配置服务器的固定值
sharding:
  clusterRole: configsvr
#这里是集群安全认证配置,首次配置启动集群不打开此配置,先留着,后面再说
#security: 
#  keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file
#  authorization: enabled
View Code

shard1.conf 如下:

net:
  port: 27021   #mongo1下其他两个分片shard2为27002,shard3为27003,mongo2、mongo3下对应上面的服务编排表设置端口
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo2\log\shard1.log #mongo1下其他两个分片shard2为shard2.log,shard3为shard3.log,mongo2、mongo3下对应做调整
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard1  #mongo1下其他两个分片shard2为shard2,shard3为shard3,mongo2、mongo3下对应做调整
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard1/run/mongod.pid
replication:
  replSetName: shard1  #副本集名称,下其他两个分片对应调整shard2为shard2,shard3为shard3
sharding:
  clusterRole: shardsvr #集群中角色归属
View Code

shard2.conf 如下:

net:
  port: 27022
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo2\log\shard2.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard2
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard2/run/mongod.pid
replication:
  replSetName: shard2
sharding:
  clusterRole: shardsvr
View Code

shard3.conf 如下:

net:
  port: 27023
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo2\log\shard3.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo2\data\shard3
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard3/run/mongod.pid
replication:
  replSetName: shard3
sharding:
  clusterRole: shardsvr
View Code

配置mongos.conf:

systemLog:
  destination: file
  logAppend: true
  path:  D:\tool\mongodbmy\mongo\mongo2\log\mongos.log #mongos没有数据存储地址,只有日志输出地址,mongo2、mongo3下做对应的地址调整
# network interfaces
net:
  port: 27029 # mongos1的端口,mongos2为27029,mongos3为27039
  bindIp: 0.0.0.0
setParameter:
  enableLocalhostAuthBypass: false
#注意!此处配置的连接地址为配置服务器config Serve的副本集名称和所在服务器地址以及端口
sharding:
  configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
View Code

最后编辑mong3 文件夹下的config.conf:

net:
  port: 27038  #config1的端口,mongo2下的为27028,mongo3下的为27038
  bindIp: 0.0.0.0  #允许连接地址,这里统一设置为允许任何ip连接
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo3\log\config.log  #config的日志存储地址,mongo2,mongo3下路径调整即可
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo3\data\config   #config的数据存储地址,mongo2、mongo3下做相应的调整
  journal:
    enabled: true #数据故障恢复和持久化,肯定是开启
#processManagement:
#  fork: true    #linux下打开此设置,Windows环境下后台启动需要注册服务,
#  pidFilePath: /mongo/config/run/mongod.pid
#副本集名称设置
replication:
  replSetName: configs
#分片集群角色,配置服务器的固定值
sharding:
  clusterRole: configsvr
#这里是集群安全认证配置,首次配置启动集群不打开此配置,先留着,后面再说
#security: 
#  keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file
#  authorization: enabled
View Code

shard1.conf 如下:

net:
  port: 27031   #mongo1下其他两个分片shard2为27002,shard3为27003,mongo2、mongo3下对应上面的服务编排表设置端口
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo3\log\shard1.log #mongo1下其他两个分片shard2为shard2.log,shard3为shard3.log,mongo2、mongo3下对应做调整
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard1  #mongo1下其他两个分片shard2为shard2,shard3为shard3,mongo2、mongo3下对应做调整
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard1/run/mongod.pid
replication:
  replSetName: shard1  #副本集名称,下其他两个分片对应调整shard2为shard2,shard3为shard3
sharding:
  clusterRole: shardsvr #集群中角色归属
View Code

shard2.conf 如下:

net:
  port: 27032
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo3\log\shard2.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard2
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard2/run/mongod.pid
replication:
  replSetName: shard2
sharding:
  clusterRole: shardsvr
View Code

shard3.conf 如下:

net:
  port: 27033
  bindIp: 0.0.0.0
systemLog:
  destination: file
  logAppend: true
  path: D:\tool\mongodbmy\mongo\mongo3\log\shard3.log
storage:
  dbPath: D:\tool\mongodbmy\mongo\mongo3\data\shard3
  journal:
    enabled: true
#processManagement:
#  fork: true
#  pidFilePath: /mongo/shard3/run/mongod.pid
replication:
  replSetName: shard3
sharding:
  clusterRole: shardsvr
View Code

配置mongos.conf:

systemLog:
  destination: file
  logAppend: true
  path:  D:\tool\mongodbmy\mongo\mongo3\log\mongos.log #mongos没有数据存储地址,只有日志输出地址,mongo2、mongo3下做对应的地址调整
# network interfaces
net:
  port: 27039 # mongos1的端口,mongos2为27029,mongos3为27039
  bindIp: 0.0.0.0
setParameter:
  enableLocalhostAuthBypass: false
#注意!此处配置的连接地址为配置服务器config Serve的副本集名称和所在服务器地址以及端口
sharding:
  configDB: configs/127.0.0.1:27018,127.0.0.1:27028,127.0.0.1:27038
View Code

至此,mongo1下的配置结束,将上述配置文件内容拷贝到mongo2,mongo3对应的文件,根据服务编排内容做端口和路径的调整,切记!!一定要按照服务编排好的端口

去设置,路径一定要配置对应的文件!!!切记切记!!

配置文件下载:https://files.cnblogs.com/files/chenwolong/mongosConfig.zip

以上便是配置,下面进入启动服务。

启动服务,配置副本集

分片集群必须按照一定的顺序启动:config serve,Shard ,Mongos,

首先,启动三台服务器的config:在mongo安装目录bin目录下以管理员身份打开3个dos窗口分别执行下面三条dos命令,当然,如果你配置了mongo的环境变量【没有配置,需要去设置环境变量】,任意地方

开启三个dos窗口,执行如下doc命令【三台服务器各执行一次】。

mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\config.conf

mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\config.conf

mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\config.conf

 

 

 【其他两个指令截图类似

【1】然后新开窗口连接到任意一台config server  【真实服务器下,不要忘记指定IP,默认为127.0.0.1】

mongo -host 127.0.0.1  --port 27018

【2】然后配置配置器的服务集:

config = {   _id : "configs",     
        members : [         
                {_id : 0, host : "127.0.0.1:27018" },         
                {_id : 1, host : "127.0.0.1:27028" },         
                {_id : 2, host : "127.0.0.1:27038" }     
            ]  }

【3】初始化副本集:

rs.initiate(config)

【4】查看副本集状态:

rs.status()

上述【1】【2】【3】【4】四个指令执行完毕后, mongos1/mongos2/mongos3服务器中 data/config 和 logs/config 文件夹中将会生产相应的文件

上述【1】【2】【3】【4】四个指令在同一个窗口中执行,执行结果打印的脚本太多,无法整体截图,贴出来供大家参考:

PS D:\tool\mongodbmy\mongo\bin> mongo --port 27018
MongoDB shell version v4.2.12-6-ga3c3db2
connecting to: mongodb://127.0.0.1:27018/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("1506619d-cbf5-42e7-9bd3-bba5813d4998") }
MongoDB server version: 4.2.12-6-ga3c3db2
Server has startup warnings:
2021-02-01T16:57:53.876+0800 I  CONTROL  [initandlisten]
2021-02-01T16:57:53.876+0800 I  CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2021-02-01T16:57:53.876+0800 I  CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2021-02-01T16:57:53.876+0800 I  CONTROL  [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).

The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

> config = {   _id : "configs",
...         members : [
...                 {_id : 0, host : "127.0.0.1:27018" },
...                 {_id : 1, host : "127.0.0.1:27028" },
...                 {_id : 2, host : "127.0.0.1:27038" }
...             ]  }
{
        "_id" : "configs",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "127.0.0.1:27018"
                },
                {
                        "_id" : 1,
                        "host" : "127.0.0.1:27028"
                },
                {
                        "_id" : 2,
                        "host" : "127.0.0.1:27038"
                }
        ]
}
> rs.initiate(config)
{
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1612169978, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1612169978, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1612169978, 1)
}
configs:SECONDARY> rs.status()
{
        "set" : "configs",
        "date" : ISODate("2021-02-01T08:59:48.508Z"),
        "myState" : 2,
        "term" : NumberLong(0),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "configsvr" : true,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(0, 0),
                        "t" : NumberLong(-1)
                },
                "lastCommittedWallTime" : ISODate("1970-01-01T00:00:00Z"),
                "appliedOpTime" : {
                        "ts" : Timestamp(1612169978, 1),
                        "t" : NumberLong(-1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1612169978, 1),
                        "t" : NumberLong(-1)
                },
                "lastAppliedWallTime" : ISODate("2021-02-01T08:59:38.372Z"),
                "lastDurableWallTime" : ISODate("2021-02-01T08:59:38.372Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(0, 0),
        "lastStableCheckpointTimestamp" : Timestamp(0, 0),
        "members" : [
                {
                        "_id" : 0,
                        "name" : "127.0.0.1:27018",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 115,
                        "optime" : {
                                "ts" : Timestamp(1612169978, 1),
                                "t" : NumberLong(-1)
                        },
                        "optimeDate" : ISODate("2021-02-01T08:59:38Z"),
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "could not find member to sync from",
                        "configVersion" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "127.0.0.1:27028",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 10,
                        "optime" : {
                                "ts" : Timestamp(1612169978, 1),
                                "t" : NumberLong(-1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1612169978, 1),
                                "t" : NumberLong(-1)
                        },
                        "optimeDate" : ISODate("2021-02-01T08:59:38Z"),
                        "optimeDurableDate" : ISODate("2021-02-01T08:59:38Z"),
                        "lastHeartbeat" : ISODate("2021-02-01T08:59:48.396Z"),
                        "lastHeartbeatRecv" : ISODate("2021-02-01T08:59:48.459Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "configVersion" : 1
                },
                {
                        "_id" : 2,
                        "name" : "127.0.0.1:27038",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 10,
                        "optime" : {
                                "ts" : Timestamp(1612169978, 1),
                                "t" : NumberLong(-1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1612169978, 1),
                                "t" : NumberLong(-1)
                        },
                        "optimeDate" : ISODate("2021-02-01T08:59:38Z"),
                        "optimeDurableDate" : ISODate("2021-02-01T08:59:38Z"),
                        "lastHeartbeat" : ISODate("2021-02-01T08:59:48.399Z"),
                        "lastHeartbeatRecv" : ISODate("2021-02-01T08:59:48.450Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncingTo" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "configVersion" : 1
                }
        ],
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1612169978, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1612169978, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1612169978, 1)
}
configs:SECONDARY>
View Code

启动3个分片副本集组:分别开9个窗口启动执行下面9条dos命令启动shard1:

mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard1.conf
mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard1.conf
mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard1.conf

其他两个指令截图类似

【A1】新开窗口连接到mong1文件夹的shard1

mongo --port 27001

【B1】配置mong1文件夹的shard1的副本集:

config = { _id : "shard1",
members : [ 
{_id : 0, host : "127.0.0.1:27001"},
{_id : 1, host : "127.0.0.1:27021"},
{_id : 2, host : "127.0.0.1:27031"}
] }

【C1】初始化mong1文件夹的副本集:

rs.initiate(config);

开启分片2副本集:

mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard2.conf
mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard2.conf
mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard2.conf

【A2】新开窗口连接到mong2文件夹的shard2

mongo --port 27002

【B2】配置mong2文件夹的shard2的副本集:

config = { _id : "shard2",
... members : [
... {_id : 0, host : "127.0.0.1:27002"},
... {_id : 1, host : "127.0.0.1:27022"},
... {_id : 2, host : "127.0.0.1:27032"}
... ] }

【C2】初始化mong2文件夹的副本集:

rs.initiate(config);

开启分片3副本集:

mongod -f D:\tool\mongodbmy\mongo\mongo1\conf\shard3.conf
mongod -f D:\tool\mongodbmy\mongo\mongo2\conf\shard3.conf
mongod -f D:\tool\mongodbmy\mongo\mongo3\conf\shard3.conf

【A3】新开窗口连接到mong3文件夹的shard3

mongo --port 27003

【B3】配置mong3文件夹的shard3的副本集:

config = { _id : "shard3",
... members : [
... {_id : 0, host : "127.0.0.1:27003"},
... {_id : 1, host : "127.0.0.1:27023"},
... {_id : 2, host : "127.0.0.1:27033"}
... ] }

【C3】初始化mong3文件夹的副本集:

rs.initiate(config);

关于上述【A1~A3,B1~B3,C1~C3】,贴出执行打印结果,其他类似:

PS D:\tool\mongodbmy\mongo\bin> mongo --port 27021
MongoDB shell version v4.2.12-6-ga3c3db2
connecting to: mongodb://127.0.0.1:27021/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("c725ae9f-d0d6-4ca3-99c1-24f88eecbcf5") }
MongoDB server version: 4.2.12-6-ga3c3db2
Server has startup warnings:
2021-02-01T17:00:34.062+0800 I  CONTROL  [initandlisten]
2021-02-01T17:00:34.062+0800 I  CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2021-02-01T17:00:34.062+0800 I  CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2021-02-01T17:00:34.063+0800 I  CONTROL  [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).

The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

shard1:SECONDARY> config = { _id : "shard2",
... members : [
... {_id : 0, host : "127.0.0.1:27021"},
... {_id : 1, host : "127.0.0.1:27022"},
... {_id : 2, host : "127.0.0.1:27023"}
... ] }
{
        "_id" : "shard2",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "127.0.0.1:27021"
                },
                {
                        "_id" : 1,
                        "host" : "127.0.0.1:27022"
                },
                {
                        "_id" : 2,
                        "host" : "127.0.0.1:27023"
                }
        ]
}
shard1:SECONDARY> rs.initiate(config);
{
        "operationTime" : Timestamp(1612170313, 1),
        "ok" : 0,
        "errmsg" : "already initialized",
        "code" : 23,
        "codeName" : "AlreadyInitialized",
        "$clusterTime" : {
                "clusterTime" : Timestamp(1612170313, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}
shard1:SECONDARY>
View Code

最后:

分别启动前端路由器mongos1,mongos2,mongos3,

注意,这里启动是用mongos!!!!!开三个窗口:

mongos -f D:\tool\mongodbmy\mongo\mongo1\conf\mongos.conf

mongos -f D:\tool\mongodbmy\mongo\mongo2\conf\mongos.conf

mongos -f D:\tool\mongodbmy\mongo\mongo3\conf\mongos.conf

 

 【其他两个指令截图类似

【S1】新开一个窗口:连接任意一个mongos,

mongo --port 27019

【S2】然后使用admin库,启用集群分片:

use admin;
sh.addShard("shard1/127.0.0.1:27001,127.0.0.1:27021,127.0.0.1:27031");
sh.addShard("shard2/127.0.0.1:27002,127.0.0.1:27022,127.0.0.1:27032");
sh.addShard("shard3/127.0.0.1:27003,127.0.0.1:27023,127.0.0.1:27033");
db.createUser( { user: "admin", pwd: "admin",  roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]  } )

#关闭当前mongos 连接,重连如下:
mongo --port 27017 -u "admin" -p "admin" --authenticationDatabase "admin"

至此,分片集群搭建完成,

那么,测试一下:

#设置一下chunk的大小:
use config;
db.setting.save({"_id":"chunksize","value":1}) # 设置块大小为1M是方便实验,不然需要插入海量数据

#模拟写入数据
use testdb;
#启用数据库分片
sh.enableSharding("testdb")
#创建集合
use testdb;
db.createCollection("user");
db.user.createIndex({"name":"hased"}) # 以"name"作哈希索引分片键
sh.shardCollection( "testdb.user", { "name" : "hashed" } ) #对user集合启用分片

for(i=1;i<=50000;i++){db.user.insert({"id":i,"name":"zzx"+i})} #模拟往mytest数据库的user表写入5万数据
sh.status() # 查看分片情况
sh.help() # 查看sh下所有指令
db.settings.help()  # 查看数据库分片帮助指令
db.runCommand({listShards:1})  # 查看分片列表,所有分片
 
use config;
查询当前块大小
db.settings.find({"_id":"chunksize"})
修改块大小
db.settings.save( { _id:"chunksize", value: 64 } );

如果看到数据平均分布于shard1,shard2,shard3,那么说明我们搭建成功,启用分片成功。

4 分片集群下的安全认证实现:

MongoDB支持许多客户端可用于验证其身份的身份验证机制。这些机制允许MongoDB集成到您现有的身份验证系统中。除了验证客户端的身份之外,MongoDB还

可以要求副本集和分片集群的成员对其各自的副本集或分片集群的成员身份进行身份验证。有关 更多信息,请参阅内部验证

首先,生成集群成员内部认证的秘钥文件,密钥文件的内容充当成员的共享密码。密钥长度必须介于6到1024个字符之间,并且只能包含base64集中的字符。如果是

生产环境,将生成后的秘钥文件拷贝到存在集群成员的每一台服务器,注意,生产环境下各节点的秘钥文件内容必须一致。

然后在所有config.conf和shard.conf中增加两项安全认证配置:

security:
keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file #秘钥文件路径
authorization: enabled #开启客户端认证

在所有mongos.conf添加:

security:
keyFile: D:\tool\mongodbmy\mongo\mongodb-keyfile.file #秘钥文件路径

至此配置结束,那么客户端的身份认证是通过用户名和密码进行认证,我们还需要创建用户和用户名,假设我们给testdb库创建用户,连接某一个mongos,为其创建用户:

mongos --port 27019;
use admin;//注意,一定要使用admin库去创建用户
db.createUser({user: "testdb", pwd: "testdb", roles: [{role: "readWrite", db:"testdb" }]})

用户创建完毕。重启集群使安全认证配置生效。

注意,这里启动是用mongos!!!!!

 注:

2.2 集群中数据分布

2.2.1 Chunk是什么

  在一个shard server内部,MongoDB还是会把数据分为chunks,每个chunk代表这个shard server内部一部分数据。chunk的产生,会有以下两个用途:

  Splitting当一个chunk的大小超过配置中的chunk size时,MongoDB的后台进程会把这个chunk切分成更小的chunk,从而避免chunk过大的情况

  Balancing在MongoDB中,balancer是一个后台进程,负责chunk的迁移,从而均衡各个shard server的负载,系统初始1个chunk,chunk size默认值64M,生产库上选择适合业务的chunk size是最好的。ongoDB会自动拆分和迁移chunks。

分片集群的数据分布(shard节点)

(1)使用chunk来存储数据

(2)进群搭建完成之后,默认开启一个chunk,大小是64M,

(3)存储需求超过64M,chunk会进行分裂,如果单位时间存储需求很大,设置更大的chunk

(4)chunk会被自动均衡迁移。

2.2.2 chunksize的选择

  适合业务的chunksize是最好的。

  chunk的分裂和迁移非常消耗IO资源;chunk分裂的时机:在插入和更新,读数据不会分裂。

  chunksize的选择:

  小的chunksize:数据均衡是迁移速度快,数据分布更均匀。数据分裂频繁,路由节点消耗更多资源。大的chunksize:数据分裂少。数据块移动集中消耗IO资源。通常100-200M

2.2.3 chunk分裂及迁移

  随着数据的增长,其中的数据大小超过了配置的chunk size,默认是64M,则这个chunk就会分裂成两个。数据的增长会让chunk分裂得越来越多。

 

  这时候,各个shard 上的chunk数量就会不平衡。这时候,mongos中的一个组件balancer  就会执行自动平衡。把chunk从chunk数量最多的shard节点挪动到数量最少的节点。

 

chunkSize 对分裂及迁移的影响

  MongoDB 默认的 chunkSize 为64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk 分裂、迁移的行为。

  chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk 分裂及迁移会更少,但可能导致数据分布不均。

  chunkSize 太小,容易出现 jumbo chunk(即shardKey 的某个取值出现频率很高,这些文档只能放到一个 chunk 里,无法再分裂)而无法迁移;chunkSize 越大,则可能出现 chunk 内文档数太多(chunk 内文档数不能超过 250000 )而无法迁移。

  chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将 chunk 分裂到指定的大小。

  chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但 chunk 大小会随着写入不断增长,直到达到目标大小。

2.3 数据区分

2.3.1 分片键shard key

  MongoDB中数据的分片是、以集合为基本单位的,集合中的数据通过片键(Shard key)被分成多部分。其实片键就是在集合中选一个键,用该键的值作为数据拆分的依据。

  所以一个好的片键对分片至关重要。片键必须是一个索引,通过sh.shardCollection加会自动创建索引(前提是此集合不存在的情况下)。一个自增的片键对写入和数据均匀分布就不是很好,因为自增的片键总会在一个分片上写入,后续达到某个阀值可能会写到别的分片。但是按照片键查询会非常高效。

  随机片键对数据的均匀分布效果很好。注意尽量避免在多个分片上进行查询。在所有分片上查询,mongos会对结果进行归并排序。

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

  为了按照片键划分数据块,MongoDB使用基于范围的分片方式或者 基于哈希的分片方式。

注意:

分片键是不可变。

分片键必须有索引。

分片键大小限制512bytes。

分片键用于路由查询。

MongoDB不接受已进行collection级分片的collection上插入无分片

键的文档(也不支持空值插入)

2.3.2 以范围为基础的分片Sharded Cluster

  Sharded Cluster支持将单个集合的数据分散存储在多shard上,用户可以指定根据集合内文档的某个字段即shard key来进行范围分片(range sharding)。

 

  对于基于范围的分片,MongoDB按照片键的范围把数据分成不同部分。

  假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点。MongoDB把这条直线划分为更短的不重叠的片段,并称之为数据块,每个数据块包含了片键在一定范围内的数据。在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。

2.3.3 基于哈希的分片

  分片过程中利用哈希索引作为分片的单个键,且哈希分片的片键只能使用一个字段,而基于哈希片键最大的好处就是保证数据在各个节点分布基本均匀。

 

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

  Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。

2.3.4 分片键选择建议

1、递增的sharding key

数据文件挪动小。(优势)

因为数据文件递增,所以会把insert的写IO永久放在最后一片上,造成最后一片的写热点。同时,随着最后一片的数据量增大,将不断的发生迁移至之前的片上。

2、随机的sharding key

数据分布均匀,insert的写IO均匀分布在多个片上。(优势)

大量的随机IO,磁盘不堪重荷。

3、混合型key

大方向随机递增,小范围随机分布。

为了防止出现大量的chunk均衡迁移,可能造成的IO压力。我们需要设置合理分片使用策略(片键的选择、分片算法(range、hash))

分片注意:

   分片键是不可变、分片键必须有索引、分片键大小限制512bytes、分片键用于路由查询。

   MongoDB不接受已进行collection级分片的collection上插入无分片键的文档(也不支持空值插入)

后期运维

启动关闭

mongodb的启动顺序是,先启动配置服务器,在启动分片,最后启动mongos.

mongod -f /usr/local/mongodb/conf/config.conf
mongod -f /usr/local/mongodb/conf/shard1.conf
mongod -f /usr/local/mongodb/conf/shard2.conf
mongod -f /usr/local/mongodb/conf/shard3.conf
mongod -f /usr/local/mongodb/conf/mongos.conf

关闭时,直接killall杀掉所有进程

killall mongod
killall mongos

查看分片

 

mongos> db.runCommand({listShards:1})

 

查看分片状态

mongos>sh.status()

 

@天才卧龙的博客

posted @ 2021-02-01 17:17  天才卧龙  阅读(1558)  评论(0编辑  收藏  举报