一。 副本集介绍
之前的文章介绍了 mongodb主从 mongodb提供了另外一种 基于副本集的集群 该方式 是一主一从的升级版 一主多从,
仍然是主节点负责写入 从节点定时同步主节点数据 使用该种方式 从节点可以负责读取的操作 主节点负责写入 可以轻松实现读写分离
同时该集群方式支持自动故障转移 集群中所有节点间保持心跳 发现主节点宕机后 选举一个新的主节点
二。 副本集搭建
查看支持的三种集群参数
mongod --help
帮助中 默认的参数 dbpath都有注释 可以查看
集群帮助如下:
Master/slave options (old; use replica sets instead): 主从集群
--master master mode
--slave slave mode
--source arg when slave: specify master as
<server:port>
--only arg when slave: specify a single database
to replicate
--slavedelay arg specify delay (in seconds) to be used
when applying master ops to slave
--autoresync automatically resync if slave data is
stale
Replica set options: 副本集集群
--replSet arg arg is <setname>[/<optionalseedhostlist
>]
--replIndexPrefetch arg specify index prefetching behavior (if
secondary) [none|_id_only|all]
--enableMajorityReadConcern enables majority readConcern
Sharding options: 分片集群
--configsvr declare this is a config db of a
cluster; default port 27019; default
dir /data/configdb
--shardsvr declare this is a shard db of a
cluster; default port 27018
环境:
副本集名称 myrep
主从自动选举 192.168.58.147,192.168.58.149,192.168.58.150
分别在每台机器创建数据目录和启动
mkdir -p /data/db
mongod --port "27017" --dbpath "/data/db" --replSet "myrep"
任意一台机器 使用mongo连接进入 设置集群配置
config = { _id:"myrep", members:[
... {_id:0,host:"192.168.58.147:27017"},
... {_id:1,host:"192.168.58.149:27017"},
... {_id:2,host:"192.168.58.150:27017"}]
... }
进入admin数据库 初始化配置
use admin
rs.initiate(config);
查看状态 查询哪个是主节点 PRIMARY表示主节点 SECONDARY表示从节点"members" : [
{
"_id" : 0,
"name" : "192.168.58.147:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 113,
"optime" : {
"ts" : Timestamp(1509178311, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-10-28T08:11:51Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1509178280, 1),
"electionDate" : ISODate("2017-10-28T08:11:20Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "192.168.58.149:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 50,
"optime" : {
"ts" : Timestamp(1509178311, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1509178311, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-10-28T08:11:51Z"),
"optimeDurableDate" : ISODate("2017-10-28T08:11:51Z"),
"lastHeartbeat" : ISODate("2017-10-28T08:11:58.642Z"),
"lastHeartbeatRecv" : ISODate("2017-10-28T08:11:58.423Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "192.168.58.150:27017",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "192.168.58.150:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 50,
"optime" : {
"ts" : Timestamp(1509178311, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1509178311, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2017-10-28T08:11:51Z"),
"optimeDurableDate" : ISODate("2017-10-28T08:11:51Z"),
"lastHeartbeat" : ISODate("2017-10-28T08:11:58.648Z"),
"lastHeartbeatRecv" : ISODate("2017-10-28T08:11:58.797Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "192.168.58.147:27017",
"configVersion" : 1
}
],
"ok" : 1
主节点为147,测试数据插入
myrep:PRIMARY> use kkk
switched to db kkk
myrep:PRIMARY> db.mycol.insert(name:'zs',sex:'boy')
2017-10-28T01:19:25.629-0700 E QUERY [thread1] SyntaxError: missing ) after argument list @(shell):1:20
myrep:PRIMARY> db.mycol.insert({name:'zs',sex:'boy'})
WriteResult({ "nInserted" : 1 })
myrep:PRIMARY> show dbs
admin 0.000GB
kkk 0.000GB
local 0.000GB
test 0.000GB
myrep:PRIMARY> cd kkk
2017-10-28T01:19:49.855-0700 E QUERY [thread1] SyntaxError: missing ; before statement @(shell):1:3
myrep:PRIMARY> use kkk
switched to db kkk
myrep:PRIMARY> show tables
mycol
myrep:PRIMARY> db.mycol.find()
{ "_id" : ObjectId("59f43d9808241ee611659c95"), "name" : "zs", "sex" : "boy" }
149 mongo命令进入当前机器服务
myrep:SECONDARY> db.getMongo().setSlaveOk(); 设置可读
myrep:SECONDARY> show dbs
admin 0.000GB
kkk 0.000GB
local 0.000GB
test 0.000GB
发现kkk数据库已经被创建了 也就是正常同步数据
测试关闭147 主节点
149客户端查看集群状态
"members" : [
{
"_id" : 0,
"name" : "192.168.58.147:27017",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)", 不可达
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2017-11-01T02:42:23.164Z"),
"lastHeartbeatRecv" : ISODate("2017-11-01T02:42:01.859Z"),
"pingMs" : NumberLong(2),
"lastHeartbeatMessage" : "Connection refused",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "192.168.58.149:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 885,
"optime" : {
"ts" : Timestamp(1509179151, 4),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2017-10-28T08:25:51Z"),
"syncingTo" : "192.168.58.150:27017",
"configVersion" : 1,
"self" : true
},
{
"_id" : 2,
"name" : "192.168.58.150:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", 切换回主节点
"uptime" : 838,
"optime" : {
"ts" : Timestamp(1509179151, 4),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1509179151, 4),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2017-10-28T08:25:51Z"),
"optimeDurableDate" : ISODate("2017-10-28T08:25:51Z"),
"lastHeartbeat" : ISODate("2017-11-01T02:42:24.126Z"),
"lastHeartbeatRecv" : ISODate("2017-11-01T02:42:23.174Z"),
"pingMs" : NumberLong(1),
"electionTime" : Timestamp(1509179151, 2),
"electionDate" : ISODate("2017-10-28T08:25:51Z"),
"configVersion" : 1
}
],
"ok" : 1
150自动切换为主节点了 登录 150 后 执行删除kkk数据库操作myrep:SECONDARY> use kkk
switched to db kkk
myrep:PRIMARY> db.dropDatabase()
{ "dropped" : "kkk", "ok" : 1 }
149检查myrep:SECONDARY> show dbs
admin 0.000GB
local 0.000GB
test 0.000GB
重启 147 (注意不要用 mongod启动 带上完整参数启动)mongod --port "27017" --dbpath "/data/db" --replSet "myrep"
检查状态发现 147的数据库kkk也删除了 检查rs.status()发现 147 自动变成了从服务器三。 jdbc操作
添加maven依赖
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.2.0</version>
</dependency>
添加测试类 (代码和之前主从一致 只是需要设置 读取偏好)package mongo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.bson.Document;
import org.junit.Test;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
public class TestMongoMs {
/**
* 获取mongodb的连接
* @return
*/
public static MongoClient getClient(){
//将副本集中所有的节点都加入
List<ServerAddress> seedList=new ArrayList<ServerAddress>();
seedList.add(new ServerAddress("192.168.58.150", 27017));
seedList.add(new ServerAddress("192.168.58.147", 27017));
seedList.add(new ServerAddress("192.168.58.149", 27017));
//设置偏好为 从节点读取数据 默认是主节点读取
MongoClientOptions mco=MongoClientOptions.builder().
readPreference(ReadPreference.secondary()).build();
MongoClient mc=new MongoClient(seedList,mco);
return mc;
}
/**
* 创建集合并添加文档和document
*/
@Test
public void createCollection(){
MongoClient mc=getClient();
MongoDatabase database=mc.getDatabase("mydb");
MongoCollection<Document> mcd=database.getCollection("userInfo");
for(int i=0;i<=100;i++){
Document doc=new Document();
doc.append("name", "ls"+i);
doc.append("sex", i%2==0?"女":"男");
doc.append("age", new Random().nextInt(100));
mcd.insertOne(doc);
}
}
/**
* 查找集合下所有文档 具体根据条件参考删除
*/
@Test
public void findCollection(){
MongoClient mc=getClient();
MongoDatabase database=mc.getDatabase("mydb");
MongoCollection<Document> mcd=database.getCollection("userInfo");
FindIterable<Document> ft=mcd.find();
MongoCursor<Document> mr=ft.iterator();
while(mr.hasNext()){
Document doc=mr.next();
System.out.println(doc.get("name")+"--"+doc.get("sex"));
}
}
/**
* 更新文档
* updateOne更新找到的所有结果集中的第一条
* updateMany是更新所有结果集
*/
@Test
public void updateCollection(){
MongoClient mc=getClient();
MongoDatabase database=mc.getDatabase("mydb");
MongoCollection<Document> mcd=database.getCollection("userInfo");
Document doc=new Document();
doc.append("sex","男");
//只是找到所有sex=女 将sex改成男 其他字段不修改
mcd.updateMany(Filters.eq("sex", "女"),new Document("$set",doc));
}
/**
* 根据条件删除
*/
@Test
public void deleteCollection(){
MongoClient mc=getClient();
MongoDatabase database=mc.getDatabase("mydb");
MongoCollection<Document> mcd=database.getCollection("userInfo");
//删除满足条件找到的第一条记录
mcd.deleteOne(Filters.eq("sex", "女"));
//两个条件都满足的所有记录都删除
mcd.deleteMany(Filters.and(Filters.eq("sex", "女"),Filters.eq("name", "ls")));
}
}
主要代码在 MongoClient实例化位置 设置偏好为 读 从从服务器
设置从服务器可读 db.getMongo().setSlaveOk()
测试java结果
信息: Discovered replica set primary 192.168.58.147:27017
十一月 01, 2017 4:44:33 下午 com.mongodb.diagnostics.logging.JULLogger log
信息: Opened connection [connectionId{localValue:4, serverValue:14}] to 192.168.58.149:27017
多次测试读取都是从 从服务器