一、mongodb应用安装
1、官网下载mongodb的社区版
https://www.mongodb.com/try/download/community
2、离线安装
将下载好的mongodb安装包上传至服务器指定目录病解压
(1)配置环境变量
export MONGO_HOME=/home/master/mongodb/mongo
export PATH=$MONGO_HOME/bin:$MONGO_HOME/sbin:$PATH
(2)测试环境
mongo --version
二、mongodb副本集部署
官方操作文档https://www.mongodb.com/docs/manual/
MongoDB中的副本集(Replica Set)是一组维护相同数据集的mongod服务。 副本集可提供冗余和高可用性,副本集能够自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
mongodb副本集类型、角色
副本集有两种类型三种角色
(1)两种类型:
主节点(Primary)类型:数据操作的主要连接点,可读写;
从节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
(2)三种角色:
主要成员(Primary):主要接收所有写操作。就是主节点。
副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操 作,但可以读操作(但需要配置)。是默认的一种从节点类型。
仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用,是非必要节点。当然也可以
将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
2、副本集架构图
(1)冗余
复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他副本,例如灾难恢复,报告或备份。
(2)复制
副本集是一组维护相同数据集的mongod实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。主节点接收所有写操作。 副本集只能有一个主要能够确认具有{w:“most”}写入关注的写入; 虽然在某些情况下,另一个mongod实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有更改即oplog。辅助(副本)节点复制主节点的oplog并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
(3)主节点选举
当主节点不与集合的其他成员通信时 对于超过配置的electionTimeoutMillis周期(默认为 10 秒),符合条件的辅助调用 选举提名自己为新的初选。群集尝试 完成新主节点的选举并恢复正常操作。副本集无法处理写入操作 直到选举成功完成。副本集可以继续 提供读取查询(如果此类查询配置为在辅助数据库上运行而 主服务器处于脱机状态。集群选择新主数据库之前的中位数时间不应 通常超过 12 秒(假设默认值)replica configuration settings.这包括所需的时间 将主数据库标记为不能利用的和 调用并完成选举. 您可以通过修改settings.electionTimeoutMillis复制配置 选择。网络延迟等因素可能会延长所需的时间 要完成副本集选举,这反过来又会影响数量 您的集群可以在没有主集群的情况下运行。这些因素是 取决于您的特定群集体系结构。降低electionTimeoutMillis默认复制配置选项(10 秒) 可以更快地检测主故障。
3、副本集配置部署
在一台机器上模拟3个节点 :
Primary)
Secondary)
Arbiter)
(1)3个节点配置文件
主节点:192.168.81.200:27017配置
# mongod.conf
storage:
dbPath: /home/master/mongodb/s1/data
journal:
enabled: true
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /home/master/mongodb/s1/log/mongod.log
processManagement:
timeZoneInfo: /usr/share/zoneinfo
fork: true
pidFilePath: /home/master/mongodb/s1/log/mongodb.pid
# network interfaces
net:
port: 27017
bindIp: 0.0.0.0
#security:
replication:
#副本集名称
replSetName: wmyrs
#sharding:
从节点:192.168.81.200:28017配置
# mongod.conf
storage:
dbPath: /home/master/mongodb/s2/data
journal:
enabled: true
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /home/master/mongodb/s2/log/mongod.log
processManagement:
timeZoneInfo: /usr/share/zoneinfo
fork: true
pidFilePath: /home/master/mongodb/s2/log/mongodb.pid
# network interfaces
net:
port: 28017
bindIp: 0.0.0.0
#security:
replication:
#副本集名称
replSetName: wmyrs
#sharding:
仲裁节点:192.168.81.200:29017配置
# mongod.conf
storage:
dbPath: /home/master/mongodb/s3/data
journal:
enabled: true
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /home/master/mongodb/s3/log/mongod.log
processManagement:
timeZoneInfo: /usr/share/zoneinfo
fork: true
pidFilePath: /home/master/mongodb/s3/log/mongodb.pid
# network interfaces
net:
port: 29017
bindIp: 0.0.0.0
#security:
replication:
#副本集名称
replSetName: wmyrs
#sharding:
(2)副本集实例启动脚本
#!/bin/bash
dir=/home/master/mongodb
ports=(27017 28017 29017)
subDir=("s1" "s2" "s3")
function sotpAndStart(){
pidStr=`netstat -tulnp | grep $1 | awk '{print $7}'`
arr1=(${pidStr//\/})
arr1_0=${arr1[0]}
arr2=(${arr1_0//$appName/})
pid=${arr2[0]}
echo "正在运行$appNmae port:$1 pid:$pid"
if [[ -z $pid ]]; then
echo "port:$1 $appName 实例挂起"
else
echo "port:$1 $appName 关闭实例"
kill $pid
fi
rm -f $2/data/mongod.lock
nohup $appName --config $2/my.conf >> $2/log/start.log 2>&1 &
netstat -tulnp | grep $1
echo "mongod...$1启动成功"
}
function start(){
for((i=0;i<3;i++));do
stopAndStart ${ports[i]} $dir/${subDir[i]}
done;
}
start
查看运行状态
ps -ef | grep mongod
(3)副本集节点设置
客户端连接mongo服务
nongo --host 192.168.81.200 --port 27017
初始化副本集
rs.initiate()
设置主节点
rs.conf()
wmyrs:SECONDARY> rs.conf()
{
"_id" : "wmyrs",
"version" : 1,
"term" : 1,
"members" : [
{
"_id" : 0,
"host" : "master:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"secondaryDelaySecs" : NumberLong(0),
"votes" : 1
}
],
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("63db7ee718a2e77c350605f4")
}
}
添加从节点
rs.add("192.168.81.200:28017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675329599, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1675329599, 1)
}
添加仲裁节点
rs.addArb("192.168.81.200:29017")
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675330868, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1675330868, 1)
}
如果添加仲裁节点失败,在主节点执行以下命令
{
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675330868, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1675330868, 1)
}
查看副本集状态
rs.status()
{
"set" : "wmyrs",
"date" : ISODate("2023-02-02T09:43:31.565Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"votingMembersCount" : 3,
"writableVotingMembersCount" : 2,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"lastCommittedWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"lastAppliedWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"lastDurableWallTime" : ISODate("2023-02-02T09:43:25.880Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1675330985, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2023-02-02T09:14:15.686Z"),
"electionTerm" : NumberLong(1),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(1675329255, 1),
"t" : NumberLong(-1)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1675329255, 1),
"t" : NumberLong(-1)
},
"numVotesNeeded" : 1,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"newTermStartDate" : ISODate("2023-02-02T09:14:15.709Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2023-02-02T09:14:15.720Z")
},
"members" : [
{
"_id" : 0,
"name" : "master:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 12641,
"optime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2023-02-02T09:43:25Z"),
"lastAppliedWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"lastDurableWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1675329255, 2),
"electionDate" : ISODate("2023-02-02T09:14:15Z"),
"configVersion" : 4,
"configTerm" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.81.200:28017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1412,
"optime" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1675331005, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2023-02-02T09:43:25Z"),
"optimeDurableDate" : ISODate("2023-02-02T09:43:25Z"),
"lastAppliedWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"lastDurableWallTime" : ISODate("2023-02-02T09:43:25.880Z"),
"lastHeartbeat" : ISODate("2023-02-02T09:43:30.904Z"),
"lastHeartbeatRecv" : ISODate("2023-02-02T09:43:30.921Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "master:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 4,
"configTerm" : 1
},
{
"_id" : 2,
"name" : "192.168.81.200:29017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 142,
"lastHeartbeat" : ISODate("2023-02-02T09:43:30.904Z"),
"lastHeartbeatRecv" : ISODate("2023-02-02T09:43:30.932Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 4,
"configTerm" : 1
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1675331005, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1675331005, 1)
}
添加从节点读权限
rs.secondaryOk()
三、spring boot 集成mongodb
添加gradle依赖
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
// testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb:2.7.8'
2、mongo副本集连接配置
@Bean
public MongoClient mongoClient() {
return MongoClients.create("mongodb://192.168.81.200:27017,192.168.81.200:28017,192.168.81.200:29017/wmy_blog?replicaSet=wmyrs");
}
@Bean
public MongoTemplate mongoTemplate(){
return new MongoTemplate(mongoClient(),"wmy_blog");
}
3、MongoTemplate操作增删改查
文档实体类
@Document("user")
public class UserDoc {
@MongoId
private String docId;
private String name;
private int age;
private String flag;
public UserDoc() {
}
public UserDoc(String name, int age, String flag) {
this.name = name;
this.age = age;
this.flag = flag;
}
public String getDocId() {
return docId;
}
}
添加文档数据
public void addUser(){
List<UserDoc> list = new ArrayList<>();
list.add(new UserDoc("LiuPing",34,"xx"));
list.add(new UserDoc("LiuCui",31,"lk"));
list.add(new UserDoc("GeJiaLi",33,"yz"));
list.add(new UserDoc("ChenYingYing",36,"xx"));
list.add(new UserDoc("YangDuan",34,"zp"));
list.add(new UserDoc("ZhangTing",33,"hb"));
list.add(new UserDoc("ZhaoYang",32,"hb"));
list.add(new UserDoc("LiQian",33,"lk"));
list.add(new UserDoc("WangWenJiao",31,"wfd"));
list.add(new UserDoc("WangWenJiao",31,"wfd"));
list.add(new UserDoc("YangWanWan",33,"ay"));
list.add(new UserDoc("ZhouYuLing",33,"sq"));
list.add(new UserDoc("PengHui",22,"xy"));
list.forEach(e->mongoTemplate.save(e));
}
查询文档数据
public List<UserDoc> basicQueryUserList(){
BasicQuery query =new BasicQuery("{\"age\":{\"$gt\":33},\"flag\":\"xx\"}");
return mongoTemplate.find(query,UserDoc.class);
}
更新文档
public void updateUser(UserDoc userDoc){
Criteria criteria = new Criteria();
criteria.and("docId").is(userDoc.getDocId());
Query query = new Query(criteria);
Update update = new Update().rename("age", "26");
mongoTemplate.updateMulti(query, update, "user");
}
删除文档
public void removeUser(UserDoc userDoc){
mongoTemplate.remove(userDoc);
}