1. MongoDB概述
1.1 序言
MongoDB 是一个可扩展的高性能,开源,模式自由,面向文档的数据库。 它使用 C++编写。MongoDB 包含以下特点:
- 面向集合的存储:适合存储对象及JSON形式的数据。
- 动态查询:Mongo 支持丰富的查询方式,查询指令使用 JSON 形式的标记,可轻易查询文档中内嵌的对象及数组。
- 完整的索引支持:包括文档内嵌对象及数组。Mongo 的查询优化器会分析查询表达式,并生成一个高效的查询计划。
- 查询监视:Mongo包含一个监控工具用于分析数据库操作性能。
- 复制及自动故障转移:Mongo 数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目的是提供冗余及自动故障转移。
- 高效的传统存储方式:支持二进制数据及大型对象(如:照片或图片)。
- 自动分片以支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器。
1.2 背景
MongoDB 的主要目标是在键值对存储方式(提供了高性能和高度伸缩性) 以及传统的 RDBMS(关系性数据库)系统,集两者的优势于一身。Mongo 适用于以下场景:
- 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
- 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由 Mongo 搭建的持久化缓存可以避免下层的数据源过载。
- 大尺寸,低价值的数据:使用传统的关系数据库存储一些数据时可能会比较贵,在此之前,很多程序员往往会选择传统的文件进行存储。
- 高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库
- 用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档格式化的存储及查询。
当然 MongDB 也有不适合的场景:
- 高度事务性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复制事物的应用程序。
- 传统的商业智能应用:针对特定问题的 BI 数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能时更适合的选择(如Hadoop套件中的Hive)。
- 需要SQL的问题。
2.Sharding cluster介绍
这是一种可以水平扩展的模式,在数据量很大时特给力,实际大规模应用一般会采用这种架构去构建monodb系统。
要构建一个 MongoDB Sharding Cluster,需要三种角色:
-
Shard Server: mongod 实例,用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个relica set承担,防止主机单点故障
-
Config Server: mongod 实例,存储了整个 Cluster Metadata,其中包括 chunk 信息。
-
Route Server: mongos 实例,前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。
3.集群架构
我是由两台Centos7来搭建的。基本的架构如下
我的两台主机的IP分别为
192.168.98.42与192.168.98.43
然后我的架构如下:
Shard服务器:使用Replica Sets确保每个数据节点都具有备份、自动容错转移、自动恢复的能力。
配置服务器:使用使用3个配置服务器确保元数据完整性。
路由进程:使用3个路由进程实现平衡,提高客户端接入性能。
3 个分片进程:Shard11,Shard12,Shard13 组成一个副本集,提供Sharding 中 shard1 的功能
3 个分片进程:Shard21,Shard22,Shard23 组成一个副本集,提供Sharding 中 Shard2 的功能。
3个配置服务器进程和3个路由器进程。
4.开始配置
4.1 环境搭建
首先搭建环境,去官网下载与你服务器相匹配的mongodb的压缩包,然后解压到你创建的路径,这个路径要用。
比如我下载的是:
注意:重点来了。
1. 以root身份配置
2. 把两台服务器的防火墙停掉!不然联不通
两台都要停掉。
4.2 配置环境变量
根据你压缩包的解压位置,配置环境变量,两台机器上都一样。
命令: vi /etc/profile
在文件最末尾添加。
我的mongodb解压在了/usr/local下,所以我这样写。
使环境变量生效
命令:. /etc/profile
4.3 编写配置文件
因为每一个进程都要通过mongodb启动,启动的时候为了避免使用命令行参数过多的问题,因此编写配置文件来配置。
我建议,根据进程功能编写运行比较好,网上说先运行config进程比较好,但是我是先运行的shard,也没有出现问题。
4.3.1 shard
在192.168.98.42上
第一个
shard11.conf
dbpath=/usr/local/mongodb/data/shard11
logpath=/usr/local/mongodb/log/shard11.log
pidfilepath=/usr/local/mongodb/pid/shard11.pid
directoryperdb=true
logappend=true
replSet=shard1
port=10011
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
注意,这里的dbpath、logpath以及pidfilepath要根据你自己的实际路径填写。我的mongodb解压在了/usr/local下,所以我这样写。
另外:很重要的是,你在路径中所写的目录,没有创建的一定要提前创建好!!!
如/usr/local/mongodb/data/shard11,/usr/local/mongodb/log/,/usr/local/mongodb/pid。一定要先创建好,才可以成功。
第二个
shard12.conf
dbpath=/usr/local/mongodb/data/shard12
logpath=/usr/local/mongodb/log/shard12.log
pidfilepath=/usr/local/mongodb/pid/shard12.pid
directoryperdb=true
logappend=true
replSet=shard1
port=10012
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
第三个
shard21.conf
dbpath=/usr/local/mongodb/data/shard21
logpath=/usr/local/mongodb/log/shard21.log
pidfilepath=/usr/local/mongodb/pid/shard21.pid
directoryperdb=true
logappend=true
replSet=shard2
port=10021
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
第四个
shard22.conf
dbpath=/usr/local/mongodb/data/shard22
logpath=/usr/local/mongodb/log/shard22.log
pidfilepath=/usr/local/mongodb/pid/shard22.pid
directoryperdb=true
logappend=true
replSet=shard2
port=10022
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
在192.168.98.43上
第一个
dbpath=/usr/local/mongodb/data/shard13
logpath=/usr/local/mongodb/log/shard13.log
pidfilepath=/usr/local/mongodb/pid/shard13.pid
directoryperdb=true
logappend=true
replSet=shard1
port=10013
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
第二个
dbpath=/usr/local/mongodb/data/shard23
logpath=/usr/local/mongodb/log/shard23.log
pidfilepath=/usr/local/mongodb/pid/shard23.pid
directoryperdb=true
logappend=true
replSet=shard2
port=10023
fork=true
shardsvr=true
journal=true
bind_ip=0.0.0.0
然后在192.168.98.42上执行
出现以下提示就是成功了。
然后其余的类似。
命令: mongod -f /etc/shard12.conf
命令: mongod -f /etc/shard21.conf
命令: mongod -f /etc/shard22.conf
然后在192.168.98.43上执行
命令: mongod -f /etc/shard13.conf
命令: mongod -f /etc/shard23.conf
所有都success之后,就成功了,如果有报错的,就证明你的配置文件或者目录可能有问题。
接下来,随便在一个mongod上进行登录shard1,进行配置初始化,这里以10011为例。
命令: mongo --port 10011
我的是配置好的,所以出现PRIMARY,不要在意。
输入命令 rs.status()
先查看状态,会出现一个未初始化状态,这里不再截图,因为我的配置好了。
然后
输入命令:
config = { _id:'shard1',
members:[{_id:0,host:'192.168.98.42:10011'},{_id:1,host:'192.168.98.42:10012'},
{_id:2,host:'192.168.98.43:10013'}]
}
这条命令是用来定义配置规则的,id为0的是主,剩余两个是从。
为什么_id是 ‘shard1’呢?
是因为shard11,shard12,shard13中的replSet为shard1.
然后输入命令:rs.initiate(config) 进行配置
出现状态码为 1并且没有其他errmsg才是成功
再输入rs.status()
就会发现配置完成。
这里需要注意的是,只在shard11,shard12,shard13中任意一个进行配置就行。其余的会自动配置。你可以去其他的上面使用rs.status()查看.
这里可能会出现三个都是Secondary的情况,出现这种情况之后,你只要随便再登录一个 比如说 mongo --port 10012 登录上去,使用rs.status()查看就会发现,10011端口那个成了Primary.
也可能出现43主机上的那个节点是 StartUp的情况,那就是因为你两台机器的防火墙并没有关闭
同理,进行配置shard2,就是随便登录一个1002x的端口。
这里以10021为例,
命令: mongo --port 10021
同样的操作,制定config
config = { _id:'shard2',
members:[{_id:0,host:'192.168.98.42:10021'},{_id:1,host:'192.168.98.42:10022'},
{_id:2,host:'192.168.98.43:10023'}]
}
然后使用命令 rs.initiate(config)进行配置。
4.3.2 config
config server与shard的配置没有什么区别,操作方式也是一样的,只不过配置文件有点不同。这里只将配置文件发出来.
192.168.98.42上:
config1.conf
config1.conf
dbpath=/usr/local/mongodb/config/config1
logpath=/usr/local/mongodb/log/config1.log
pidfilepath=/usr/local/mongodb/pid/config1.pid
directoryperdb=true
logappend=true
port=10031
fork=true
configsvr=true
journal=true
replSet=cfgReplSet
bind_ip=0.0.0.0
config2.conf
dbpath=/usr/local/mongodb/config/config2
logpath=/usr/local/mongodb/log/config2.log
pidfilepath=/usr/local/mongodb/pid/config2.pid
directoryperdb=true
logappend=true
port=10032
fork=true
configsvr=true
journal=true
replSet=cfgReplSet
bind_ip=0.0.0.0
然后剩余操作就类似了。
命令:mongod -f config1.conf
命令:mongod -f config2.conf
192.168.98.43上:
config3.conf
dbpath=/usr/local/mongodb/config/config3
logpath=/usr/local/mongodb/log/config3.log
pidfilepath=/usr/local/mongodb/pid/config3.pid
directoryperdb=true
logappend=true
port=10033
fork=true
configsvr=true
journal=true
replSet=cfgReplSet
bind_ip=0.0.0.0
命令:mongod -f config3.conf
之后也是随便登录一个config,这里以config1为例
命令:mongo --port 10031
定义config:
config = { _id:'cfgReplSet',
members:[{_id:0,host:'192.168.98.42:10031'},{_id:1,host:'192.168.98.42:10032'},
{_id:2,host:'192.168.98.43:10033'}]
}
使用命令进行初始化:
rs.initiate(config)
出现状态码为1 则成功。与上面类似。
4.3.3 route
配置完上述服务器之后,路由配置就很简单了。只需要写配置文件,然后执行命令即可。
192.168.98.42
route.conf (这里本来要写route1的,然后就这样吧,不影响)
configdb=cfgReplSet/192.168.98.42:10031,192.168.98.42:10032,192.168.98.43:10033
pidfilepath=/usr/local/mongodb/pid/route.pid
port=10050
logpath=/usr/local/mongodb/log/route.log
logappend=true
fork=true
bind_ip=0.0.0.0
configdb参数写的是三个配置config的地址和端口号。注意别写错地址了。
route2.conf
configdb=cfgReplSet/192.168.98.42:10031,192.168.98.42:10032,192.168.98.43:10033
pidfilepath=/usr/local/mongodb/pid/route2.pid
port=10052
logpath=/usr/local/mongodb/log/route2.log
logappend=true
fork=true
bind_ip=0.0.0.0
命令:mongos -f route.conf
命令:mongos -f route2.conf
注意,这里是mongos
192.168.98.43
route3.conf
configdb=cfgReplSet/192.168.98.42:10031,192.168.98.42:10032,192.168.98.43:10033
pidfilepath=/usr/local/mongodb/pid/route3.pid
port=10053
logpath=/usr/local/mongodb/log/route3.log
logappend=true
fork=true
bind_ip=0.0.0.0
命令:mongos -f route3.conf 注意 这里是mongos
然后路由就配置好了,不用其他多余配置。
4.3.4 分片配置
接下来的任务就是要把他们“连”到一起。
登陆任意一台mongos,
这里以10050端口的mongos为例
然后执行命令
命令: use admin
命令:sh.addShard(“shard1/192.168.98.42:10011,192.168.98.42:10012,192.168.98.43:10013”)
执行完成,成功后会有
提示。
同理 执行命令:
sh.addShard(“shard1/192.168.98.42:10021,192.168.98.42:10022,192.168.98.43:10023”)
查看状态:
命令: sh.status()
命令: db.runCommand({ listshards:1 }) #列出 shard 个数
至此集群搭建完成
4.4 测试
还是在上面的mongos中进行测试,
执行命令
命令: db.runCommand({enablesharding:“testdb”}); # 创建testdb库
执行命令:
命令: db.runCommand( { shardcollection : “friends.user”,key : {id: 1},unique : true } ) # 使用 user 表来做分片,片键为 id 且唯一
查看集群状态:
命令:use testdb
命令: db.users.status()
4.5 总结
只是踩过无数坑,并且看过各种教程后总结的,因为我没有一点mongodb的基本知识,所以搭起来很难,如有错误或者问题,请评论指教。