前言
MongoDB是一个由C++语言编写的基于分布式文件存储的数据库,是当前NoSQL数据库中比较热门的一种,旨在为Web应用提供可扩展的高性能数据存储解决方案。本文介绍MongoDB复制集及数据分片。
MongoDB
简介
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。支持的数据结构非常松散,因此可以存储比较复杂的数据类型。最大的特点是其支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
特点及功能特性
特点:高性能、易部署、易使用,存储数据非常方便
主要功能特性有:
面向集合存储,易存储对象类型的数据
模式自由
支持动态查询
支持完全索引,包含内部对象
支持查询
支持复制和故障恢复
使用高效的二进制数据存储,包括大型对象(如视频等)
自动处理碎片,以支持云计算层次的扩展性
支持Ruby,Python,Java,C++,PHP等多种语言
文件存储格式为Bson(一种Json的扩展)
可通过网络访问
优缺点
与关系型数据库相比,MongoDB的优点:
弱一致性(最终一致),更能保证用户的访问速度
文档结构的存储方式,能够更便捷的获取数据
内置GridFS,支持大容量的存储
内置Sharding
第三方支持丰富(这是与其他的NoSQL相比,MongoDB也具有的优势)
性能优越
与关系型数据库相比,MongoDB的缺点:
不支持事务操作
占用空间过大
没有成熟的维护工具
MongoDB复制集
复制集
工作特性:
至少三个,且应该为奇数个节点,可使用arbiter(仲裁者)来参与选举
复制集可实现失效自动转移(通过选举方式实现)
复制集的中特殊类型的节点:
0优先级的节点:冷备节点,不会被选举成为主节点,但可以参与选举
被隐藏的从节点:首先是一个0优先级的从节点,且对客户端不可见
延迟复制的从节点:首先是一个0优先级的从节点,且复制时间落后于主节点一个固定时长
arbiter: 仲裁者
复制集架构
实验拓扑
1
2
|
#系统环境:CentOS6.6
#各节点时间已同步
|
配置过程
安装所需软件
1
2
3
4
5
6
7
|
[root@node1 ~]
# cd mongodb/
[root@node1 mongodb]
# ls
mongodb-org-server-2.6.10-1.x86_64.rpm mongodb-org-tools-2.6.10-1.x86_64.rpm
mongodb-org-shell-2.6.10-1.x86_64.rpm
[root@node1 mongodb]
# yum install *.rpm -y #3个包都安装
#所有节点都执行以上安装操作
|
编辑配置文件
1
2
3
4
5
6
7
8
9
10
11
12
|
[root@node1 ~]
# vim /etc/mongod.conf
logpath=
/var/log/mongodb/mongod
.log
logappend=
true
fork=
true
dbpath=
/mongodb/data
#数据位置
pidfilepath=
/var/run/mongodb/mongod
.pid
#bind_ip=127.0.0.1 #默认监听本机,注释掉监听所有
httpinterface=
true
#开放web
rest=
true
replSet=testSet
#复制集名,可自定义
replIndexPrefetch=_id_only
|
同步配置文件至各节点
1
2
3
4
5
6
|
[root@node1 ~]
# scp /etc/mongod.conf node3:/etc
root@node3's password:
mongod.conf 100% 1567 1.5KB
/s
00:00
[root@node1 ~]
# scp /etc/mongod.conf node4:/etc
root@node4's password:
mongod.conf 100% 1567 1.5KB
/s
00:00
|
创建数据目录
1
2
3
4
5
6
|
[root@node1 ~]
# mkdir /mongodb/data -pv
mkdir
: created directory `
/mongodb
'
mkdir
: created directory `
/mongodb/data
'
[root@node1 ~]
# chown -R mongod.mongod /mongodb
#各节点都执行以上操作
|
启动服务
1
2
3
4
5
6
|
[root@node1 ~]
# service mongod start
Starting mongod: [ OK ]
[root@node1 mongodb]
# ss -tnl | grep 27017
LISTEN 0 128 *:27017 *:*
#各节点启动服务,启动过程中需要初始化数据,故启动较慢
|
连接数据库做初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
[root@node1 ~]
# mongo
MongoDB shell version: 2.6.10
connecting to:
test
Welcome to the MongoDB shell.
For interactive help,
type
"help"
.
For
more
comprehensive documentation, see
http:
//docs
.mongodb.org/
Questions? Try the support group
http:
//groups
.google.com
/group/mongodb-user
> rs.initiate()
{
"info2"
:
"no configuration explicitly specified -- making one"
,
"me"
:
"node1.scholar.com:27017"
,
"info"
:
"Config now saved locally. Should come online in about a minute."
,
"ok"
: 1
}
#初始化成功,查看状态信息
> rs.status()
{
"set"
:
"testSet"
,
"date"
: ISODate(
"2015-07-13T12:33:27Z"
),
"myState"
: 1,
"members"
: [
{
"_id"
: 0,
"name"
:
"node1.scholar.com:27017"
,
"health"
: 1,
"state"
: 1,
"stateStr"
:
"PRIMARY"
,
"uptime"
: 1111,
"optime"
: Timestamp(1436790736, 1),
"optimeDate"
: ISODate(
"2015-07-13T12:32:16Z"
),
"electionTime"
: Timestamp(1436790737, 1),
"electionDate"
: ISODate(
"2015-07-13T12:32:17Z"
),
"self"
:
true
}
],
"ok"
: 1
}
testSet:PRIMARY>
#已成为主节点
|
添加节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
testSet:PRIMARY> rs.add(
"172.16.10.125"
)
{
"ok"
: 1 }
testSet:PRIMARY> rs.add(
"172.16.10.126"
)
{
"ok"
: 1 }
#查看各节点状态
testSet:PRIMARY> rs.status()
{
"set"
:
"testSet"
,
"date"
: ISODate(
"2015-07-13T12:41:07Z"
),
"myState"
: 1,
"members"
: [
{
"_id"
: 0,
"name"
:
"node1.scholar.com:27017"
,
"health"
: 1,
"state"
: 1,
"stateStr"
:
"PRIMARY"
,
"uptime"
: 1571,
"optime"
: Timestamp(1436791178, 1),
"optimeDate"
: ISODate(
"2015-07-13T12:39:38Z"
),
"electionTime"
: Timestamp(1436790737, 1),
"electionDate"
: ISODate(
"2015-07-13T12:32:17Z"
),
"self"
:
true
},
{
"_id"
: 1,
"name"
:
"172.16.10.125:27017"
,
"health"
: 1,
"state"
: 2,
"stateStr"
:
"SECONDARY"
,
"uptime"
: 98,
"optime"
: Timestamp(1436791178, 1),
"optimeDate"
: ISODate(
"2015-07-13T12:39:38Z"
),
"lastHeartbeat"
: ISODate(
"2015-07-13T12:41:06Z"
),
"lastHeartbeatRecv"
: ISODate(
"2015-07-13T12:41:05Z"
),
"pingMs"
: 1,
"syncingTo"
:
"node1.scholar.com:27017"
},
{
"_id"
: 2,
"name"
:
"172.16.10.126:27017"
,
"health"
: 1,
"state"
: 2,
"stateStr"
:
"SECONDARY"
,
"uptime"
: 89,
"optime"
: Timestamp(1436791178, 1),
"optimeDate"
: ISODate(
"2015-07-13T12:39:38Z"
),
"lastHeartbeat"
: ISODate(
"2015-07-13T12:41:06Z"
),
"lastHeartbeatRecv"
: ISODate(
"2015-07-13T12:41:06Z"
),
"pingMs"
: 1,
"syncingTo"
:
"node1.scholar.com:27017"
}
],
"ok"
: 1
}
|
创建数据,验证是否同步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#主节点
testSet:PRIMARY> use testdb
switched to db testdb
testSet:PRIMARY> db.students.insert({name:
"ZhangSan"
,age:
"21"
})
WriteResult({
"nInserted"
: 1 })
#从节点
testSet:SECONDARY> rs.slaveOk()
#每个从节点首先申明从节点准备完毕才可同步
testSet:SECONDARY> use testdb
switched to db testdb
testSet:SECONDARY> show collections
students
system.indexes
testSet:SECONDARY> db.students.findOne()
{
"_id"
: ObjectId(
"55a3b494ebcafd9edbdfce4d"
),
"name"
:
"ZhangSan"
,
"age"
:
"21"
}
#验证从节点是否可写
testSet:SECONDARY> db.classes.insert({class:
"2"
,numstu:
"50"
})
WriteResult({
"writeError"
: {
"code"
: undefined,
"errmsg"
:
"not master"
} })
#由此可见,只有主节点才可写
|
以上便是复制集的相关配置,如果主节点故障,从节点会自动选举出新的主节点,这里就不再演示
数据分片
分片缘由
分片(sharding)是MongoDB用来将大型集合分割到不同服务器(集群)上所采用的方法。当单台服务器CPU,Memory,IO等无法满足需求,就需要将数据分片存放,减缓服务器压力。
分片架构
实验拓扑
配置过程
因为以上做过实验我们首先来清理一下数据
1
2
3
4
5
|
[root@node1 ~]
# service mongod stop
Stopping mongod: [ OK ]
[root@node1 ~]
# rm -rf /mongodb/data/*
#各节点都执行以上操作,若第一次做可忽略
|
Config Server配置
1
2
3
4
5
|
#安装所需包
[root@node2 mongodb]
# ls
mongodb-org-server-2.6.10-1.x86_64.rpm mongodb-org-tools-2.6.10-1.x86_64.rpm
mongodb-org-shell-2.6.10-1.x86_64.rpm
[root@node2 mongodb]
# yum install *.rpm -y
|
修改配置文件
1
2
3
4
5
6
7
8
9
10
11
|
[root@node2 ~]
# vim /etc//mongod.conf
logpath=
/var/log/mongodb/mongod
.log
logappend=
true
fork=
true
dbpath=
/mongodb/data
configsvr=
true
#开启config server
pidfilepath=
/var/run/mongodb/mongod
.pid
#bind_ip=127.0.0.1
httpinterface=
true
rest=
true
|
创建数据目录
1
2
3
4
|
[root@node2 ~]
# mkdir /mongodb/data -pv
mkdir
: created directory `
/mongodb
'
mkdir
: created directory `
/mongodb/data
'
[root@node2 ~]
# chown -R mongod.mongod /mongodb
|
启动服务
1
2
3
4
5
6
|
[root@node2 ~]
# service mongod start
Starting mongod: [ OK ]
[root@node2 ~]
# ss -tnl | grep 27019
LISTEN 0 128 *:27019 *:*
#监听端口已发生改变,不再是27017
|
Mongos配置
1
2
|
#安装所需包,Mongos节点只装此包即可,无需装第一次实验中的mongod的相关包
[root@node1 ~]
# yum install mongodb-org-mongos-2.6.10-1.x86_64.rpm -y
|
启动服务
1
2
3
4
5
6
7
8
|
[root@node1 ~]
# mongos --configdb=172.16.10.124 --fork --logpath=/var/log/mongodb/mongos.log
2015-07-13T22:22:47.404+0800 warning: running with 1 config server should be
done
only fo
r testing purposes and is not recommended
for
production
about to fork child process, waiting
until
server is ready
for
connections.
forked process: 3583
child process started successfully, parent exiting
#--configdb指定config server --logpath指定日志位置 --fork后台运行
|
Shard配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#以为我们第一次实验安装过软件了,下面直接修改配置文件
[root@node3 ~]
# vim /etc/mongod.conf
logpath=
/var/log/mongodb/mongod
.log
logappend=
true
fork=
true
dbpath=
/mongodb/data
pidfilepath=
/var/run/mongodb/mongod
.pid
#bind_ip=127.0.0.1
httpinterface=
true
rest=
true
[root@node3 ~]
# service mongod start
Starting mongod: [ OK ]
#两个shard节点都执行以上操作
|
Mongos节点添加Shard节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[root@node1 ~]
# mongo --host 172.16.10.123
MongoDB shell version: 2.6.10
connecting to: 172.16.10.123:27017
/test
mongos> sh.addShard(
"172.16.10.125"
)
{
"shardAdded"
:
"shard0000"
,
"ok"
: 1 }
mongos> sh.addShard(
"172.16.10.126"
)
{
"shardAdded"
:
"shard0001"
,
"ok"
: 1 }
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id"
: 1,
"version"
: 4,
"minCompatibleVersion"
: 4,
"currentVersion"
: 5,
"clusterId"
: ObjectId(
"55a3c9ba131b83ff44e19435"
)
}
shards:
{
"_id"
:
"shard0000"
,
"host"
:
"172.16.10.125:27017"
}
{
"_id"
:
"shard0001"
,
"host"
:
"172.16.10.126:27017"
}
databases:
{
"_id"
:
"admin"
,
"partitioned"
:
false
,
"primary"
:
"config"
}
|
对所需对象启用分片功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#对数据库启用sharding功能
mongos> sh.enableSharding(
"testdb"
)
{
"ok"
: 1 }
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id"
: 1,
"version"
: 4,
"minCompatibleVersion"
: 4,
"currentVersion"
: 5,
"clusterId"
: ObjectId(
"55a3c9ba131b83ff44e19435"
)
}
shards:
{
"_id"
:
"shard0000"
,
"host"
:
"172.16.10.125:27017"
}
{
"_id"
:
"shard0001"
,
"host"
:
"172.16.10.126:27017"
}
databases:
{
"_id"
:
"admin"
,
"partitioned"
:
false
,
"primary"
:
"config"
}
{
"_id"
:
"test"
,
"partitioned"
:
false
,
"primary"
:
"shard0000"
}
{
"_id"
:
"testdb"
,
"partitioned"
:
true
,
"primary"
:
"shard0000"
}
#指定需要分片的Collection及索引
mongos> sh.shardCollection(
"testdb.students"
,{
"age"
: 1})
{
"collectionsharded"
:
"testdb.students"
,
"ok"
: 1 }
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id"
: 1,
"version"
: 4,
"minCompatibleVersion"
: 4,
"currentVersion"
: 5,
"clusterId"
: ObjectId(
"55a3c9ba131b83ff44e19435"
)
}
shards:
{
"_id"
:
"shard0000"
,
"host"
:
"172.16.10.125:27017"
}
{
"_id"
:
"shard0001"
,
"host"
:
"172.16.10.126:27017"
}
databases:
{
"_id"
:
"admin"
,
"partitioned"
:
false
,
"primary"
:
"config"
}
{
"_id"
:
"test"
,
"partitioned"
:
false
,
"primary"
:
"shard0000"
}
{
"_id"
:
"testdb"
,
"partitioned"
:
true
,
"primary"
:
"shard0000"
}
testdb.students
shard key: {
"age"
: 1 }
chunks:
shard0000 1
{
"age"
: {
"$minKey"
: 1 } } -->> {
"age"
: {
"$maxKey"
: 1 } }
on : shard0000 Timestamp(1, 0)
|
分片功能已开启,接下来我们手动创建数据来验证是否会分片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
mongos> use testdb
switched to db testdb
mongos>
for
(i=1;i<=100000;i++) db.students.insert({name:
"student"
+i,age:(i%120),address:
"China"
})
WriteResult({
"nInserted"
: 1 })
mongos> db.students.
find
().count()
100000
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id"
: 1,
"version"
: 4,
"minCompatibleVersion"
: 4,
"currentVersion"
: 5,
"clusterId"
: ObjectId(
"55a3c9ba131b83ff44e19435"
)
}
shards:
{
"_id"
:
"shard0000"
,
"host"
:
"172.16.10.125:27017"
}
{
"_id"
:
"shard0001"
,
"host"
:
"172.16.10.126:27017"
}
databases:
{
"_id"
:
"admin"
,
"partitioned"
:
false
,
"primary"
:
"config"
}
{
"_id"
:
"test"
,
"partitioned"
:
false
,
"primary"
:
"shard0000"
}
{
"_id"
:
"testdb"
,
"partitioned"
:
true
,
"primary"
:
"shard0000"
}
testdb.students
shard key: {
"age"
: 1 }
chunks:
shard0001 1
shard0000 2
{
"age"
: {
"$minKey"
: 1 } } -->> {
"age"
: 1 } on : shard0001 Timestamp(2, 0)
{
"age"
: 1 } -->> {
"age"
: 119 } on : shard0000 Timestamp(2, 2)
{
"age"
: 119 } -->> {
"age"
: {
"$maxKey"
: 1 } } on : shard0000 Timestamp(2, 3)
|
查看数据状态会发现数据已被分到不同shard上,至此,数据分片成功实现
The end
MongoDB复制集及数据分片就先说到这里了,通过以上简单应用可以看出,MongoDB在大数据处理方面比关系型数据库略胜一筹,但由于MongoDB目前还处在发展阶段,在实际生产环境中还有许多问题有待解决,不过相信在未来MongoDB会更加出色。以上仅为个人学习整理,如有错漏,大神勿喷~~~
本文转自 北城书生 51CTO博客,原文链接:http://blog.51cto.com/scholar/1673939