俗话说"好记性不如烂笔头",编程的海洋如此的浩大,养成做笔记的习惯是成功的一步!
此笔记主要是ZooKeeper3.4.9版本的笔记,并且笔记都是博主自己一字一字编写和记录,有错误的地方欢迎大家指正。
一、基础知识:
1、MongoDB的名称来源于Humongous Database,中文意思就是巨大无比的数据库,顾名思义,MongoDB就是为处理大数据而生, 以解决海量数据的存储和高效查询使用为使命。是NoSQL数据库的一种,是基于文档保存数据的形式,有C++语言编写的开源数据库系统。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成,MongoDB 文档类似于 JSON 对象,有数值、字符串、布尔值、日期、数组、对象ID等类型,字段值还可以包含其他文档,数组及文档数组。
2、MongoDB通常在如下情形下考虑使用:
1)用作操作日志的记录,例如用户在网站上的操作行为记录。
2)记录的数据是比较松散,没有统一结构的形式的数据。因为MongoDB本身存储的数据是不需要有强硬的结构化。
3)大尺寸、低价值的数据,例如日志信息、大量的消息推送记录等数据。
4)高伸缩性的场景,因为MongoDB性能高,并且非常容易扩展,有着强大的集群功能。
注意:MongoDB本身不支持事务和多表(文档)的级联,故如果有此需求的场景,不应该使用MongoDB。
3、mongodb3.2.11-linux-x86_64-rhel70-3.2.11.tgz是基于Linux readHead系统的安装文件(CentOS系统也适合使用)。mongodb-linux-x86_64-2.4.9.tgz是旧版本的安装文件,留着备用。
注意:此笔记都是基于3.2.11版本来记录的。
mongodb.conf是基本的配置文件,本身压缩包是没有创建配置文件的,需要自己去创建。
jar_lib文件夹存放的是java连接MongoDB的jar包。jar包下载地址http://central.maven.org/maven2/org/mongodb/mongo-java-driver/
4、Mongodb与传统的关系型数据的术语对应关系:
RDBMS(关系型数据库管理系统) MongoDB
数据库 数据库
表格 集合
行 文档
列 字段
表联合 嵌入文档
主键 主键 (MongoDB 提供了 key 为 _id)
5、MongoDB默认的服务端口是27017,默认的数据库文档存储路径为 /data/db,默认情况下只允许本地通过127.0.0.1地址来访问,
如果允许通过其他ip地址来访问,则需要配置bind_ip=0.0.0.0,开放通过所有地址均可访问。
6、MongoDB的特性:
(1)对于单个文档,MongoDB的操作是原子性的,即操作单个文档是数据安全的。
(2)本身不支持事务,但是可以通过组合一些命令来达到简单的事务效果,但是无法实现复杂的事务情形。
可以参考官方网站的例子,通过两阶段提交来实现简单的事务效果。
地址:https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits
(3)MongoDB默认的数据库标识是自动生成的,字段名称为_id,值为ObjectId类型,并且ObjectId内部的值是唯一的。
如果在存储数据时指定了_id字段,那么将不再自定生成。存储的格式例子:
{ "_id" : ObjectId("583c6a7a9abb612322fd08c8"), "2" : true, "a" : 1 }
{ "_id" : ObjectId("583c6be49abb612322fd08c9"), "2" : true, "a" : 1 }
{ "_id" : 123, "a" : 1 }
如果手动设置ObjectId类型,长度必须要求为24位。
(4)MongoDB的shell脚本操作使用的是JavaScript脚本语言,故拥有JavaScript语言的特性,例如区分大小写,单双引号的使用,
浮点型数值精度丢失,定制JSON对象等。
7、MongoDB的集群:
1、replica set 通过副本集的方式来达到集群的效果,但是仅仅没有负载均衡的能力。由一个主节点多个从节点的形式组成,默认所以的读写操作都在主节点上(可以设置从节点拥有读的能力,但不可以设置写操作),数据会自动同步
到从节点。当主节点宕机后,会自动选取从节点升级为主节点,接替主节点的工作,故拥有容灾备份的能力,
但是因为同一时刻只有一个主节点,所以没有负载均衡的能力。
2、sharding 通过分片区的方式来达到负载均衡的效果,但是没有容灾备份的能力。将数据进行分片,由多个服务器来分别承担分片数据,通过路由计算规则来觉得存储的数据所在的分区位置,故客户端对数据的读写操作,可能分到不同的片区由不同的服务器来处理,达到了负载均衡的能力,但是如果有个别片区的服务宕机了,那么就无法提供这一片区的数据服务,没有容灾备份的能力。
3、sharding + replica set 集合分片区和副本集的特性,将其整合在一起,使得既有容灾备份的效果,又有负载均衡的能力。相当于将sharding分片区进行分组,每个分片区组都存储完整的数据,一个组就相当于一个副本集,建立多个组就相当于有多个副本集,当一个组的sharding分片区有服务器宕机时,其他组的sharding分片区服务器能马上代替其工作。
附加:主从节点的数据复制是根据oplog(operation log)操作日志来同步的,从节点读取主节点的oplog来更新自己的数据库。oplog达到指定大小时,会滚动到文件头重新记录,覆盖掉以前的操作日志,故oplog的空间不能过于小,导致从节点同步数据丢失。
8、mongodb自带有命令形式的客户端,可以通过mongo命令登录进行操作mongodb。如果需要图形界面来操作,则需要额外安装图形界面的应用来支持,或者使用图形工具软件来连接。常用的有如下几款:
MongoDBCompass(官方版):地址为 https://www.mongodb.com/try/download/compass?jmp=docs
Robo 3T(原名:Robomongo)
mongobooster
二、使用笔记:
1、最简单的形式启动服务:
解压mongodb3.2.11-linux-x86_64-rhel70-3.2.11.tgz后,进入解压后的bin目录,执行如下命令便可以简单的启动MongoDB服务:
./mongod --dbpath=/usr/user/mongodb-linux-x86_64-rhel70-3.2.11/data/db
注意:--dbpath是指定数据库路径,必须要先创建好该路径目录。
MongoDB的数据库文档默认是存储在/data/db目录下的,如果没有预先创建好该目录会启动报错。
注意是mongod命令,不是mongo命令,bin目录下有两个名字非常相近的命令,但功能是完全不同的。
附加:MongoDB关闭服务的方式:
(1)执行mongod命令来关闭 ./mongod --shutdown --dbpath=/usr/user/mongodb-linux-x86_64-rhel70-3.2.11/data/db
必须要指定好正确的db路径,因为停止服务时要移除数据库的锁标识。
(2)进入mongo的shell操作工具(执行命令./mongo 127.0.0.1:27021来进入操作工作),切换到admin数据库来停止服务。
use admin
db.shutdownServer()
(3)查询进程进行kill掉。
ps -ef|grep mongo
kill 进程号
2、进入bin目录,可以通过 ./mongod -h 来查看更多的可执行参数,"mongod命令可以使用的参数列表.txt"就是可以执行的参数列表。
3、通过指定配置文件来启动服务:
进入解压的目录,执行命令: ./bin/mongod --config mongodb.conf
其中mongodb.conf是自己创建的配置文件(注意文件路径),其中最基本的配置内容有:
#数据库路径
dbpath=/usr/local/mongodb/db
#日志路径
logpath=/usr/local/mongodb/logs/mongodb.log
#以追加方式写入日志
logappend=true
#默认的服务端口
port=27017
#后台形式运行服务,使用此形式必须要配置日志路径
fork=true
#禁用http查看界面。默认就是关闭的。
nohttpinterface=true
4、MongoDB的http查看界面,是通过web形式展现的,默认是没开启此功能的,需要配置 nohttpinterface=false
如果想让web界面提供更多的功能,需要在启动时指定 -rest参数,如: ./bin/mongod --config mongodb.conf -rest
本地启动该服务后,可以在web查看到所有的命令 http://localhost:28017/_commands
5、常用命令:
(1)普通命令:
show dbs 查看所有的数据库
use mydb 使用mydb数据库
show collections 查看当前数据库下的所有集合(表)
db 当前数据库引用,对数据库的操作都需要db开头
db.stats() 查看当前数据库的状态
db.version() 使用的MongoDB版本号。
db.getMongo() 查看当前连接数据库的地址。
db.mydb.isCapped() 查看当前集合是否固定长度的集合。
db.createCollection("mydb") 创建集合,默认创建的是非固定长度的集合。
db.createCollection("mydb",{capped:true,size:10000,max:1000}) 创建固定长度的集合,size表示集合大小,max表示文档数。
db.runCommand({"convertToCapped":"mydb",size:10000}) 将已存在的mydb集合转换为固定长度的集合。
(2)删除命令
db.dropDatabase() 删除当前数据库。
db.col_name.drop() 删除集合。col_name是集合名词。
db.collection.remove(<query>,{justOne: <boolean>,writeConcern: <number>})
query :(可选)删除的文档的条件。
justOne : (可选)如果设为 true 或 1,则只删除一个文档。默认为false,即删除所有符合条件的文档。
writeConcern :(可选)抛出异常的级别。有-1,0,1,2级别,默认级别是1,即如果写入失败则立刻返回错误。
例子:
删除mycoll集合下的所有数据。
db.mycoll.remove({})
删除标题为mongo的所有数据。
db.mycoll.remove({"title":"mongo"})
删除标题为mongo的第一条数据。
db.mycoll.remove({"title":"mongo"},true)
(3)新增命令
db.mycoll.insert({'key01':'val01','key02':'val02'})
插入数据到mycoll集合中,如果该集合不存在,则会新建一个。
db.mycoll.save({'_id':ObjectId("56064f89ade2f21f36b03136"),'key01':'val01','key02':'val02'})
保存数据。如果有_id=56064f89ade2f21f36b03136的数据,即数据已经存在,则直接进行替换,否则就插入新的数据。
(4)更新命令
db.collection.update(<query>,<update>,{upsert: <boolean>,multi: <boolean>,writeConcern: <number>})
query : update的查询条件,类似sql update查询内where后面的。如果需要更新所有数据,则直接传入{}空json对象。
update : update的对象和一些更新的操作符(如,inc...)等,也可以理解为sql update查询内set后面的
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
writeConcern :可选,抛出异常的级别。
例子:
替换title为mongo的第一条数据,注意是替换形式,既把title为mongo的记录直接就变为title:"newMongoDB",states:"ok"。
db.mycoll.update({title:"mongo"},{title:"newMongoDB",states:"ok"},false)
更新title为mongo的第一条数据,使用了$set操作符,注意不是替换,是局部更新。
db.mycoll.update({title:"mongo"},{$set:{title:"newMongoDB",states:"ok"}})
更新title为mongo的所有数据。ps:如果该数据没有states字段,那么就好新增此字段,如果有就直接更新。
db.mycoll.update({title:"mongo"},{$set:{title:"newMongoDB",states:"ok"}},false,true)
更新title为mongo的的数据,如果不存在任何的记录,则插入更新的数据。
db.mycoll.update({title:"mongo"},{$set:{title:"newMongoDB",states:"ok"}},true,false)
更新所有的数据,所有money字段的值+1,如果money字段不存在,则新增money字段,值设置为1。
db.col.update({},{$inc:{"money":1}},{multi:true})
注意:在更新数据时,对于已经存在的字段则进行更新操作,如果该数据没有更新的字段,则会新增此字段。
(5)查询命令
db.mycoll.find() 查询mycoll集合的所有文档。
db.mycoll.findOne() 查询当前mycoll集合的文档,只获取第一条数据,并美化后才输出。
db.mycoll.find().pretty() 查询mycoll集合的所有文档,并美化后才输出。
db.mycoll.find().limit(<num>) 限制条数查询。num是限制的条数,如果没输入任何数值,则默认查询全部。
db.mycoll.find().skip(<num>) 对查询结果跳过指定的条数。num是限制的条数,如果没输入任何数值,则默认不跳过任何条数。
ps:附加命令pretty、limit等命令,是可以组合在一起使用的。
db.col.find().sort({<key>:-1}) 查询结果进行排序。key是排序字段,值-1表示降序,1表升序。可以使用多个字段按顺序排序。
ps:如果数据没有该排序字段,则认为是属于最小值,降序中排在最后。
find()和findOne()都可以带条件查询,查询的条件:
AND条件: db.mycoll.find({title:"mongo",state:"ok"}) 查询title="mongo" AND state="ok"的数据。
OR条件: db.mycoll.find({$or:[{title:"mongo"},{state:"ok"}]}) 查询title="mongo" OR state="ok"的数据。
IN关键字:db.mycoll.find({_id:{$in:[1,2,3,4]}}) 查询_id为1,2,3,4中任何一个数值的数据。
等于: {<key>:<value>} db.col.find({"by":"菜鸟教程"}) 相当于where by = '菜鸟教程'
等于写法2: {<key>:{eq:\
小于: {<key>:{lt:\
小于或等于: {<key>:{lte:\
大于: {<key>:{gt:\
大于或等于: {<key>:{gte:\
不等于: {<key>:{ne:\
类型查询:{<key>:{type:\
正则表达式:{<key>:{$type:/<value>/}} db.col.find({"name":/^china/i}) 查询name名称已china开头并且不区分大小写的数据。
正则表达式写法2: db.col.find({"name":{regex:"\^china",options:"$i"}}) 查询name名称已china开头并且不区分大小写的数据。
其他例子:
查询 title="mongo" AND (state="OK" OR date=ISODate("2016-11-29T02:48:10.115Z"))的数据
db.mycoll.find({title:"mongo",$or:[{state:"ok"},{date:ISODate("2016-11-29T02:48:10.115Z")}]})
查询 (title="mongo" AND state="OK") OR (date=ISODate("2016-11-29T02:48:10.115Z"))的数据
db.mycoll.find({$or:[{title:"mongo",state:"ok"},{date:ISODate("2016-11-29T02:48:10.115Z")}]})
find()和findOne()可以指定输出的字段:
查询标题为mongo的数据,并且只显示title和falg字段值,其中_id是默认显示的。
db.mycoll.find({"title":"mongo"},{title:1,flag:1})
查询第一条数据,并且只显示title和falg字段值,_id不显示。
db.mycoll.findOne({},{_id:0,title:1,flag:1})
(6)索引命令
db.collection.ensureIndex({<key>:-1}}, <option>) 给集合创建索引。当数据量大时,必须创建索引才能加快查询速度,注意默认_id没有加入索引的。
例子:
给mycol的title字段创建升序索引,给description字段创建降序索引,相当于传统数据库的联合索引,注意字段顺序。
db.mycoll.ensureIndex({"title":1,"description":-1})
给mycol的title字段创建升序索引,并且通过后台运行的方式来创建。ps:创建索引时会阻塞其他数据库操作,可通过后台方式来防止此情况。
db.mycoll.ensureIndex({open: 1}, {background: true})
给mycol的title字段创建升序索引,后台方式运行,并且要求title是唯一索引。dropDups表示相同的title记录是否删除,默认不删除。
db.mycoll.ensureIndex({title: 1}, {background: true,unique:true,dropDups:false})
提示:如果查询的数据字段都是同一个索引的一部分,那么直接是从索引中获取查询结果,而无需再查找文档,速度将非常的快。
例如:创建索引db.users.ensureIndex({gender:1,user_name:1}) ,然后查询db.users.find({gender:"M"},{user_name:1,_id:0})。
注意:集合中索引不能超过64个,索引名的长度不能超过125个字符,一个复合索引最多可以有31个字段。可以通过explain()来查看查询是否使用了索引。
(7)聚合命令
db.collection.aggregate(<option>) 聚合操作主要用于处理数据(例如统计、计算平均值等),并返回处理结果。
例子:
根据money字段进行分组,并统计出各分组的总金额。ps:$group操作符,_id字段是必须要写的,表示分组字段。
db.mycol.aggregate({group:{_id:"money",total:{sum:"money"}}})
先用match进行数据过滤,要求金额必须大于21小于等于60,然后对其数据进行分组,统计出总数量。
注意_id:null表示所以数据合并为一个分组。此处使用了MongoDB的概念,对match操作后的数据给group进一步操作。
db.col.aggregate([{match:{money:{gt:21,lte:60}}},{group:{_id:null,count:{$sum:1}}}])
对文档数据输出进行定制。$project操作符就是修改输出的数据。只输出_id,money,flag字段的数据,
其余字段一律不输出,并且flag的数据来源于state字段,相当于给输出字段修改名称。
db.col.aggregate({project:{_id:1,money:1,flag:"state"}})
6、特殊的命令详解:
(1)insert和save的区别:
insert 是直接插入数据,如果主键已经存在,则会报_id_ dup key主键重复的异常,导致插入失败。
save 也是插入数据,但是如果主键已经存在,则是直接进行更新。
(2)save和update的区别:
save 如果数据存在,则是直接进行替换,而非局部更新。
update 如果没有指定$set操作符,则和svae功能一样,是属于直接替换。
如果使用了$set操作符,则只对指定的字段进行更新,属于局部更新,并且可以同时更新多条数据。
7、MongoDB的备份与恢复:
(1)备份操作:
mongodump -h dbhost -d dbname -o dbdirectory
-h:MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017
-d:需要备份的数据库实例,例如:test
-o:备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,
系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。
(2)恢复操作:
mongorestore -h dbhost -d dbname --directoryperdb dbdirectory
-h:MongoDB所在服务器地址
-d:需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2
--directoryperdb:备份数据所在位置,例如:c:\data\dump\test。
--drop:恢复的时候,先删除当前数据,然后恢复备份的数据。慎用!
8、MongoDB自带的监控工具:
(1)状态监测工具:
mongostat
(2)操作耗时监测工具:
mongotop <num>
<num> 是监测间隔,表示多少秒一次获取监测数据,默认1秒。
9、默认情况下,mongodb是不需要验证的,如果要开启验证,则需要在配置文件中设置并且创建账号密码,步骤如下:
(1)进入其中一个数据库(通常是使用默认的admin库):use admin
(2)创建用户:
db.createUser({user:"admin",pwd:"tcljr@*2020",roles:["root"]})
db.createUser({user:"tcljr",pwd:"tcljr@*2020",roles:["readWrite"]})
db.createUser({user:"riskmg",pwd:"tcljr@*2020",roles:[{role:"readWrite",db:"sit-riskmg"}]})
说明:如果没有指定db,则默认是使用当前数据库名的集合。如果需要给不同数据库创建用户,需要切换到不同数据库后再创建。
(3)在配置文件中,将auth=true,然后重启mongodb服务。
(4)通过moongodb的shell客户端进入 ./bin/mongo 10.0.112.35:27017
(5)切换到对应数据库,然后进行验证:
use admin
db.auth("admin","tcljr@*2020")
注意:必须要先选择数据库,如果选择的数据库不正确,即使账号密码正确都会认证失败。
说明:如果不进行验证,则是无法查看数据库和数据的,例如show dbs会不显示任何数据库。
(6)如果是有使用副本集群,如果开启了auth=true认证,则必须要配置认证文件keyFile,否则集群节点之间无法通讯。
keyFile文件可通过 openssl rand -base64 1024 > mongodb.key 来生成,生成的字符长度如果超过1024,则可以手动删除一部分。
三、java使用MongoDB的方式:
1、http://central.maven.org/maven2/org/mongodb/mongo-java-driver/
2、SpringBoot整合mongodb:
(1)增加maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
(2)配置application.yml文件:
spring:
data:
#mongodb配置(集群配置(也可以用于单机))
mongodb:
uri: mongodb://10.0.112.35:27017,10.0.112.35:27018,10.0.112.36:27017,10.0.112.36:27018,10.0.112.37:27017/riskmg
#mongodb配置(单机配置)
(3)直接注入MongoTemplate依赖即可使用:
@Resource
private MongoTemplate mongoTemplate;
/*************************************************************附加*******************************************************/
1、MongoDB 中可以使用的类型如下表所示:
类型 数字
Double 1
String 2
Object 3
Array 4
Binary data 5
Undefined 6 已废弃。
Object id 7
Boolean 8
Date 9
Null 10
Regular Expression 11
JavaScript 13
Symbol 14
JavaScript (with scope) 15
32-bit integer 16
Timestamp 17
64-bit integer 18
Min key 255 Query with -1.
Max key 127
2、原子操作常用命令
$set
用来指定一个键并更新键值,若键不存在并创建。
{ $set : { field : value } }
$unset
用来删除一个键。
{ $unset : { field : 1} }
$inc
$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
{ $inc : { field : value } }
$push
用法:
{ $push : { field : value } }
把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。
$pushAll
同$push,只是一次可以追加多个值到一个数组字段内。
{ $pushAll : { field : value_array } }
$pull
从数组field内删除一个等于value值。
{ $pull : { field : _value } }
$addToSet
增加一个值到数组内,而且只有当这个值不在数组内才增加。
$pop
删除数组的第一个或最后一个元素
{ $pop : { field : 1 } }
$rename
修改字段名称
{ $rename : { old_field_name : new_field_name } }
$bit
位操作,integer类型
{$bit : { field : {and : 5}}}
3、原子操作数据模型
考虑下面的例子,图书馆的书籍及结账信息。
实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。
book = {
_id: 123456789,
title: "MongoDB: The Definitive Guide",
author: [ "Kristina Chodorow", "Mike Dirolf" ],
published_date: ISODate("2010-09-24"),
pages: 216,
language: "English",
publisher_id: "oreilly",
available: 3,
checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
}
你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。
在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:
db.books.findAndModify ( {
query: {
_id: 123456789,
available: { $gt: 0 }
},
update: {
$inc: { available: -1 },
$push: { checkout: { by: "abc", date: new Date() } }
}
} )
4、ObjectId类型
(1)ObjectId 是一个12字节 BSON 类型数据,有以下格式:
前4个字节表示时间戳
接下来的3个字节是机器标识码
紧接的两个字节由进程id组成(PID)
最后三个字节是随机数。
(2) 手动创建ObjectId对象:myobj = new ObjectId() 或者myobj = ObjectId()
(3)ObjectId的可操作api:
ObjectId("5349b4ddd2781d08c09890f4").getTimestamp() 获取对象时间戳。
new ObjectId().str 获取对象标识的字符串格式。
5、实现_id的自增长
MongoDB的主键id不支持数值自增长的形式,可以通过编写自定义函数来实现。
//自定义增长的函数
function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
new:true //new 表示返回个性化后的文档
});
return sequenceDocument.sequence_value;
}
//使用方式
db.mycol.insert({"_id":getNextSequenceValue("productid"), "product_name":"Samsung S3","category":"mobiles"})
6、MongoDB的副本集配置:
步骤一:创建多个数据库目录。
进入/usr/user/mongodb-linux-x86_64-rhel70-3.2.11/目录,创建dbs目录,然后进入dbs目录,
创建db01、db02、db03、arb目录。
步骤二:启动MongoDB服务。
./bin/mongod --dbpath /usr/user/mongodb-linux-x86_64-rhel70-3.2.11/dbs/db01 --port 27017 --replSet myrs
./bin/mongod --dbpath /usr/user/mongodb-linux-x86_64-rhel70-3.2.11/dbs/db02 --port 27018 --replSet myrs
./bin/mongod --dbpath /usr/user/mongodb-linux-x86_64-rhel70-3.2.11/dbs/db03 --port 27019 --replSet myrs
./bin/mongod --dbpath /usr/user/mongodb-linux-x86_64-rhel70-3.2.11/dbs/arb --port 30000 --replSet myrs
步骤三:使用mongo的shell登录到其中一个服务端。
./bin/mongo 10.17.2.61:27017
步骤四:在mongo的shell中初始化副本集。
//创建配置对象。注意host主机地址切勿填写为localhost本地地址,将会导致java客户端连接出异常。
var config={_id:"myrs",members:[{_id:1,host:"10.17.2.61:27017"},{_id:2,host:"10.17.2.61:27018"},{_id:3,host:"10.17.2.61:27019"}]}
//初始化。注意只能初始化一次,mongodb会将初始化后的数据写入文件,下次重新启动服务不用再初始化。
rs.initiate(config)
注意:
rs开头表示是对replica set 副本集的操作。initiate方法只运行初始化一次。
如果想修改config配置,可以使用rs.reconfig(config:{force:true})来强制更改配置。
执行完配置后,可以通过rs.config()来看配置情况,rs.status()来查看集群状态。
步骤五:添加arbiter仲裁节点。
arbiter仲裁节点不备份数据,只是再当主服务器宕机时,有仲裁节点来选定从节点哪个变为主节点。
如果没有仲裁节点,从节点将自己从内部选取,故可以不需要仲裁节点,但要求节点数必须是奇数,如果是偶数则必须要仲裁节点。
rs.addArb("10.17.2.61:30000")
提示:如果需要动态的添加节点或删除节点,可以使用rs.add("host:port")命令来添加副本集节点,
删除从节点或者仲裁节点使用rs.remove("host:port")。
步骤六:指定一个主节点。
默认情况下,当前所以节点都是从节点,可以使用rs.status()来查看状态。
登录需要指定为主节点的mongo的shell客户端,执行命令rs.isMaster() 来提升当前节点为主节点。
提示:默认从节点是不可以做读写的,可以设置为运行从节点进行读操作,但写操作是一直都禁止的。
登录从节点的mongo的shell客户端,执行命令 rs.slaveOk(),注意只是针对当前会话的设置,
如果退出重进,需要重新执行这个命令。
步骤七:测试。
可以将主节点的进程kill掉,可以看到从节点有一个自动提升为主节点。
提升:当有节点宕机后,其他节点还是会定时的发布心跳来检测节点是否恢复,会打印大量的日志信息,需要处理好日志级别。
步骤八:java客户端连接副本集。
Builder builder = MongoClientOptions.builder();
builder.serverSelectionTimeout(3000000);
builder.requiredReplicaSetName("myrs");
builder.readConcern(readCon);
builder.writeConcern(writeCon);
MongoClientOptions op = builder.build();
/*多个副本集节点,指定多个ip地址。必须有一一列举副本集节点的ip,
*MongoClient客户端之后在指定ip的副本集读取和操作数据,如果没有指定,即使他也是副本集的一个,也不会拿取数据。
*下面的ip中,即使有一个ip的服务宕机了,也不影响操作,可以继续提供服务。
*/
List<ServerAddress> list = new ArrayList<ServerAddress>();
list.add(new ServerAddress("10.17.2.61", 27017));
list.add(new ServerAddress("10.17.2.61", 27018));
list.add(new ServerAddress("10.17.2.61", 27019));
list.add(new ServerAddress("10.17.2.61", 30000));
MongoClient client = new MongoClient(list, op);