# lagou-mongodb-sharding
**Repository Path**: hackerodm/lagou-mongodb-sharding
## Basic Information
- **Project Name**: lagou-mongodb-sharding
- **Description**: 业务场景:用户在拉勾网投递简历时,我们会为每次投递的简历生成一份快照,将快照信息存储到
MongoDB中。
功能需求:搭建MongoDB分片集群,模拟简历快照数据进行操作,具体要求如下:
(1) 如图搭建一个分片集群,要求每个分片节点中的复制集含有一个仲裁节点
(2) 使用权限控制,建立要访问的数据库lg_resume,这个账号名字是lagou_gx、密码是abc321
这个账号对数据库有读写权限
(3) 使用SpringBoot 进行访问分片集群,对lg_resume 库中的lg_resume_datas 进行增加和查询操作
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2021-04-08
- **Last Updated**: 2023-01-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# lagou-mongodb-sharding
### 一、介绍
#### 1.1、视频讲解地址
链接:https://pan.baidu.com/s/1gnTlxOCcM6VLVqry6lY4MQ
提取码:fmm7
#### 1.2、作业内容
业务场景:用户在拉勾网投递简历时,我们会为每次投递的简历生成一份快照,将快照信息存储到
MongoDB中。
功能需求:搭建MongoDB分片集群,模拟简历快照数据进行操作,具体要求如下:
(1) 如图搭建一个分片集群,要求每个分片节点中的复制集含有一个仲裁节点
(2) 使用权限控制,建立要访问的数据库lg_resume,这个账号名字是lagou_gx、密码是abc321
这个账号对数据库有读写权限
(3) 使用SpringBoot 进行访问分片集群,对lg_resume 库中的lg_resume_datas 进行增加和查询操作
### 二、环境及软件版本
| 环境 | 版本 |
| ------------------------- | ----- |
| 操作系统:Centos 7 x86_64 | 7 |
| 虚拟机:VMware | 15.5 |
| 远程连接:XShell | 6.0 |
| 数据库:mongo | 4.1.3 |
| 文件传输:XFtp | 6.0 |
| JDK | 1.8 |
### 三、整体架构

本集群采用伪集群方式搭建,所有节点均部署在一台虚拟机。虚拟机IP:192.168.0.234
#### 3.1、路径规划
| 端口 | 目录名称 | 用途 |
| ----- | ------------------------------------------ | ------------------------- |
| | /usr/local/mongodb/config | Config Server配置信息目录 |
| | /usr/local/mongodb/config/logs | Config Server日志目录 |
| 17011 | /usr/local/mongodb/config/cnf17011 | Config Server1数据目录 |
| 17013 | /usr/local/mongodb/config/cnf17013 | Config Server2数据目录 |
| 17015 | /usr/local/mongodb/config/cnf17015 | Config Server3数据目录 |
| | /usr/local/mongodb/shard | Shard Server分片配置目录 |
| | /usr/local/mongodb/shard/logs | shard Server日志文件 |
| | /usr/local/mongodb/shard/shard1 | Shard1数据目录 |
| 37011 | /usr/local/mongodb/shard/shard1/shard37011 | Shard1集群节点37011 |
| 37013 | /usr/local/mongodb/shard/shard1/shard37013 | Shard1集群节点37013 |
| 37015 | /usr/local/mongodb/shard/shard1/shard37015 | Shard1集群节点37015 |
| 37017 | /usr/local/mongodb/shard/shard1/shard37017 | Shard1仲裁节点37017 |
| | /usr/local/mongodb/shard/shard2 | Shard2数据目录 |
| 47011 | /usr/local/mongodb/shard/shard2/shard47011 | Shard2集群节点47011 |
| 47013 | /usr/local/mongodb/shard/shard2/shard47013 | Shard2集群节点47013 |
| 47015 | /usr/local/mongodb/shard/shard2/shard47015 | Shard2集群节点47015 |
| 47017 | /usr/local/mongodb/shard/shard2/shard47017 | shard2仲裁节点47017 |
| | /usr/local/mongodb/shard/shard3 | Shard3数据目录 |
| 57011 | /usr/local/mongodb/shard/shard3/shard57011 | Shard3集群节点57011 |
| 57013 | /usr/local/mongodb/shard/shard3/shard57013 | Shard3集群节点57013 |
| 57015 | /usr/local/mongodb/shard/shard3/shard57015 | Shard3集群节点57015 |
| 57017 | /usr/local/mongodb/shard/shard3/shard57017 | Shard3集群节点57017 |
| | /usr/local/mongodb/shard/shard4 | Shard4数据目录 |
| 58011 | /usr/local/mongodb/shard/shard4/shard58011 | Shard4集群节点58011 |
| 58013 | /usr/local/mongodb/shard/shard4/shard58013 | Shard4集群节点58011 |
| 58015 | /usr/local/mongodb/shard/shard4/shard58015 | Shard4集群节点58011 |
| 58017 | /usr/local/mongodb/shard/shard4/shard58017 | Shard4集群节点58011 |
| 27017 | /usr/local/mongodb/route | 路由节点 |
| | /usr/local/mongodb/route/logs | 路由节点日志 |
#### 3.2、创建目录
```shell
[root@192 mongodb]# mkdir config shard route
[root@192 mongodb]# mkdir route/logs config/logs shard/logs shard/shard1 shard/shard2 shard/shard3 shard/shard4
[root@192 mongodb]# mkdir shard/shard1/shard37011 shard/shard1/shard37013 shard/shard1/shard37015 shard/shard1/shard37017
[root@192 mongodb]# mkdir shard/shard2/shard47011 shard/shard2/shard47013 shard/shard2/shard47015 shard/shard2/shard47017
[root@192 mongodb]# mkdir shard/shard3/shard57011 shard/shard3/shard57013 shard/shard3/shard57015 shard/shard3/shard57017
[root@192 mongodb]# mkdir shard/shard4/shard58011 shard/shard4/shard58013 shard/shard4/shard58015 shard/shard4/shard58017
[root@192 mongodb]# mkdir config/cnf17011 config/cnf17013 config/cnf17015
```
#### 3.3、安装mongodb
下载mongodb-linux-x86_64-4.1.3.tgz,上传到服务器的mongodb目录并解压,解压之后将文件拷贝到mongodb目录:
```shell
[root@192 mongodb]# tar -xvf mongodb-linux-x86_64-4.1.3.tgz
[root@192 mongodb]# mv mongodb-linux-x86_64-4.1.3/* ./
```
#### 3.4、安装psmisc
```shell
[root@192 mongodb]# yum install psmisc -y
```
### 四、MongoDB集群搭建
#### 4.1、配置Config节点
##### 4.1.1、节点1配置config17011.conf
```properties
# 数据库文件位置
dbpath=config/cnf17011
# 日志文件位置
logpath=config/logs/config17011.log
# 追加方式写入日志
logappend=true
# fork守护进程
fork=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=17011
# 标志为配置服务器
configsvr=true
# 配置服务器副本集名称
replSet=configsvr
```
##### 4.1.2、节点2配置config17013.conf
```properties
# 数据库文件位置
dbpath=config/cnf17013
# 日志文件位置
logpath=config/logs/config17013.log
# 追加方式写入日志
logappend=true
# fork守护进程
fork=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=17013
# 标志为配置服务器
configsvr=true
# 配置服务器副本集名称
replSet=configsvr
```
##### 4.1.3、节点3配置config17015.conf
```properties
# 数据库文件位置
dbpath=config/cnf17015
# 日志文件位置
logpath=config/logs/config17015.log
# 追加方式写入日志
logappend=true
# fork守护进程
fork=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=17015
# 标志为配置服务器
configsvr=true
# 配置服务器副本集名称
replSet=configsvr
```
##### 4.1.4、启动配置节点
```shell
[root@192 mongodb]# ./bin/mongod -f config/config17011.conf
[root@192 mongodb]# ./bin/mongod -f config/config17013.conf
[root@192 mongodb]# ./bin/mongod -f config/config17015.conf
```
##### 4.1.5、配置节点集群
进入任意节点的mongo shell 添加配置节点集群,在添加配置节点集群的时候,注意use admin数据库。
配置集群成员并初始化,然后使用rs.status()查看集群状态。
```shell
./bin/mongo --port 17011
use admin
var cfg = {"_id":"configsvr",
"members":[
{"_id":1,"host":"192.168.0.234:17011"},
{"_id":2,"host":"192.168.0.234:17013"},
{"_id":3,"host":"192.168.0.234:17015"},
]
};
rs.initiate(cfg)
rs.status();
```
#### 4.2、分片Sharding节点
分片节点包含四组集群节点配置,并且每组集群
##### 4.2.1、shard1节点配置
shard1集群节点包含37011、37013、37015、37017,将37017作为仲裁节点。
###### 4.2.1.1、37011节点配置
```properties
# 数据库目录
dbpath=shard/shard1/shard37011
# 日志文件存放目录
logpath=shard/logs/shard1-37011.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=37011
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard1
# 指定为shardsvr
shardsvr=true
```
###### 4.2.1.2、37013节点配置
```properties
# 数据库目录
dbpath=shard/shard1/shard37013
# 日志文件存放目录
logpath=shard/logs/shard1-37013.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=37013
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard1
# 指定为shardsvr
shardsvr=true
```
###### 4.2.1.3、37015节点配置
```properties
# 数据库目录
dbpath=shard/shard1/shard37015
# 日志文件存放目录
logpath=shard/logs/shard1-37015.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=37015
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard1
# 指定为shardsvr
shardsvr=true
```
###### 4.2.1.4、37017节点配置
```properties
# 数据库目录
dbpath=shard/shard1/shard37017
# 日志文件存放目录
logpath=shard/logs/shard1-37017.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=37017
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard1
# 指定为shardsvr
shardsvr=true
```
###### 4.2.1.5、启动shard1集群
```shell
[root@192 mongodb]# ./bin/mongod -f shard/shard1/shard37011.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard1/shard37013.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard1/shard37015.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard1/shard37017.conf
```
###### 4.2.1.6、配置shard1集群
```shell
[root@192 mongodb]# ./bin/mongo -port 37011
use admin
var cfg = {"_id":"shard1",
"protocolVersion":1,
"members":[
{"_id":1,"host":"192.168.0.234:37011","priority":10},
{"_id":2,"host":"192.168.0.234:37013","priority":5},
{"_id":3,"host":"192.168.0.234:37015","priority":0},
{"_id":4,"host":"192.168.0.234:37017","arbiterOnly":true}
]
};
rs.initiate(cfg)
rs.status()
```
##### 4.2.2、shard2节点配置
###### 4.2.2.1、47011节点配置
```properties
# 数据库目录
dbpath=shard/shard2/shard47011
# 日志文件存放目录
logpath=shard/logs/shard2-47011.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=47011
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard2
# 指定为shardsvr
shardsvr=true
```
###### 4.2.2.2、47013节点配置
```properties
# 数据库目录
dbpath=shard/shard2/shard47013
# 日志文件存放目录
logpath=shard/logs/shard2-47013.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=47013
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard2
# 指定为shardsvr
shardsvr=true
```
###### 4.2.2.3、47015节点配置
```properties
# 数据库目录
dbpath=shard/shard2/shard47015
# 日志文件存放目录
logpath=shard/logs/shard2-47015.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=47015
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard2
# 指定为shardsvr
shardsvr=true
```
###### 4.2.2.4、47017节点配置
```properties
# 数据库目录
dbpath=shard/shard2/shard47017
# 日志文件存放目录
logpath=shard/logs/shard2-47017.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=47017
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard2
# 指定为shardsvr
shardsvr=true
```
###### 4.2.2.5、启动shard2集群
```shell
[root@192 mongodb]# ./bin/mongod -f shard/shard2/shard47011.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard2/shard47013.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard2/shard47015.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard2/shard47017.conf
```
###### 4.2.2.6、配置shard2集群
进入任意节点,进行初始化操作。
```shell
./bin/mongo -port 47011
use admin
var cfg = {"_id":"shard2",
"protocolVersion":1,
"members":[
{"_id":1,"host":"192.168.0.234:47011","priority":10},
{"_id":2,"host":"192.168.0.234:47013","priority":5},
{"_id":3,"host":"192.168.0.234:47015","priority":0},
{"_id":4,"host":"192.168.0.234:47017","arbiterOnly":true}
]
};
rs.initiate(cfg);
rs.status();
```
##### 4.2.3、shard3节点配置
###### 4.2.3.1、57011节点配置
```properties
# 数据库目录
dbpath=shard/shard3/shard57011
# 日志文件存放目录
logpath=shard/logs/shard3-57011.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=57011
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard3
# 指定为shardsvr
shardsvr=true
```
###### 4.2.3.2、57013节点配置
```properties
# 数据库目录
dbpath=shard/shard3/shard57013
# 日志文件存放目录
logpath=shard/logs/shard3-57013.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=57013
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard3
# 指定为shardsvr
shardsvr=true
```
###### 4.2.3.3、57015节点配置
```properties
# 数据库目录
dbpath=shard/shard3/shard57015
# 日志文件存放目录
logpath=shard/logs/shard3-57015.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=57015
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard3
# 指定为shardsvr
shardsvr=true
```
###### 4.2.3.4、57017节点配置
```properties
# 数据库目录
dbpath=shard/shard3/shard57017
# 日志文件存放目录
logpath=shard/logs/shard3-57017.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=57017
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard3
# 指定为shardsvr
shardsvr=true
```
###### 4.2.3.5、启动shard3集群
```shell
[root@192 mongodb]# ./bin/mongod -f shard/shard3/shard57011.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard3/shard57013.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard3/shard57015.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard3/shard57017.conf
```
###### 4.2.3.6、配置shard3集群
```shell
[root@192 mongodb]# ./bin/mongo -port 57011
use admin
var cfg = {"_id":"shard3",
"protocolVersion":1,
"members":[
{"_id":1,"host":"192.168.0.234:57011","priority":10},
{"_id":2,"host":"192.168.0.234:57013","priority":5},
{"_id":3,"host":"192.168.0.234:57015","priority":0},
{"_id":4,"host":"192.168.0.234:57017","arbiterOnly":true}
]
};
rs.initiate(cfg);
rs.status();
```
##### 4.2.4、shard4节点配置
###### 4.2.4.1、58011节点配置
```properties
# 数据库目录
dbpath=shard/shard4/shard58011
# 日志文件存放目录
logpath=shard/logs/shard4-58011.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=58011
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard4
# 指定为shardsvr
shardsvr=true
```
###### 4.2.4.2、58013节点配置
```properties
# 数据库目录
dbpath=shard/shard4/shard58013
# 日志文件存放目录
logpath=shard/logs/shard4-58013.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=58013
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard4
# 指定为shardsvr
shardsvr=true
```
###### 4.2.4.3、58015节点配置
```properties
# 数据库目录
dbpath=shard/shard4/shard58015
# 日志文件存放目录
logpath=shard/logs/shard4-58015.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=58015
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard4
# 指定为shardsvr
shardsvr=true
```
###### 4.2.4.4、58017节点配置
```properties
# 数据库目录
dbpath=shard/shard4/shard58017
# 日志文件存放目录
logpath=shard/logs/shard4-58017.log
# 追加方式写入日志
logappend=true
# 绑定IP
bind_ip=0.0.0.0
# 端口
port=58017
# 后台守护进程启动
fork=true
# 复制集名称
replSet=shard4
# 指定为shardsvr
shardsvr=true
```
###### 4.2.4.5、启动shard4集群
```shell
[root@192 mongodb]# ./bin/mongod -f shard/shard4/shard58011.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard4/shard58013.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard4/shard58015.conf
[root@192 mongodb]# ./bin/mongod -f shard/shard4/shard58017.conf
```
###### 4.2.4.6、配置shard4集群
```shell
[root@192 mongodb]# ./bin/mongo -port 58011
use admin
var cfg = {"_id":"shard4",
"protocolVersion":1,
"members":[
{"_id":1,"host":"192.168.0.234:58011","priority":10},
{"_id":2,"host":"192.168.0.234:58013","priority":5},
{"_id":3,"host":"192.168.0.234:58015","priority":0},
{"_id":4,"host":"192.168.0.234:58017","arbiterOnly":true}
]
};
rs.initiate(cfg);
rs.status();
```
#### 4.3、路由节点
##### 4.3.1、路由节点27017配置
route27017.conf
```properties
# 端口
port=27017
# 绑定IP
bind_ip=0.0.0.0
# fork
fork=true
# 日志文件
logpath=route/logs/route.log
# 追加方式记录日志
logappend=true
# 配置集群
configdb=configsvr/192.168.0.234:17011,192.168.0.234:17013,192.168.0.234:17015
```
##### 4.3.2、路由节点启动
采用mongs启动路由节点。
```shell
[root@192 mongodb]# ./bin/mongos -f route/route-27017.conf
```
##### 4.3.3、mongos添加分片节点
```shell
[root@192 mongodb]# ./bin/mongos -f route/route-27017.conf
sh.status()
sh.addShard("shard1/192.168.0.234:37011,192.168.0.234:37013,192.168.0.234:37015,192.168.0.234:37017");
sh.addShard("shard2/192.168.0.234:47011,192.168.0.234:47013,192.168.0.234:47015,192.168.0.234:47017");
sh.addShard("shard3/192.168.0.234:57011,192.168.0.234:57013,192.168.0.234:57015,192.168.0.234:57017");
sh.addShard("shard4/192.168.0.234:58011,192.168.0.234:58013,192.168.0.234:58015,192.168.0.234:58017");
sh.status()
```
##### 4.3.4、开启数据库和集合分片(指定片键)
继续使用mongos完成分片开启和分片大小设置。
本例存储简历快照数据库,分片键采用hash算法,对resumeid字段进行分片。
```shell
#开启数据库分片功能
mongos> sh.enableSharding("lagou_resume");
#指定集合开启分片功能
sh.shardCollection("lagou_resume.lagou_resume_datas",{"resumeid":"hashed"})
```
最终的集群状态信息:
```json
mongos> sh.status();
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("5f6eed16d073eb1450241ff9")
}
shards:
{ "_id" : "shard1", "host" : "shard1/192.168.0.234:37011,192.168.0.234:37013,192.168.0.234:37015", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2/192.168.0.234:47011,192.168.0.234:47013,192.168.0.234:47015", "state" : 1 }
{ "_id" : "shard3", "host" : "shard3/192.168.0.234:57011,192.168.0.234:57013,192.168.0.234:57015", "state" : 1 }
{ "_id" : "shard4", "host" : "shard4/192.168.0.234:58011,192.168.0.234:58013,192.168.0.234:58015", "state" : 1 }
active mongoses:
"4.1.3" : 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 }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
shard1 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : shard1 Timestamp(1, 0)
{ "_id" : "lagou_resume", "primary" : "shard4", "partitioned" : true, "version" : { "uuid" : UUID("e2a6bd19-a6be-46ea-97c9-95ac9a3b99d1"), "lastMod" : 1 } }
lagou_resume.lagou_resume_datas
shard key: { "resumeid" : "hashed" }
unique: false
balancing: true
chunks:
shard1 2
shard2 2
shard3 2
shard4 2
{ "resumeid" : { "$minKey" : 1 } } -->> { "resumeid" : NumberLong("-6917529027641081850") } on : shard1 Timestamp(1, 0)
{ "resumeid" : NumberLong("-6917529027641081850") } -->> { "resumeid" : NumberLong("-4611686018427387900") } on : shard1 Timestamp(1, 1)
{ "resumeid" : NumberLong("-4611686018427387900") } -->> { "resumeid" : NumberLong("-2305843009213693950") } on : shard2 Timestamp(1, 2)
{ "resumeid" : NumberLong("-2305843009213693950") } -->> { "resumeid" : NumberLong(0) } on : shard2 Timestamp(1, 3)
{ "resumeid" : NumberLong(0) } -->> { "resumeid" : NumberLong("2305843009213693950") } on : shard3 Timestamp(1, 4)
{ "resumeid" : NumberLong("2305843009213693950") } -->> { "resumeid" : NumberLong("4611686018427387900") } on : shard3 Timestamp(1, 5)
{ "resumeid" : NumberLong("4611686018427387900") } -->> { "resumeid" : NumberLong("6917529027641081850") } on : shard4 Timestamp(1, 6)
{ "resumeid" : NumberLong("6917529027641081850") } -->> { "resumeid" : { "$maxKey" : 1 } } on : shard4 Timestamp(1, 7)
```
#### 4.4、写入测试数据
##### 4.4.1、写入测试数据
```js
db.lagou_resume_datas.insert({resumeid:1,name:'zhangsan',city:'cs',birth_day:new ISODate('2001-08-01'),expectSalary:18000});
db.lagou_resume_datas.insert({resumeid:2,name:'lisi',city:'gz',birth_day:new ISODate('2001-08-01'),expectSalary:18000});
db.lagou_resume_datas.insert({resumeid:3,name:'wangwu',city:'sh',birth_day:new ISODate('2001-08-01'),expectSalary:15000});
db.lagou_resume_datas.insert({resumeid:4,name:'zhaoliu',city:'bj',birth_day:new ISODate('2001-08-01'),expectSalary:12000});
db.lagou_resume_datas.insert({resumeid:5,name:'刘超杰',city:'cs',birth_day:new ISODate('1985-08-03'),expectSalary:8000});
db.lagou_resume_datas.insert({resumeid:6,name:'谢霆锋',city:'hk',birth_day:new ISODate('1980-08-01'),expectSalary:98000});
db.lagou_resume_datas.insert({resumeid:7,name:'汪涵',city:'cs',birth_day:new ISODate('1976-08-01'),expectSalary:58000});
db.lagou_resume_datas.insert({resumeid:8,name:'zhaoliying',city:'cs',birth_day:new ISODate('1987-08-01'),expectSalary:38000});
db.lagou_resume_datas.insert({resumeid:9,name:'nono',city:'cs',birth_day:new ISODate('2001-08-01'),expectSalary:10000});
```
##### 4.4.2、分片效果验证
shard1存储的数据:
```shell
[root@192 mongodb]# ./bin/mongo -port 37011
shard1:PRIMARY> use lagou_resume
switched to db lagou_resume
shard1:PRIMARY> show collections
lagou_resume_datas
shard1:PRIMARY> db.lagou_resume_datas.find();
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb679"), "resumeid" : 6, "name" : "谢霆锋", "city" : "hk", "birth_day" : ISODate("1980-08-01T00:00:00Z"), "expectSalary" : 98000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67b"), "resumeid" : 8, "name" : "zhaoliying", "city" : "cs", "birth_day" : ISODate("1987-08-01T00:00:00Z"), "expectSalary" : 38000 }
```
shard2存储的数据:
```shell
[root@192 mongodb]# ./bin/mongo -port 47011
shard2:PRIMARY> use lagou_resume
switched to db lagou_resume
shard2:PRIMARY> show tables;
lagou_resume_datas
shard2:PRIMARY> db.lagou_resume_datas.find();
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb676"), "resumeid" : 3, "name" : "wangwu", "city" : "sh", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 15000 }
```
shard3存储的数据:
```shell
[root@192 mongodb]# ./bin/mongo -port 57011
shard3:PRIMARY> use lagou_resume
switched to db lagou_resume
shard3:PRIMARY> show tables;
lagou_resume_datas
shard3:PRIMARY> db.lagou_resume_datas.find();
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb675"), "resumeid" : 2, "name" : "lisi", "city" : "gz", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 18000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb677"), "resumeid" : 4, "name" : "zhaoliu", "city" : "bj", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 12000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb678"), "resumeid" : 5, "name" : "刘超杰", "city" : "cs", "birth_day" : ISODate("1985-08-03T00:00:00Z"), "expectSalary" : 8000 }
```
shard4存储的数据:
```shell
[root@192 mongodb]# ./bin/mongo -port 58011
shard4:PRIMARY> use lagou_resume
switched to db lagou_resume
shard4:PRIMARY> show tables;
lagou_resume_datas
shard4:PRIMARY> db.lagou_resume_datas.find();
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb674"), "resumeid" : 1, "name" : "zhangsan", "city" : "cs", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 18000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67a"), "resumeid" : 7, "name" : "汪涵", "city" : "cs", "birth_day" : ISODate("1976-08-01T00:00:00Z"), "expectSalary" : 58000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67c"), "resumeid" : 9, "name" : "nono", "city" : "cs", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 10000 }
```
### 五、安全认证配置以及集群启动shell脚本
#### 5.1、创建管理员账号和普通账号
##### 5.1.1、进入路由节点创建管理员账号
MongoDB服务端开启安全检查之前,至少需要一个管理员账号,admin数据库中的用户都被视为管理员。否则其它账号不会进入安全审查。
```shell
mongos> use admin
switched to db admin
mongos> db
admin
mongos> db.createUser({
... user:"root",
... pwd:"123456",
... roles:[{role:"root",db:"admin"}]
... });
```
##### 5.1.2、创建普通账号
```shell
mongos> use lagou_resume
switched to db lagou_resume
mongos> db
lagou_resume
mongos> db.createUser({
... user:"lagou_gx",
... pwd:"abc321",
... roles:[{role:"readWrite",db:"lagou_resume"}]
... });
Successfully added user: {
"user" : "lagou_gx",
"roles" : [
{
"role" : "readWrite",
"db" : "lagou_resume"
}
]
}
```
#### 5.2、集群启动shell脚本
##### 5.2.1、编写集群启动shell脚本
再bin的同级目录编写startup.sh文件,并依次启动配置集群、分片集群、路由节点。
```sh
./bin/mongod -f config/config17011.conf
./bin/mongod -f config/config17013.conf
./bin/mongod -f config/config17015.conf
./bin/mongod -f shard/shard1/shard37011.conf
./bin/mongod -f shard/shard1/shard37013.conf
./bin/mongod -f shard/shard1/shard37015.conf
./bin/mongod -f shard/shard1/shard37017.conf
./bin/mongod -f shard/shard2/shard47011.conf
./bin/mongod -f shard/shard2/shard47013.conf
./bin/mongod -f shard/shard2/shard47015.conf
./bin/mongod -f shard/shard2/shard47017.conf
./bin/mongod -f shard/shard3/shard57011.conf
./bin/mongod -f shard/shard3/shard57013.conf
./bin/mongod -f shard/shard3/shard57015.conf
./bin/mongod -f shard/shard3/shard57017.conf
./bin/mongod -f shard/shard4/shard58011.conf
./bin/mongod -f shard/shard4/shard58013.conf
./bin/mongod -f shard/shard4/shard58015.conf
./bin/mongod -f shard/shard4/shard58017.conf
./bin/mongos -f route/route-27017.conf
```
##### 5.2.2、startup.sh执行权限
```shell
[root@192 mongodb]# chmod +x startup.sh
[root@192 mongodb]# ll
-rwx--x--x. 1 root root 774 Sep 27 13:32 startup.sh
```
#### 5.3、集群安全认证配置
##### 5.3.1、生成数字安全密匙
```shell
[root@192 mongodb]# mkdir keyfile/mongodb -p
[root@192 mongodb]# openssl rand -base64 756 > keyfile/mongodb/lagouKeyfile.file
[root@192 mongodb]# chmod 600 keyfile/mongodb/lagouKeyfile.file
```
##### 5.3.2、关闭集群所有节点
采用psmisc关闭所有mongo进程
```shell
[root@192 mongodb]# killall mongod
[root@192 mongodb]# killall mongos
```
##### 5.3.3、配置节点和分片节点开启安全认证和指定密匙文件
修改所有的配置节点和分片节点的配置。
```properties
auth=true
keyFile=keyfile/mongodb/lagouKeyfile.file
```
##### 5.3.4、配置路由节点密匙文件
修改路由节点配置。
```properties
keyFile=keyfile/mongodb/lagouKeyfile.file
```
##### 5.3.5、重启集群
```shell
./start.sh
```
##### 5.3.6、安全验证
```shell
[root@192 mongodb]# ./bin/mongo --port 27017
MongoDB shell version v4.1.3
connecting to: mongodb://127.0.0.1:27017/
Implicit session: session { "id" : UUID("9ef748fe-69f4-4f41-8ecd-708c300855c5") }
MongoDB server version: 4.1.3
mongos> use lagou_resume
switched to db lagou_resume
mongos> db
lagou_resume
mongos> show tables;
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
mongos> db.auth("lagou_gx","abc321")
1
mongos> show tables;
lagou_resume_datas
mongos> db.lagou_resume_datas.find();
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb674"), "resumeid" : 1, "name" : "zhangsan", "city" : "cs", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 18000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67a"), "resumeid" : 7, "name" : "汪涵", "city" : "cs", "birth_day" : ISODate("1976-08-01T00:00:00Z"), "expectSalary" : 58000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67c"), "resumeid" : 9, "name" : "nono", "city" : "cs", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 10000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb675"), "resumeid" : 2, "name" : "lisi", "city" : "gz", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 18000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb677"), "resumeid" : 4, "name" : "zhaoliu", "city" : "bj", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 12000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb678"), "resumeid" : 5, "name" : "刘超杰", "city" : "cs", "birth_day" : ISODate("1985-08-03T00:00:00Z"), "expectSalary" : 8000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb676"), "resumeid" : 3, "name" : "wangwu", "city" : "sh", "birth_day" : ISODate("2001-08-01T00:00:00Z"), "expectSalary" : 15000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb679"), "resumeid" : 6, "name" : "谢霆锋", "city" : "hk", "birth_day" : ISODate("1980-08-01T00:00:00Z"), "expectSalary" : 98000 }
{ "_id" : ObjectId("5f701419ecdfe62f7c8cb67b"), "resumeid" : 8, "name" : "zhaoliying", "city" : "cs", "birth_day" : ISODate("1987-08-01T00:00:00Z"), "expectSalary" : 38000 }
```
### 六、SpringBoot访问分片集群
#### 6.1、maven创建springboot工程lagou-resume-snapshot
```xml
4.0.0
com.lagou.edu
lagou-resume-snapshot
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-data-mongodb
2.2.2.RELEASE
org.springframework.boot
spring-boot-starter-test
2.2.2.RELEASE
test
org.apache.maven.plugins
maven-compiler-plugin
3.8.0
1.8
1.8
```
#### 6.2、mongodb数据库连接配置
```yaml
spring:
data:
mongodb:
host: 192.168.0.234
port: 27017
username: lagou_gx
password: abc321
database: lagou_resume
```
#### 6.3、Entity类ResumeSnapshot
```java
package com.lagou.edu.resume.snapshot.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.util.Date;
@Document("lagou_resume_datas")
public class ResumeSnapshot {
@Id
private String id;
private Long resumeid;
private String name;
private String city;
@Field("birth_day")
private Date birthday;
private double expectSalary;
@Override
public String toString() {
return "ResumeSnapshot{" +
"id='" + id + '\'' +
", resumeid='" + resumeid + '\'' +
", name='" + name + '\'' +
", city='" + city + '\'' +
", birthday=" + birthday +
", expectSalary=" + expectSalary +
'}';
}
.....getter setter.....
}
```
#### 6.4、Repository接口LagouResumeSnapshotRespository
```java
package com.lagou.edu.resume.snapshot.repository;
import com.lagou.edu.resume.snapshot.entity.ResumeSnapshot;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface LagouResumeSnapshotRepository extends MongoRepository {
/**
* 根据ResumeId查找resume
* @param resumeid
* @return
*/
ResumeSnapshot findByResumeidEquals(Long resumeid);
/**
* 删除简历
* @param resumeid
*/
void deleteByResumeidEquals(Long resumeid);
}
```
#### 6.5、SpringBoot应用入口
```java
package com.lagou.edu.resume.snapshot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class LagouResumeSnapshotApplication {
public static void main(String[] args) {
ApplicationContext context =
SpringApplication.run(LagouResumeSnapshotApplication.class,args);
}
}
```
#### 6.6、测试ResumeSnopshotTest
##### 6.6.1、保存简历快照
```java
/**
* 保存简历快照测试
*/
@Test
public void saveResume(){
ResumeSnapshot resume = new ResumeSnapshot();
resume.setResumeid(12L);
resume.setCity("tw");
resume.setName("周杰伦");
resume.setBirthday(new Date(System.currentTimeMillis()-(365*20*24*60*60*1000L)));
resume.setExpectSalary(100000);
ResumeSnapshot resumeSnapshot = resumeSnapshotRepository.save(resume);
System.out.println("After save to mongo :"+resumeSnapshot);
}
```
测试结果:
```shell
After save to mongo :ResumeSnapshot{id='5f71829cca497f59a23bc210', resumeid='12', name='周杰伦', city='tw', birthday=Tue Oct 03 14:28:44 CST 2000, expectSalary=100000.0}
```
##### 6.6.2、查询所有简历
```java
/**
* 查询所有简历快照测试
*/
@Test
public void findAll(){
List snapshotList = resumeSnapshotRepository.findAll();
snapshotList.forEach((snapshot)->{
System.out.println(snapshot);
});
}
```
测试结果:
```shell
ResumeSnapshot{id='5f701419ecdfe62f7c8cb676', resumeid='3', name='wangwu', city='sh', birthday=Wed Aug 01 08:00:00 CST 2001, expectSalary=15000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb679', resumeid='6', name='谢霆锋', city='hk', birthday=Fri Aug 01 08:00:00 CST 1980, expectSalary=98000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb67b', resumeid='8', name='zhaoliying', city='cs', birthday=Sat Aug 01 09:00:00 CDT 1987, expectSalary=38000.0}
ResumeSnapshot{id='5f71829cca497f59a23bc210', resumeid='12', name='周杰伦', city='tw', birthday=Tue Oct 03 14:28:44 CST 2000, expectSalary=100000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb675', resumeid='2', name='lisi', city='gz', birthday=Wed Aug 01 08:00:00 CST 2001, expectSalary=18000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb677', resumeid='4', name='zhaoliu', city='bj', birthday=Wed Aug 01 08:00:00 CST 2001, expectSalary=12000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb678', resumeid='5', name='刘超杰', city='cs', birthday=Sat Aug 03 08:00:00 CST 1985, expectSalary=8000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb674', resumeid='1', name='zhangsan', city='cs', birthday=Wed Aug 01 08:00:00 CST 2001, expectSalary=18000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb67a', resumeid='7', name='汪涵', city='cs', birthday=Sun Aug 01 08:00:00 CST 1976, expectSalary=58000.0}
ResumeSnapshot{id='5f701419ecdfe62f7c8cb67c', resumeid='9', name='nono', city='cs', birthday=Wed Aug 01 08:00:00 CST 2001, expectSalary=10000.0}
```
##### 6.6.3、根据Resumeid查询简历快照
```java
/**
* 根据resumeid获取简历快照测试
*/
@Test
public void getResumeByResumeid(){
Long resumeid = 12L;
ResumeSnapshot resumeSnapshot = resumeSnapshotRepository
.findByResumeidEquals(resumeid);
System.out.println(resumeSnapshot);
}
```
测试结果
```shell
ResumeSnapshot{id='5f71829cca497f59a23bc210', resumeid='12', name='周杰伦', city='tw', birthday=Tue Oct 03 14:28:44 CST 2000, expectSalary=100000.0}
```
##### 6.6.4、根据Resumeid删除简历
```java
/**
* 根据resumeid删除简历测试
*/
@Test
public void removeResumeById(){
Long resumeid = 12L;
resumeSnapshotRepository.deleteByResumeidEquals(12L);
}
```