- A+
目录
1. MongoDB简介
MongoDB是由C++语言编写的一个基于分布式文件存储的开源数据库系统,它的目的在于为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库当中功能最丰富,最像关系型数据库的。它支持的数据结构非常松散,会将数据存储为一个文档,数据结构由键值对(key=>value)组成,是类似于json的bson格式,字段值可以包含其它文档、数组和文档数组,因此可以存储比较复杂的数据类型。
MongoDB最大的特点就是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系型数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
MongoDB的主要特点:
1. MongoDB提供了一个面向文档存储,操作起来比较简单和容易的非关系型数据库。
2. 你可以在MongoDB记录中设置任何属性的索引来实现更快的排序。
3. 你可以通过本地u或者网络创建数据镜像,这使得MongoDB含有更强的扩展性。
4. 如果负载的增加(需要更多的存储空间和更强的处理能力),它可以分布在计算机网络中的其它节点上,这就是所谓的分片。
5. MongoDB支持丰富的查询表达式,查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象和数组。
6. MongoDB使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段。
7. MongoDB中的Map/Reduce主要是用来对数据进行批量处理和聚合操作,Map函数调用emit(key,value)遍历集合中所有的记录,将key于value传递给Reduce函数进行处理。另外Map函数和Reduce函数是使用JavaScript编写的,所以可以通过db.runCommand和mapreduce命令来执行MapReduce操作。
8. GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
9. MongoDB允许在服务端执行脚本,可以用JavaScript编写某个函数,直接在服务端执行,也可以吧函数的定义存储在服务端,下次直接调用即可。
10. MongoDB支持各种编程语言:RUBY、PYTHON、JAVA、C++、PHP、C#等多种语言并且MongoDB的安装也非常简单。
11. MongoDB安装简单
MongoDB官网:https://www.mongodb.com/
MongoDB学习网站:http://www.runoob.com/mongodb/mongodb-tutorial.html
MongoDB下载地址:https://www.mongodb.com/download-center#community
2. MongoDB 安装部署
1. 本机系统环境
[root@linux-node1 ~]# cat /etc/redhat-release CentOS release 6.7 (Final) [root@linux-node1 ~]# /etc/init.d/iptables status iptables: Firewall is not running. [root@linux-node1 ~]# hostname -I 192.168.56.11 [root@linux-node1 ~]# hostname linux-node1
2. 上传并解压下载好的软件包
cd /usr/local/ rz mongodb-linux-x86_64-rhel62-3.4.3.tgz tar -zxf mongodb-linux-x86_64-rhel62-3.4.3.tgz #将解压后的目录重新命名为mongodb mv mongodb-linux-x86_64-rhel62-3.4.3 mongodb cd mongodb
3. 创建相关目录
mkdir /usr/local/mongodb/data #<== mongodb数据目录 mkdir /usr/local/mongodb/conf #<== mongodb配置文件目录 mkdir /usr/local/mongodb/logs #<== mongodb日志文件存放目录 mkdir /usr/local/mongodb/pid #<== 存放mongodb PID文件目录
4. 修改hosts解析文件
echo "127.0.0.1$(hostname)" >>/etc/hosts #echo "192.168.56.11 linux-node1" >>/etc/hosts #echo "192.168.56.12 linux-node2" >>/etc/hosts #echo "192.168.56.13 linux-node3" >>/etc/hosts tail -4 /etc/hosts
5. 配置enabled和defrag文件,解决MongoDB启动时警告
echo "never" > /sys/kernel/mm/transparent_hugepage/enabled echo "never" >/sys/kernel/mm/transparent_hugepage/defrag
6. 修改/etc/security/limits.conf配置文件,也是解决mangodb启动时警告
cat >>/etc/security/limits.conf <<EOF mongod softnofile 64000 mongod hardnofile 64000 mongod softnproc 32000 mongod hardnproc 32000 EOF tail -4 /etc/security/limits.conf
配置环境变量(可不做)
#vim /etc/profile cat >> /etc/profile <<EOF ulimit -f unlimited ulimit -t unlimited ulimit -v unlimited ulimit -n 64000 ulimit -m unlimited ulimit -u 64000 EOF #提示,配置完使用点火source生效
7. 配置MongoDB配置文件
[root@linux-node1 ~]# cat /usr/local/mongodb/conf/mongodb.conf #代表端口号,如果不指定则默认为27017 #port=27037 #MongoDB数据文件目录 dbpath=/usr/local/mongodb/data #以守护进程启动,即在后台运行 #fork=true #MongoDB日志文件目录 logpath=/usr/local/mongodb/logs/mongodb.log #日志文件自动累加 logappend=true #pid文件路径 pidfilepath=/usr/local/mongodb/pid/mongodb.pid #设开启简单的rest API,置后打开28017网页端口 rest=true
MongoDB命令参数说明:http://blog.csdn.net/fdipzone/article/details/7442162
8. 启动MongoDB
/usr/local/mongodb/bin/mongod --httpinterface \ --config /usr/local/mongodb/conf/mongodb.conf --fork #查看是否启动成功: netstat -lntup|grep 2*017 #说明:mongodb的默认端口是27017,它的web访问端口比它大1000为28017
9. 优化启动命令
[root@linux-node1 ~]# vim /etc/init.d/mongod #!/bin/bash # chkconfig: - 64 36 # description:mongod case $1 in start) /usr/local/mongodb/bin/mongod--maxConns 20000 --httpinterface--config /usr/local/mongodb/conf/mongodb.conf --fork ;; stop) /usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.shutdownServer()" ;; status) /usr/local/mongodb/bin/mongo 127.0.0.1:27017/admin --eval "db.stats()" ;; esac
授予执行权限
chmod +x /etc/init.d/mongod
添加进chkconfig管理
chkconfig --add mongod chkconfig mongod on chkconfig --list mongod
10. 登录MongoDB_Web界面,确认是都安装成功(http://本机IP:28017/)
- 如果你的MongoDB运行端口使用默认的27017,你可以使用端口号为28017来访问用户界面,这是因为MongoDB的Web界面访问端口比服务的端口多1000
- 设置远程访问,既开放端口27017,28018。在MongoDB的配置文件中配置(rest=true),这个配置如果在生产环境中确认完后就要将这个配置去掉,因为不安全。
页面如下:
3. MongoDB 主从同步
说明:安装配置两台MongoDB数据库,两台机器需要做时间同步
主:192.168.56.11
从:192.168.56.12
1. 配置主配置文件:
port=27017 dbpath=/usr/local/mongodb/data logpath=/usr/local/mongodb/logs/mongodb.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb.pid rest=true fork=true master=true
解释解释:
port=27017 #<== MongoDB端口 dbpath=/usr/local/mongodb/data #<== MongoDB数据存放目录 logpath=/usr/local/mongodb/logs/mongodb.log #<== 日志存放路径 logappend=true #<== 日志文件自动追加 pidfilepath=/usr/local/mongodb/pid/mongodb.pid #<== MongoDBpid文件 rest=true #<== 开启简单的rest API,可打开28017网页端口 fork=true #<== 启动MongoDB时以守护进程运行 master=true #<== 为master端
2. 配置从配置文件:
[root@linux-node2 ~]# cat /usr/local/mongodb/conf/mongodb.conf port=27017 dbpath=/usr/local/mongodb/date logpath=/usr/local/mongodb/logs/mongodb.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb.pid rest=true slave=true source=192.168.56.11:27017 autoresync=true oplogSize=2048 fork=true
参数解释:
port=27017 #<== MongoDB端口 dbpath=/usr/local/mongodb/date #<== MongoDB存放数据目录 logpath=/usr/local/mongodb/logs/mongodb.log #<== MongoDB日志文件 logappend=true #<== 日志文件自动追加 pidfilepath=/usr/local/mongodb/pid/mongodb.pid #<== MongoDB_PID文件 rest=true #<== 开启简单的rest API,可打开28017网页端口 slave=true #<== 开始slave端 source=192.168.56.11:27017 #<== 主那台MongoDB服务器同步数据 autoresync=true #<== 自动同步 oplogSize=2048 #<== 指定的复制操作日志(OPLOG)的最大大小 fork=true #<== 启动MongoDB时以守护进程运行
3. 启动
master端启动:
/usr/local/mongodb/bin/mongod --httpinterface \ --config /usr/local/mongodb/conf/mongodb.conf
slave端启动:
/usr/local/mongodb/bin/mongod --httpinterface \ --config /usr/local/mongodb/conf/mongodb.conf
4. 在slave端开启服务验证
[root@linux-node2 conf]# mongo #<== 登录MongoDB数据库 > rs.slaveOk(); #<== 开启
查看master状态
> db.runCommand({"isMaster":1}) { "ismaster" : true, "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 1000, "localTime" : ISODate("2017-04-12T04:51:51.224Z"), "maxWireVersion" : 5, "minWireVersion" : 0, "readOnly" : false, "ok" : 1 }
5. 测试
在master端写入数据:
> db.foo.save({"id":123456,"name":'zyl'}) #<== 插入数据 > db.foo.find({"id":123456}) #<== 查看
在slave端查看数据是否成功写入
> db.foo.find({"id":123456}) #<== 查看
4. MongoDB 高可用
4.1 副本集说明
实现数据库的高可用是随着我们业务不断增长的必要需求,而实现高可用架构,复制则是我们高可用的基础,那么,到底什么是复制?什么是复制集呢?当MongoDB主服务器宕机时,是通过什么来实现主从切换、故障转移的呢?下面就是实践复制集的来实现高可用的。
什么是复制,什么是复制集(副本集)?
复制:就是将一个数据库实例中所有数据库的改变复制到另一个独立的数据库实例中,改变是数据库实例复制的根本,如果没有改变,就无所谓是复制,因此在数据库哄所有的更新、插入、删除或者是改变表结构的行为都是对数据库的改变。
那么MongoDB中有哪些方案来实现主从复制呢?
其中一个方案为主从复制集群,这种结构和关系型MySQL数据库的主从复制是很相似的,在本文中3章节中配置的即是。但是当前的MongoDB版本已经不建议使用,因为这种主从的架构一旦主库出现故障,需要手工把主库切换到最可靠的从库,而其它从库就得从新的主库去同步数据。这种手工切换的方法,势必会延长了故障发生的时间,导致我们提供服务的时间收到影响。
因此我们就出现了副本集(replSet,复制集,下同),原理上也是主从复制。
副本集与主从复制的区别是主库出现故障时,能自动主从切换,从而故障得以修复,其它从库从新的主库同步数据,整个过程不需要手工干预,因此副本集就是在故障发生时,能够主从自动切换的复制,从复制本身设计的初衷来看就是避免故障的发生,减少故障对我们服务时间的影响。
一主一从节点切换:
当主节点放生宕机时,他就是自动的将从提升为主服务器,而一旦原主服务器故障恢复后,他就会继续以从的角色对外提供服务。
4.2 MondoDB高可用部署
部署三个实例的副本集:
主:192.168.56.11:27017
从:192.168.56.12:27018
从:192.168.56.13:27019
从:192.168.56.13:27020(用于测试添加删除节点)
1. 配置文件配置
192.168.56.11主配置文件:
[root@linux-node1 ~]# cat /usr/local/mongodb/conf/mongodb.conf port=27017 bind_ip=192.168.56.11 httpinterface=true dbpath=/usr/local/mongodb/data logpath=/usr/local/mongodb/logs/mongodb.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb.pid rest=true fork=true replSet=rep #<== 主要参数,复制集的名字,主从之间相互通信 #注意:在主从的配置文件中replSet的参数必须一致,参数(rep)自己定义即可
192.168.56.12从配置文件:
[root@linux-node2 ~]# cat /usr/local/mongodb/conf/mongodb.conf port=27018 bind_ip=192.168.56.12 httpinterface=true dbpath=/usr/local/mongodb/data logpath=/usr/local/mongodb/logs/mongodb.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb.pid rest=true fork=true replSet=rep
192.168.56.13从配置文件:
[root@linux-node3 ~]# cat /usr/local/mongodb/conf/mongodb.conf port=27018 bind_ip=192.168.56.13 httpinterface=true dbpath=/usr/local/mongodb/data logpath=/usr/local/mongodb/logs/mongodb.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb.pid rest=true fork=true replSet=rep
2. 启动
配置命令环境变量
echo 'PATH=/usr/local/mongodb/bin:$PATH' >>/etc/profile tail -1 /etc/profile source /etc/profile #启动命令(3台服务器都启动) mongod --config /usr/local/mongodb/conf/mongodb.conf netstat -lntup
3. 进入数据库中进行初始化
[root@linux-node1 ~]# mongo --host 192.168.56.11 --port 27017 #<== 登录数据库 > show dbs; #<== 查看当前的数据库失败,是因为复制集还没有配置好,还需要初始化 2017-04-13T11:40:26.488+0800 E QUERY [thread1] Error: listDatabases failed:{ "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 Mongo.prototype.getDBs@src/mongo/shell/mongo.js:62:1 shellHelper.show@src/mongo/shell/utils.js:761:19 shellHelper@src/mongo/shell/utils.js:651:15 @(shellhelp2):1:1 ##如下查看当前复制集状态 > rs.status() { "info" : "run rs.initiate(...) if not yet done for the set", "ok" : 0, "errmsg" : "no replset config has been received", "code" : 94, "codeName" : "NotYetInitialized" } #提示:输出提示要求运行rs.initiate进行初始化 ##在初始化之前首先定义配置文件: > cfg={"_id":"rep", ... "members":[{"_id":0,"host":"192.168.56.11:27017"}, ... {"_id":1,"host":"192.168.56.12:27018"}, ... {"_id":2,"host":"192.168.56.13:27019"}]} { "_id" : "rep", "members" : [ { "_id" : 0, "host" : "192.168.56.11:27017" }, { "_id" : 1, "host" : "192.168.56.12:27018" }, { "_id" : 2, "host" : "192.168.56.13:27019" } ] } > rs.initiate(cfg) { "ok" : 1 } rep:OTHER> #<== 这里会看到提示符发生了变化,OTHER表示正在选举主服务器 rep:PRIMARY> #<== 再按回车就会发现变成了PRIMARY,表示该服务器提升为主 rep:PRIMARY> rs.status() #<== 查看当前复制集的状态 { "set" : "rep", #<== 当前复制集的名称 "date" : ISODate("2017-04-13T05:08:47.033Z"), "myState" : 1, "term" : NumberLong(1), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "appliedOpTime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) } }, "members" : [ #<== members表示成员(一共有3个成员) { "_id" : 0, "name" : "192.168.56.11:27017", #<== 名字(主机加端口) "health" : 1, #<== 当health为1时表示运行正常 "state" : 1, #<== 当状态为1的时候说明他是主服务器 "stateStr" : "PRIMARY", #<== 主服务器的状态说明 "uptime" : 5583, "optime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-04-13T05:08:41Z"), "electionTime" : Timestamp(1492055610, 1), #<== 选举时间 "electionDate" : ISODate("2017-04-13T03:53:30Z"), #<== 选举日期 "configVersion" : 1, "self" : true #<== 当前访问的实例是否是本实例 }, { "_id" : 1, "name" : "192.168.56.12:27018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", #<== SECONDARY表示从服务器 "uptime" : 4527, "optime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-04-13T05:08:41Z"), "optimeDurableDate" : ISODate("2017-04-13T05:08:41Z"), "lastHeartbeat" : ISODate("2017-04-13T05:08:45.525Z"), "lastHeartbeatRecv" : ISODate("2017-04-13T05:08:45.707Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.56.11:27017", "configVersion" : 1 }, { "_id" : 2, "name" : "192.168.56.13:27019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 4527, "optime" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1492060121, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2017-04-13T05:08:41Z"), "optimeDurableDate" : ISODate("2017-04-13T05:08:41Z"), "lastHeartbeat" : ISODate("2017-04-13T05:08:45.736Z"), "lastHeartbeatRecv" : ISODate("2017-04-13T05:08:45.750Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.56.12:27018", "configVersion" : 1 } ], "ok" : 1 } rep:PRIMARY> #总结:首先配置replSet名字必须一样,然后进行初始化进行定义
4. 在slave端开启服务验证可以查看数据
mongo --host 192.168.56.12 --port 27018 #<== 进入MongoDB数据库开启验证 rs.slaveOk(); #<== 开启 mongo --host 192.168.56.13 --port 27019 rs.slaveOk();
5. 测试
5.1测试主从是否同步
##1.登录主数据库写入数据 [root@linux-node1 ~]# mongo --host 192.168.56.11 --port 27017 rep:PRIMARY> db.foo.save({"id":123456,"name":'zyl'}) rep:PRIMARY> db.foo.find({"id":123456}) { "_id" : ObjectId("58ef0aafd8292f121f1d1bc1"), "id" : 123456, "name" : "zyl" } ##2.在两台从服务器上进行查看 [root@linux-node2 ~]# mongo --host 192.168.56.12 --port 27018 rep:SECONDARY> db.foo.find({"id":123456}) { "_id" : ObjectId("58ef0aafd8292f121f1d1bc1"), "id" : 123456, "name" : "zyl" } [root@linux-node3 ~]# mongo --host 192.168.56.13 --port 27019 rep:SECONDARY> db.foo.find({"id":123456}) { "_id" : ObjectId("58ef0aafd8292f121f1d1bc1"), "id" : 123456, "name" : "zyl" }
5.2测试主从高可用
#1.模拟主服务器宕机 [root@linux-node1 ~]# ps -ef|grep mong root 266061 1 11:35 ? 00:03:46 mongod --config /usr/local/mongodb/conf/mongodb.conf root 270081475 0 14:53 pts/0 00:00:00 grep mong [root@linux-node1 ~]# kill 26606 #2.在从服务器上查看状态 [root@linux-node2 ~]# mongo --host 192.168.56.12 --port 27018 rep:SECONDARY> rs.status() 说明:这时会发现原来id为2的从服务器变为了主服务器,主从切换成功
4.3 扩容副本节点
说明:这里我不在增加机器,在node3节点上增加加一个实例测试,改一下端口即可,但是效果是一样的,需要注意的是数据目录,配置文件、日志、pid文件名字不要冲突
1. 创建数据目录
[root@linux-node3 ~]# mkdir /usr/local/mongodb/data4
2. 配置配置文件
[root@linux-node3 ~]# vim /usr/local/mongodb/conf/mongodb4.conf port=27020 bind_ip=192.168.56.13 httpinterface=true dbpath=/usr/local/mongodb/data4 logpath=/usr/local/mongodb/logs/mongodb4.log logappend=true pidfilepath=/usr/local/mongodb/pid/mongodb4.pid rest=true fork=true replSet=rep
3. 启动新的数据库实例
mongod --config /usr/local/mongodb/conf/mongodb4.conf netstat -lntup
4. 加入副本集:
mongo --host 192.168.56.11 --port 27017 #<== 进入mongodb数据库 rep:PRIMARY> rs.status() #<== 查看当前副本集(这时还27020没有被加入) rep:PRIMARY> rs.add("192.168.56.13:27020") #<== 添加 { "ok" : 1 } #<== 表示添加成功 rep:PRIMARY> rs.status() #<== 查看验证是否添加进来(新添加进来的id为3) #注意:新增加的节点不要忘记开启验证
4.4 摘除副本节点
登录数据库使用remove参数进行摘除
rep:PRIMARY> rs.remove("192.168.56.13:27020") #<== 括号里面的永远是放IP和端口号 { "ok" : 1 } rep:PRIMARY> rs.status() #<== 摘除后查看确认
4.5 主从手动切换
1. 登录mongodb数据库查看主从节点状态
[root@linux-node1 ~]# mongo --host 192.168.56.11 --port 27017 rep:SECONDARY> rs.status()#<== 由以上可以看出当前主服务器为92.168.56.13:27019 ...... ...... "_id" : 0, "name" : "192.168.56.11:27017", ...... "stateStr" : "SECONDARY", ...... ...... "_id" : 1, "name" : "192.168.56.12:27018", ...... "stateStr" : "SECONDARY", ...... ...... "_id" : 2, "name" : "192.168.56.13:27019", ...... "stateStr" : "PRIMARY", ...... ......
2. 登录MongoDB主服务器,将该主服务器冻结
[root@linux-node1 ~]# mongo --host 192.168.56.13 --port 27019 rep:PRIMARY> rs.freeze(40) #注意:在测试该手动时冻结该主时失败,但是对于后面的切换不影响
3. 还是在主库中降级
rep:PRIMARY> rs.stepDown(60,30) ...... ...... #说明:在线的把当前服务器进行降级,这时会发生个错误,提示我们重新连接,操作提示符也会跟着变化。必须在主服务器进行操作 rep:SECONDARY> #<== 这时的提示符已经变为从 rep:SECONDARY> rs.status() #<== 查看一下状态,发现状态已经改变
5. MongoDB复制与选举原理
5.1 复制原理
在我们使用mysql时可以启动binlog日志,来记录我们队数据库的增删改操作,而在MongoDB数据库中也是有这样的日志的,它只记录发生改变数据的操作,这就是oplog操作日志。
oplog日志相当于MySQL中binlog日志一样,只记录发生改变的记录,改变是数据库复制的本质。
1. 在数据库中进行增删改查操作
rep:PRIMARY> show dbs #<== 进入数据库后查看数据库 admin 0.000GB local 0.001GB test 0.000GB rep:PRIMARY> use zyl_db #<== 进入数据库(插入数据库后会自动生成该数据库) switched to db zyl_db rep:PRIMARY> show collections; #<== 经查勘zyl_db数据库并无数据 rep:PRIMARY> db.users.insert({"uid":1000}) #<== 往users表中插入数据(插入时自动生成) WriteResult({ "nInserted" : 1 }) rep:PRIMARY> show dbs #<== 查看当前数据库 admin 0.000GB local 0.001GB test 0.000GB zyl_db 0.000GB rep:PRIMARY> show collections; #<== 查看生成的表 users rep:PRIMARY> db.users.find() #<== 查看users表中数据 { "_id" : ObjectId("58f57a7203d0ed85e3276750"), "uid" : 1000 } #<== 查看users表数据 rep:PRIMARY> db.users.update({"uid":1000},{"uid":9999}) #<== 更改users表中数据 WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) rep:PRIMARY> db.users.find() #<== 更新后查看更新的表数据 { "_id" : ObjectId("58f5769603d0ed85e327674d"), "uid" : 9999 } rep:PRIMARY> db.users.remove({}) #<== 删除users表数据 WriteResult({ "nRemoved" : 1 })
2. 查看操作日志oplog
rep:PRIMARY> use local #<== 进入local数据库 switched to db local rep:PRIMARY> show collections; #<== 查看local数据库下的表 me oplog.rs #<== 操作日志(记录用户对数据库的增删改操作) replset.election replset.minvalid startup_log system.replset rep:PRIMARY> db.oplog.rs.find() ...... ......输出省略
oplog.rs操作日志解释说明:http://www.cnblogs.com/huangfox/p/3484497.html
5.2 选举的原理
节点类型:
1. 标准节点
2. 被动节点
3. 仲裁节点
提示:只有标准节点可能被选举为活跃节点,有选举权;被动节点有完整副本,不能成为活跃节点,有选举权;仲裁节点不复制数据,不可能成为活跃节点,只有选举权。
标准节点与被动节点区别:
priority(优先值)值高者是标准节点,低者则为被动节点,这个值是可以设置的,后面有操作实践
谁会被选举?
票数高者胜,priority是优先权0-1000值,相当于额外增加0-1000的票数。
选举结果:票数高者胜,相同票数者,数据新者胜。
1. 将27020添加进来,作为仲裁节点
rep:PRIMARY> rs.addArb("192.168.56.13:27020"); #<== 注意添加方式 rep:PRIMARY> rs.status() ...... ...... "_id" : 6, "name" : "192.168.56.13:27020", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 8, "lastHeartbeat" : ISODate("2017-04-18T07:50:05.190Z"), "lastHeartbeatRecv" : ISODate("2017-04-18T07:50:01.416Z"), "pingMs" : NumberLong(0), "configVersion" : 18 } ], "ok" : 1 }
2. 构造配置文件
#我们一共有4个实例,两个设为标准节点,一个被动节点,一个仲裁节点 rep:PRIMARY> cfg={"_id":"rep", "members":[{"_id":4,"host":"192.168.56.11:27017","priority":100}, {"_id":3,"host":"192.168.56.12:27018","priority":100}, {"_id":5,"host":"192.168.56.13:27019","priority":0}, {"_id":6,"host":"192.168.56.13:27020","arbiterOnly":true}]} { "_id" : "zyl", "members" : [ { "_id" : 0, "host" : "192.168.56.11:27017", "priority" : 100 }, { "_id" : 1, "host" : "192.168.56.12:27018", "priority" : 100 }, { "_id" : 2, "host" : "192.168.56.13:27019", "priority" : 0 }, { "_id" : 3, "host" : "192.168.56.13:27020", "arbiterOnly" : true } ] }
3.重新配置更新(因为已经初始化,所以不能再进行初始化。但是可以重新加载配置更新)
rep:PRIMARY> rs.reconfig(cfg) { "ok" : 1 } rep:PRIMARY> rs.status() rep:PRIMARY> rs.isMaster() #<== 查看mongodb架构状态 { "hosts" : [ #<== 标准节点 "192.168.56.11:27017", "192.168.56.12:27018" ], "passives" : [ #<== 被动节点 "192.168.56.13:27019" ], "arbiters" : [ #<== 仲裁节点 "192.168.56.13:27020" ], "setName" : "rep", #<== 副本集名称 "setVersion" : 19, "ismaster" : true, #<== 当前实例是否是主服务器 "secondary" : false, #<== 是否是从服务器 "primary" : "192.168.56.12:27018", #<== 该架构的主服务器 "me" : "192.168.56.12:27018", #<== 当前访问的服务器实例 "electionId" : ObjectId("7fffffff000000000000001e"), #<== 选举的ID是什么 "lastWrite" : { "opTime" : { "ts" : Timestamp(1492502019, 1), "t" : NumberLong(30) }, "lastWriteDate" : ISODate("2017-04-18T07:53:39Z") }, "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 1000, "localTime" : ISODate("2017-04-18T07:53:45.906Z"), "maxWireVersion" : 5, "minWireVersion" : 0, "readOnly" : false, "ok" : 1 }
4.测试标准节点的切换
1).将27018实例down掉。
2).查看当前副本集的状态,看那个是主库(结论是27017变为为主服务器)
3).测试两台标准节点宕机后会不会切换到被动节点?
答案是不会的,即使所有的标准节点都宕机了,被动节点也不会成为标准节点,就是说被动节点不可能成为主节点,只能是从节点
6. MongoDB复制管理
6.1 复制的管理
复制集的管理其实就是使用命令来进行管理,以下来一一介绍复制集的命令
查看帮助
rep:PRIMARY> rs.help()
rs.status() #<== 检查复制集状态
rs.initiate() #<== 当复制集配置启动之后初始化,这是默认配置
rs.initiate(cfg) #<== 定义cfg的配置文档进行初始化
rs.conf() #<== 配置完成后查看当前的配置信息
rs.reconfig(cfg) #<== 正在运行的复制集只能通过重新配置的办法进行更新
rs.add(hostportstr) #<== 在线添加复制集rs.add(“host”:port)
rs.add(membercfgobj) #<== 在线添加复制集还可以通过定义配置的方法
rs.addArb(hostportstr) #<== 添加仲裁节点rs. addArb(“host”:port)
rs.stepDown([stepdownSecs, catchUpSecs]) #<== 降级使用rs.stepDown(35,30);35意思是在35秒内本服务器不会做任何的选举,后面的30秒代表追赶时间(当主服务器需要降级时,有多个从服务器当前处于业务繁忙,并没有赶上同步主服务器的数据,我们就允许从服务器在这30秒的时间同步完主服务器数据,然后再进行主从切换)
rs.syncFrom(hostportstr) #<== 如果初始化或新添加一个新的节点进来之后,这个数据库需要重新的同步,如果我们不希望它影响主服务器或其它节点,我们可以指定一个我们想要额节点给他进行同步
rs.freeze(secs) #<== 冷冻服务器,当我们在进行服务器降级时如果不希望那台服务器被选举则可以将其冷冻多少秒内不备选举:rs.freeze(30)
rs.remove(hostportstr) #<== 删除一个复制节点
rs.slaveOk() #<== 开启复制节点同步开关
rs.printReplicationInfo() #<== 查看oplog日志的大小和时间的范围
rs.printSlaveReplicationInfo() #<== 查看从服务器是否有延时
db.isMaster() #<== 当前是否是主节点,查看当前复制集的结构
6.2 更改Oplog大小
什么时候需要更改oplog大小呢?
只有oplog大小远远不能满足频繁更新的业务需求时才会去更改oplog大小,否则很少或者根本不需要改变。
在配置复制集启动时,就应该对oplog大小有所预计,并配置比可能的合适的大小更大的配置,旧版本(3.2版本前)修改oplogSize必须重启主从数据库。
1. 查看修改前oplog属性信息
rep:PRIMARY> use local switched to db local rep:PRIMARY> db.oplog.rs.stats() { "ns" : "local.oplog.rs", "size" : 361088, "count" : 3759, "avgObjSize" : 96, "storageSize" : 151552, "capped" : true, #<== ture表示是固定集合(固定集合是可以改变大小的) "max" : -1, "maxSize" : NumberLong("2147483648"), #<== oplog大小 ...... ......
2. 修改oplog大小:
#首先查看当前oplog大小 rep:PRIMARY> rs.printReplicationInfo() configured oplog size: 2048MB log length start to end: 77267secs (21.46hrs) oplog first event time: Tue Apr 18 2017 12:44:55 GMT+0800 (CST) oplog last event time: Wed Apr 19 2017 10:12:42 GMT+0800 (CST) now: Wed Apr 19 2017 10:12:45 GMT+0800 (CST) #修改oplog大小为100MB rep:PRIMARY> db.runCommand({"convertToCapped":"oplog.rs","size":102400000}) #修改后查看 rep:PRIMARY> db.oplog.rs.stats()
#提示:当主服务器修改后oplog大小后,从服务器的oplog大小并不会改变,所以我们一次要对从服务器的oplog大小进行手动修改(还是使用以上方法即可),实际情况中很少修改
6.3 部署认证的复制
以密钥文件认证方式
1. 查看密钥认证配置
[root@linux-node1 mongodb]# pwd /usr/local/mongodb [root@linux-node1 mongodb]# ./bin/mongod --help|grep -E"auth|clusterAuthMode|keyfile" --keyFile arg #<== 用于集群验证的私钥 --clusterAuthMode arg #<== 集群认证模式(含多种认证,私钥文件、发送的密钥文件等) --auth #<== 单节点所使用的的认证模式(分片和高可用都不能用)
2. 编辑配置文件(所有节点)
[root@linux-node1 ~]# vim /usr/local/mongodb/conf/mongodb.conf ...... clusterAuthMode=keyFile keyFile=/usr/local/mongodb/date/repkey ......
3. 创建密钥文件并授权为600(所有节点)
echo "rep key">/usr/local/mongodb/date/repkey #<== 密钥文件内容保持一致,不然节点直接无法通信 chmod 600 /usr/local/mongodb/date/repkey ll /usr/local/mongodb/date/repkey #提示:如有报错可查看日志
4. 重启所有节点
5. 测试
rep:PRIMARY> rs.status() #<== 执行命令发现执行不了,因为还未对用户授权 { "ok" : 0, "errmsg" : "not authorized on admin to execute command { replSetGetStatus: 1.0 }", "code" : 13, "codeName" : "Unauthorized" } rep:SECONDARY> use admin #<== 进入admin库 switched to db admin rep:SECONDARY> db.auth("root","123456") #<== 对我们事先创建的root用户授权 1 #<== 返回1表示授权成功 #说明:这里是提前创建的超级管理用户,经测试普通用户在这里不管用 创建用户参考网址: http://www.cnblogs.com/zhoujinyi/p/4610050.html http://www.blogjava.net/anchor110/articles/385978.html #如下就可以正常使用命令 rep:SECONDARY> rs.status() { "set" : "rep", "date" : ISODate("2017-04-19T09:35:33.140Z"), ...... ......
7. MongoDB分片集群部署
7.1 分片服务器说明
MongoDB设计的理念之一就是实现分布式储存,这个分部署储存一定意义上它就是分片,MOngoDB之所以设计成分片式的存储是因为针对现在web发展的集中式的存储过于集中,随着我们业务的发展,严重的制约了我们业务的扩展能力,比如单台服务器的磁盘越来越大,它的I/O、CPU都是有限的。想充分利用这些,就是设计分布式存储服务器。
为了突破单点数据库服务器的I/O能力限制,对数据库存储进行水平扩展,严格地说,每一个服务器或者实例或者复制集就是一个分片。
分片服务器优势:
1. MongoDB提供雷士线性增长架构
2. 提高数据库可用性
3. 提高大型数据库查询服务性能(分片集群不仅能充分利用磁盘I/O资源,还能充分利用并发下的内存和CPU资源)。
什么时候需要分片?
1. 单点数据库服务器存储成为瓶颈
2. 单点数据库服务器的性能成为瓶颈
3. 大型应用分散数据以充分利用内存
如何部署分片服务器:
简单配置:
(1)一台路由服务器/实例
客户端程序连接的是路由实例,是和客户端打交道的一个接口,路由实例连接的是配置服务器
(2)一台配置服务器/实例
配置服务器他能知道后端所有分片数据的分布在哪里,当服务器是复制集的时候,如果发生主从的自动切换,他能知道去哪找主服务器,简单的说,配置服务器他知道后端所有数据的分布情况。
(3)2台shard服务器/实例
配置服务器连接的是2台分片服务器,分片服务器是用来存储数据。
7.2 部署MongoDB分片集群
部署架构图:
部署环境:
由三台服务器搭建环境
主机 |
192.168.56.11 (P) |
192.168.56.12(S) |
192.168.56.13(S) |
端口 |
主机名 |
linux-node1 |
linux-node2 |
linux-node3 |
22 |
服 务 |
mongs(路由服务) |
|
|
21017 |
config_service |
config_service |
config_service |
31017 |
|
shard1 |
shard1 |
shard1 |
47017 |
|
shard2 |
shard2 |
shard2 |
47018 |
|
shard3 |
shard3 |
shard3 |
47019 |
1.上传MongoDB_3.4.4包并解压(3台服务器均上传)
cd /usr/local/ rz mongodb_3.4.4.tar tar xf mongodb_3.4.4.tar
2.各配置文件内容如下
config_service配置文件:
cd /usr/local/mongodb/conf [root@linux-node1 conf]# cat config.conf port = 31017 dbpath = /usr/local/mongodb/data/config logpath = /usr/local/mongodb/logs/config.log logappend = true fork = true pidfilepath = /usr/local/mongodb/pid/config.pid replSet = cfg configsvr = true
集群分片shard1配置文件(shard2、shard3配置文件都相同只有端口/数据目录/pid文件不同)
[root@linux-node1 conf]# cat shard1.conf port = 47017 dbpath = /usr/local/mongodb/data/shard1 logpath = /usr/local/mongodb/logs/shard1.log replSet = shard1 logappend=true fork = true shardsvr = true pidfilepath=/usr/local/mongodb/pid/shard1.pid
路由(mongos)配置文件配置如下:
[root@linux-node1 conf]# cat mongos.conf port = 21017 configdb = cfg/192.168.56.11:31017,192.168.56.13:31017,192.168.56.13:31017 logpath = /usr/local/mongodb/logs/mongos.log logappend = true fork = true pidfilepath = /usr/local/mongodb/pid/mongos.pid #注意:这里的cfg是配置服务器复制集的名称
3. 启动config_service服务(3台都启动)然后登陆任意一台MongoDB
mongod -f /usr/local/mongodb/conf/config.conf #<== 启动 netstat -lntup|grep 31017 #<== 确认是都已经启动 mongo --port 31017 #<== 登陆任意一台配置服务器
4. 对配置服务器进行初始化创建副本集
> rs.initiate({_id:"cfg",configsvr:true, members:[{_id:0,host:"192.168.56.11:31017"}, {_id:1,host:"192.168.56.12:31017"}, {_id:2,host:"192.168.56.13:31017"}]}) ##提示:初始化后就会发现提示符变化了“cfg:OTHER>”是正在选主的状态;cfg:PRIMARY>表示为主;cfg:SECONDARY>表示为从。 cfg:PRIMARY> rs.isMaster() #<== 查看那个是主服务器 cfg:PRIMARY> rs.status() #<== 查看所有副本集的状态
5. 启动shard服务器(同时操作3台服务器)
mongod -f /usr/local/mongodb/conf/shard1.conf mongod -f /usr/local/mongodb/conf/shard2.conf mongod -f /usr/local/mongodb/conf/shard3.conf netstat -lntup|grep 4701*
6. 配置shard分片服务器进行初始化配置复制集
6.1 登录shard1其中一台Mongodb服务
##如下登录47017端口分片服务器 mongo --port 47017 ##配置初始化变量 > cfg={"_id":"shard1", "members":[{"_id":0,"host":"192.168.56.11:47017","priority":100}, {"_id":1,"host":"192.168.56.12:47017","priority":100}, {"_id":2,"host":"192.168.56.13:47017","arbiterOnly":true}]} ......... ......输出省略.. ##进行初始化 > rs.initiate(cfg) { "ok" : 1 } #<== 初始化成功 shard1:OTHER> shard1:PRIMARY> rs.status()#<== 查看副本集状态
6.2 登录shard2其中一台Mongodb服务
##如下登录47018端口分片服务器 mongo --port 47018 ##配置初始化变量 > cfg={"_id":"shard2", "members":[{"_id":0,"host":"192.168.56.11:47018","priority":100}, {"_id":1,"host":"192.168.56.12:47018","priority":100}, {"_id":2,"host":"192.168.56.13:47018","arbiterOnly":true}]} ......... ......输出省略.. ##进行初始化 > rs.initiate(cfg) { "ok" : 1 } #<== 初始化成功 shard2:OTHER> shard2:PRIMARY> rs.status() #<== 查看副本集状态
6.3 登录shard3其中一台Mongodb服务
##如下登录47019端口分片服务器 mongo --port 47019 ##配置初始化变量 > cfg={"_id":"shard3", "members":[{"_id":0,"host":"192.168.56.11:47019","priority":100}, {"_id":1,"host":"192.168.56.12:47019","priority":100}, {"_id":2,"host":"192.168.56.13:47019","arbiterOnly":true}]} ......... ......输出省略.. ##进行初始化 > rs.initiate(cfg) { "ok" : 1 } #<== 初始化成功 shard3:OTHER> shard3:PRIMARY> rs.status() #<== 查看副本集状态
7. 启动mongos(路由服务器)
mongos -f /usr/local/mongodb/conf/mongos.conf #<== 启动路由服务器 netstat -lntup|grep 21017 #<== 确认是否启动 #注意:启动路由服务时是使用的mongos
7.3. MongoDB集群添加分片
1. 登录mongodb路由服务器,查看当前分片的状态
#mongo --port 21017 #<== 登录路由服务器 mongos> show dbs #<== 查看有哪些数据库 admin 0.000GB config 0.000GB #<== 因为路由服务器连接的是配置服务器,所以这里有个config库 mongos> sh.status() #<== 查看当前分片服务器状态信息 --- Sharding Status --- sharding version: { #<== 分片版本信息 "_id" : 1, "minCompatibleVersion" : 5, "currentVersion" : 6, "clusterId" : ObjectId("5901a62239ee781e2deec97e") } shards: #<== 当前有哪些分片 active mongoses: #<== mongos版本 "3.4.4" : 1 autosplit: #<== 自动分割状态 Currently enabled: yes balancer: #<== 均衡器 Currently enabled: yes Currently running: no Balancer lock taken at Thu Apr 27 2017 16:04:51 GMT+0800 (CST) by ConfigServer:Balancer #<== 配置服务均衡器状态 Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: No recent migrations databases: #<== 参与分片的数据库
2. 添加分片:
##添加第一个集群分片 sh.addShard("shard1/192.168.56.11:47017,192.168.56.13:47017,192.168.56.13:47017") { "shardAdded" : "shard1", "ok" : 1 } ##添加分片后查看状态 mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "minCompatibleVersion" : 5, "currentVersion" : 6, "clusterId" : ObjectId("5901a62239ee781e2deec97e") } shards: { "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1 } active mongoses: "3.4.4" : 1 autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: no Balancer lock taken at Thu Apr 27 2017 16:04:51 GMT+0800 (CST) by ConfigServer:Balancer Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: No recent migrations databases: mongos> ##添加第二个分片集群 sh.addShard("shard2/192.168.56.11:47018,192.168.56.13:47018,192.168.56.13:47018") { "shardAdded" : "shard2", "ok" : 1 } mongos> sh.status() #<== 添加后查看集群状态 ##添加第三个分片集群 sh.addShard("shard3/192.168.56.11:47019,192.168.56.13:47019,192.168.56.13:47019") { "shardAdded" : "shard3", "ok" : 1 } mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "minCompatibleVersion" : 5, "currentVersion" : 6, "clusterId" : ObjectId("5901a62239ee781e2deec97e") } shards: { "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1 } { "_id" : "shard2", "host" : "shard2/192.168.56.11:47018,192.168.56.12:47018", "state" : 1 } { "_id" : "shard3", "host" : "shard3/192.168.56.11:47019,192.168.56.12:47019", "state" : 1 } active mongoses: "3.4.4" : 1 autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: no Balancer lock taken at Thu Apr 27 2017 16:04:51 GMT+0800 (CST) by ConfigServer:Balancer Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: No recent migrations databases: mongos>
注意:在添加分片集群时,当第一个添加的分片和第二个添加的分片中有相同的数据库,那么第二个分片添加的时候就会初始化失败报错,这时就必须将该分片中相同数据库删掉才可以添加成功,所以在生产环境中这些问题都应该提前去预防。
删除zyl数据库命令如下:
use zyl db.dropDatabase()
3. 在zyl数据库中插入数据
##进入zyl数据库(在mongos服务器操作即可) use zyl ##插入数据 db.user.insert({uid:"1",name:"adfs",lname:"ja22ang"}) db.user.insert({uid:"2",name:"adfs",lname:"ja22ang"}) db.user.insert({uid:"3",name:"adfs",lname:"ja22ang"}) db.user.insert({uid:"4",name:"adfs",lname:"ja22ang"}) db.user.insert({uid:"5",name:"adfs",lname:"ja22ang"}) db.user.insert({uid:"6",name:"awes",lname:"j9ng"}) db.user.insert({uid:"7",name:"asfs",lname:"j0ng"}) db.user.insert({uid:"8",name:"aqas",lname:"jaatang"}) db.user.insert({uid:"9",name:"aas",lname:"jaaa22ng"}) db.user.insert({uid:"10",name:"aees",lname:"jaa2ang"}) db.user.insert({uid:"11",name:"ars",lname:"jaaa34ng"}) db.user.insert({uid:"12",name:"aggs",lname:"jaaang"}) db.user.insert({uid:"13",name:"eeas",lname:"jaarrang"}) db.user.insert({uid:"14",name:"artys",lname:"jaaayung"}) db.user.insert({uid:"15",name:"arrts",lname:"jakjhaang"})
4. 打开数据库允许分片
mongos> use zyl mongos> db.user.find().limit(10) #<== 查看盖数据库表中前十行内容 mongos> sh.enableSharding("zyl") #<== 允许该服务器分片 { "ok" : 1 } mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "minCompatibleVersion" : 5, "currentVersion" : 6, "clusterId" : ObjectId("5901a62239ee781e2deec97e") } shards: { "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1 } { "_id" : "shard2", "host" : "shard2/192.168.56.11:47018,192.168.56.12:47018", "state" : 1 } { "_id" : "shard3", "host" : "shard3/192.168.56.11:47019,192.168.56.12:47019", "state" : 1 } active mongoses: "3.4.4" : 1 autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: no Balancer lock taken at Tue May 02 2017 09:23:22 GMT+0800 (CST) by ConfigServer:Balancer Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: No recent migrations databases: { "_id" : "zyl", "primary" : "shard3", "partitioned" : true } #<== partitioned为true表示允许分片 #提示:数据库允许分片但不意味着集合就允许分片
5. 对数据库的集合进行分片
mongos> use zyl
switched to db zyl
mongos> show collections
foo
user
##查看索引:
mongos> db.zzz.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "zyl.user"
}
]
##在以上可以看出还没有索引。所以这里我们创建索引
mongos> db.user.ensureIndex({"uid":1},{"unique":true})
##上面的索引创建成功,然后查看
mongos> db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "zyl.user"
},
{
"v" : 2,
"unique" : true,
"key" : {
"uid" : 1
},
"name" : "uid_1",
"ns" : "zyl.user"
}
]
mongos>
mongos> sh.enableSharding("zyl") #<== 开启zyl数据库分片(上面开启这里可不用开启)
{ "ok" : 1 }
mongos> sh.shardCollection("zyl.user",{"uid":1}) #<== 让user集合根据uid进行分片
{ "collectionsharded" : "zyl.user", "ok" : 1 }
mongos> sh.status() #<== 查看分片情况
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("5901a62239ee781e2deec97e")
}
shards:
{ "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1 }
{ "_id" : "shard2", "host" : "shard2/192.168.56.11:47018,192.168.56.12:47018", "state" : 1 }
{ "_id" : "shard3", "host" : "shard3/192.168.56.11:47019,192.168.56.12:47019", "state" : 1 }
active mongoses:
"3.4.4" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Balancer lock taken at Tue May 02 2017 09:23:22 GMT+0800 (CST) by ConfigServer:Balancer
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases: #<== 进行分片的数据库
{ "_id" : "zyl", "primary" : "shard3", "partitioned" : true }
zyl.user
shard key: { "uid" : 1 } #<== 片键(根据uid分片)
unique: false
balancing: true #<== 将数据均匀的分布
chunks: #<== 块儿
shard3 1 #<== 这里数据块就一个,所以均衡情况不易看出
{ "uid" : { "minKey" : 1 } } -->> { "uid" : { "maxKey" : 1 } } on : shard3 Timestamp(1, 0) #<== 表示存储到shard3片键上
mongos>
7.4 MongoDB分片集群部署总结
1.配置分片服务器
配置选项:port=47017 shardsvr=true
2.配置服务器
配置选项:port=31017 configsvr=true
3.路由服务器配置
主要参数:configdb=配置服务器复制集名称/配置服务器IP:端口
4.登录路由服务器添加分片服务器
sh.addShard("shard1/192.168.56.11:47017,192.168.56.13:47017,192.168.56.13:47017")
sh.addShard("shard2/192.168.56.11:47018,192.168.56.13:47018,192.168.56.13:47018")
sh.addShard("shard4/192.168.56.11:47019,192.168.56.13:47019,192.168.56.13:47019")
5.允许分片
打开一个数据库允许分片: sh.enableSharding("test")
在允许分片集合分片需要创建索引: db.ofo.createIndex({"uid":1})
打开一个集合是否分片: sh.shardCollection("zyl.user",{"uid":true}) <== 此命令的含义是打开zyl数据库的user集合分片,分片的依据是uid
生产环境建议:路由实例3台以上,配置实例3台以上,每个分片至少2台以上的分片服务器,每个分片服务器至少2台的副本集。
8. 片键选择
分布式环境的存储目标之一就是充分的利用各个服务器磁盘I/O的性能,我们追求的最高的目标就是能够均匀的坟山磁盘I/O性能,从这个意义上我们选择的键应该是能够均匀存储数据的字段,因此尽可能选择存储分片均匀的键。当然,必须要结合业务需求,任何脱离业务需求的架构都不是合理的。
1.登录mongos并查看分片状态
mongo --port 21017 mongos> sh.status()
2.进入数据库并插入测试数据
说明:
##进入测试库(这里时创新的数据库,无任何数据) mongos> use zyl switched to db test ##批量插入数据(插入数据较多,时间稍长) mongos> for(i=0;i<50000;i++){ db.ofo.insert({uid:i,name:'zyl',a:i+88,b:i-66}) } WriteResult({ "nInserted" : 1 }) mongos> for(i=0;i<50000;i++){ db.ofo2.insert({uid:i,name:'zyl',a:i+88,b:i-66}) } WriteResult({ "nInserted" : 1 }) mongos> for(i=0;i<50000;i++){ db.ofo3.insert({uid:i,name:'zyl',a:i+88,b:i-66}) } WriteResult({ "nInserted" : 1 }) mongos> db.ofo1.count() #<== 查看集合总文档数 mongos> show collections ofo ofo2 ofo3
3.为集合创建索引并允许test数据库以及数据库下集合分片
##为test数据库下3个集合创建索引 mongos> db.ofo1.createIndex({"uid":1}) mongos> db.ofo2.createIndex({"a":1}) mongos> db.ofo3.createIndex({"uid":1}) ##查看创建索引 mongos> db.ofo1.getIndexes() mongos> db.ofo2.getIndexes() mongos> db.ofo3.getIndexes() ##允许zyl数据库及下面集合分片 mongos> sh.enableSharding("zyl") mongos> sh.shardCollection("zyl.ofo",{"uid":1}) mongos> sh.shardCollection("zyl.ofo2",{"a":1}) mongos> sh.shardCollection("zyl.ofo3",{"uid":1}) ##查看状态 mongos> sh.status()
总结:
(1)字段的值有限
制约了业务扩展能力,理论上分片有限。。
(2)时间戳或者自动增长ID
结果:数据大多都逻辑连续和顺序地插入到一个分片上
优点:无限数量的字段值,提供无限数量的分片
缺点:单一且不可分散的热点
(3)随机片键
优点:分散热点
缺点:数据越大,性能越差
(4)结合业务的特点,组合的搜索条件就是片键
结果:高效
9. 分片管理
分片管理帮助信息:
mongos> sh.help() sh.addShard( host ) #添加分片服务器器 sh.addShardToZone(shard,zone) #增加碎片区 sh.updateZoneKeyRange(fullName,min,max,zone) #将集合的指定区域分配 sh.disableBalancing(coll) #禁用平衡在一个集合 sh.enableBalancing(coll) #重新启用一个集合的平衡 sh.enableSharding(dbname) #使用切分的数据库 sh.getBalancerState() #查看平衡器是否启用 sh.isBalancerRunning() #如果有任何人在平衡工作进展还真 sh.moveChunk(fullName,find,to) #移动块儿(当数据发现不均的时候,用的很少) sh.removeShardFromZone(shard,zone) #从区域中删除碎片 sh.removeRangeFromZone(fullName,min,max) #从给定区域移除给定集合的范围 sh.shardCollection(fullName,key,unique,options) #收集分片 sh.splitAt(fullName,middle) #通过制定的块进行分摊数据,达到数据均衡 sh.splitFind(fullName,find) #移动一定的块儿到不同的服务器中(均衡作用) sh.startBalancer() #启动平衡器,使块自动平衡 sh.status() #查看集群分片状态 sh.stopBalancer() #打印群集的一般概述 sh.disableAutoSplit() #禁用一个集合自动分割 sh.enableAutoSplit() sh.getShouldAutoSplit() #返回是否启用自动分割
9.1 查看分片服务器状态信息
[root@linux-node1 ~]# mongo --port 21017 MongoDB shell version v3.4.4 connecting to: mongodb://127.0.0.1:21017/ ...... ...... mongos> show dbs #<== 查看有那些数据库 admin 0.000GB config 0.001GB zyl 0.007GB mongos> use zyl #<== 进入zyl数据库 switched to db zyl mongos> show collections #<== 查看zyl数据库下集合 ofo1 ofo2 ofo3 mongos> db.ofo1.stats() #<== 查看集合统计信息(确定一个集合是否进行分片) mongos> sh.status() #<== 查看分片服务器状态信息
9.2 给分片添加、删除标签
1. 添加便签
mongos> sh.status() .....省略部分内容...... shards: { "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1 } { "_id" : "shard2", "host" : "shard2/192.168.56.11:47018,192.168.56.12:47018", "state" : 1 } { "_id" : "shard3", "host" : "shard3/192.168.56.11:47019,192.168.56.12:47019", "state" : 1 } .....省略部分内容...... mongos> sh.addShardTag("shard1","label_1") { "ok" : 1 } mongos> sh.addShardTag("shard1","label_11") { "ok" : 1 } #提示:能添加多个标签 mongos> sh.status() #<== 再次查看状态 .....省略部分内容...... shards: { "_id" : "shard1", "host" : "shard1/192.168.56.11:47017,192.168.56.12:47017", "state" : 1, "tags" : [ "label_1", "label_11" ] } #<== 这是为shard1添加的标签 { "_id" : "shard2", "host" : "shard2/192.168.56.11:47018,192.168.56.12:47018", "state" : 1 } { "_id" : "shard3", "host" : "shard3/192.168.56.11:47019,192.168.56.12:47019", "state" : 1 } .....省略部分内容...... #提示:标签名称自定义即可
2. 删除标签
mongos> sh.removeShardTag("shard1","label_1") { "ok" : 1 } mongos> sh.status()
提示:查看更多帮助命令 sh.help()
9.3 查看当前的实例是否进行分片
mongos> sh.getBalancerState()#<== 当前服务器是否进行分片 true mongos> sh.isBalancerRunning()#<== 当前均衡器是否在工作 false
9.4 移动特定的数据
通过查询结果将分片中数据进行分摊
mongos> sh.splitFind("zyl.ofo1",{"uid":5000}) #<== 对数据进行均衡 { "ok" : 1 } mongos> sh.status() #<== 查看
提示:查看后可能发现没有一定的效果,原因是均衡器已经均衡过了,如果最终的数据认为均衡器已经达到了合理的结果,那么最终的结果执行了sh.splitFind()是没效果的。
9.5 添加/删除分片
1.添加分片
sh.addShard("shard1/192.168.56.11:47017,192.168.56.13:47017,192.168.56.13:47017")
2.删除分片
use admin db.runCommand({"removeshard":"shard1"})
9.6 config服务器集合有哪些
[root@linux-node3 ~]# mongo --port 31017 cfg:PRIMARY> show dbs admin 0.000GB config 0.001GB local 0.004GB cfg:PRIMARY> use config switched to db config cfg:PRIMARY> show collections actionlog changelog chunks #<== 让config服务器得知数据存储在那个分片上 collections #<== 当前启用分片的所有集合 databases #<== 分片服务器中有哪些数据库 lockpings locks migrations mongos #<== 告诉我们配置服务器能够识别的mongos有哪些 shards #<= 添加的分片 tags version
配置服务器能够知道后端分片服务器分布情况,那么它是怎么知道的呢?
cfg:PRIMARY> db.chunks.findOne() { "_id" : "zyl.ofo1-uid_MinKey", #<== 集合名以及分片的片键和片的范围作为ID "lastmod" : Timestamp(1, 1), #<== 上次修改的时间 "lastmodEpoch" : ObjectId("590980b42676897469f2ae4e"), #<== 上次修改的ID值 "ns" : "zyl.ofo1", #<== 命名空间 "min" : { "uid" : { "$minKey" : 1 } }, "max" : { "uid" : 25000 }, "shard" : "shard1" #<== 最大值到最小值保存的分片 } #由此。config服务器能知道后端服务器所有存储的情况
查看当前启用分片的所有集合
cfg:PRIMARY> db.collections.find() { "_id" : "zyl.user", "lastmodEpoch" : ObjectId("000000000000000000000000"), "lastmod" : ISODate("2017-05-03T02:58:06.086Z"), "dropped" : true } { "_id" : "zyl.user2", "lastmodEpoch" : ObjectId("000000000000000000000000"), "lastmod" : ISODate("2017-05-03T02:58:06.150Z"), "dropped" : true } { "_id" : "zyl.ofo", "lastmodEpoch" : ObjectId("000000000000000000000000"), "lastmod" : ISODate("2017-05-03T03:42:35.902Z"), "dropped" : true } { "_id" : "zyl.ofo2", "lastmodEpoch" : ObjectId("590982632676897469f2ae73"), "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : { "a" : 1 }, "unique" : false } { "_id" : "zyl.ofo3", "lastmodEpoch" : ObjectId("000000000000000000000000"), "lastmod" : ISODate("2017-05-03T03:42:41.067Z"), "dropped" : true } { "_id" : "zyl.ofo1", "lastmodEpoch" : ObjectId("590980b42676897469f2ae4e"), "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : { "uid" : 1 }, "unique" : false } cfg:PRIMARY>
查看分片服务器中有哪些数据库
cfg:PRIMARY> db.databases.find() { "_id" : "zyl", "primary" : "shard1", "partitioned" : true }
查看存储的mongos信息,这就是为什么当其中一台mongos宕机时能够找到其中一台mongos
cfg:PRIMARY> db.databases.find() { "_id" : "zyl", "primary" : "shard1", "partitioned" : true } cfg:PRIMARY> db.mongos.find() { "_id" : "linux-node1:21017", "ping" : ISODate("2017-05-05T03:42:56.569Z"), "up" : NumberLong(72091), "waiting" : true, "mongoVersion" : "3.4.4" } { "_id" : "linux-node3:21017", "ping" : ISODate("2017-05-05T03:42:56.636Z"), "up" : NumberLong(72122), "waiting" : true, "mongoVersion" : "3.4.4" } { "_id" : "linux-node2:21017", "ping" : ISODate("2017-05-05T03:42:49.266Z"), "up" : NumberLong(72108), "waiting" : true, "mongoVersion" : "3.4.4" }