1、Master-Slave主从结构
主从架构一般用于备份或者做读写分离。一般有一主一从设计和一主多从设计。
由两种角色构成:
(1)主(Master)
可读可写,当数据有修改的时候,会将oplog同步到所有连接的salve上去。
在早期的系统设计中,主从模式是比较流行的,将读写分离,在不同的DB上操作,可以有效降低数据库的压力,而且还能实现数据的备份,但是在master节点故障的时候,不能及时的自动的切换到slaves节点,需要手动干预,这个是硬伤
(2)从(Slave)
只读不可写,自动从Master同步数据。
特别的,对于Mongodb来说,并不推荐使用Master-Slave架构,因为Master-Slave其中Master宕机后不能自动恢复,推荐使用Replica Set
除非Replica的节点数超过50,才需要使用Master-Slave架构,正常情况是不可能用那么多节点的。
还有一点,Master-Slave不支持链式结构,Slave只能直接连接Master。Redis的Master-Slave支持链式结构,Slave可以连接Slave,成为Slave的Slave。
2、Relica Set副本集方式
Mongodb的Replica Set即副本集方式主要有两个目的,一个是数据冗余做故障恢复使用,当发生硬件故障或者其它原因造成的宕机时,可以使用副本进行恢复。
另一个是做读写分离,读的请求分流到副本上,减轻主(Primary)的读压力。
默认情况下,复制集的所有读请求都发到 Primary,Driver 可通过设置 Read Preference 来将读请求路由到其他的节点。
副本节点同步直接点操作是异步的,然而会导致副本集无法返回最新的数据给客户端程序。
(1)主节点(Primary)
接收所有的写请求,然后把修改同步到所有Secondary。一个Replica Set只能有一个Primary节点,当Primary挂掉后,其他Secondary或者Arbiter节点会重新选举出来一个主节点。默认读请求也是发到Primary节点处理的,需要转发到Secondary需要客户端修改一下连接配置。
(2)副本节点(Secondary)
与主节点保持同样的数据集。当主节点挂掉的时候,参与选主。
(3)仲裁者(Arbiter)
不保有数据,不参与选主,只进行选主投票。使用Arbiter可以减轻数据存储的硬件需求,Arbiter跑起来几乎没什么大的硬件资源需求,但重要的一点是,在生产环境下它和其他数据节点不要部署在同一台机器上。
注意,一个自动failover的Replica Set节点数必须为奇数,目的是选主投票的时候要有一个大多数才能进行选主决策。
(4)选主过程
其中Secondary宕机,不受影响,若Primary宕机,会进行重新选主
3、MongoDB的Sharding架构
为什么使用分片
。复制所有的写入操作到主节点
。延迟的敏感数据会在主节点查询
。单个副本集限制在12个节点
。当请求量巨大时会出现内存不足。
。本地磁盘不足
。垂直扩展价格昂贵
Sharding cluster是一种可以水平扩展的模式,在数据量很大时特给力,实际大规模应用一般会采用这种架构去构建。sharding分片很好的解决了单台服务器磁盘空间、内存、cpu等硬件资源的限制问题,把数据水平拆分出去,降低单节点的访问压力。每个分片都是一个独立的数据库,所有的分片组合起来构成一个逻辑上的完整的数据库。因此,分片机制降低了每个分片的数据操作量及需要存储的数据量,达到多台服务器来应对不断增加的负载和数据的效果。
(1)数据分片(Shards)
用来保存数据,保证数据的高可用性和一致性,将其分散在不同的机器上的过程。将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载
分片的基本思想就是:
将集合切成小块,这些块分散到若干片里,每个片只负责总数据的一部分。通过一个名为 mongos 的路由进程进行操作,mongos 知道数据和片的对应
关系(通过配置服务器)。 大部分使用场景都是解决磁盘空间的问题,对于写入有可能会变差(+++里面的说明+++),查 询则尽量避免跨分片查询。使用分片的时机:
(2)查询路由(Query Routers)
路由就是mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去
(3)配置服务器(Config servers)
保存集群的元数据(metadata),包含各个Shard的路由规则
部署MongoDB
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-3.4.24.tgz
wget https://fastdl.mongodb.org/src/mongodb-src-r4.2.6.tar.gz
解除linux系统“文件句柄数和最大用户进程数限制”,即设置ulimit -n和ulimit -u的值大于20000。如果ulimit的值设置过低的话,当MongoDB处于频繁访问的状态下,将会产生错误,最终导致无法连接到MongoDB实例。
设置方法如下以CentOS7为例:
more /etc/security/limits.conf
root soft fsize unlimited
root hard fsize unlimited
root soft cpu unlimited
root hard cpu unlimited
root soft as unlimited
root hard as unlimited
root soft nofile 64000
root hard nofile 64000
root soft nproc 64000
root hard nproc 64000
二、部署MongoDB
安装依赖
yum install checkpolicy
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-3.4.24.tgz
tar xf mongodb-linux-x86_64-3.4.24.tgz
mkdir /data/mongo/{data,log,run} -p
配置mongo环境变量
echo "export PATH=$PATH:/opt/shell/soft/mongodb/mongodb-linux-x86_64-3.4.24/bin" >> /etc/profile.d/mongo.sh
source /etc/profile.d/mongo.sh
配置mongo配置文件
#允许任何IP进行连接
bind_ip=10.0.0.5
#运行的端口号
port=27017
#数据存放位置
dbpath=/data/mongo/data
#日志文件
logpath=/data/mongo/log/mongodb.log
#指定pid文件
pidfilepath =/data/mongo/run/mongodb.pid
#以追的方式记录日志
logappend=true
#允许后台运行
fork=true
#最大同时连接数 默认2000
maxConns=2000
auth=true
启动mongo
mongod -f /opt/shell/soft/mongodb/mongodb.conf
关闭mongo
mongod -f /opt/shell/soft/mongodb/mongodb.conf --shutdown
设置开机启动
vim /lib/systemd/system/mongodb.service
[Unit]
Description=mongodb server daemon
Documentation=man:mongodb(8) man:mongod(5)
After=network.target mongodb.service
[Service]
User=mgdb
# (open files)
LimitCORE=infinity
LimitNOFILE=100000
LimitNPROC=100000
Type=forking
ExecStart=/opt/mongodb/bin/mongod -f /opt/mongodb/mongodb.conf
ExecReload=/bin/kill -HUP
ExecStop=/opt/mongodb/bin/mongod -f /opt/mongodb/mongodb.conf --shutdown
PrivateTmp=true
[Install]
WantedBy=multi-user.target
重载系统服务
systemctl daemon-reload
systemctl start mongodb
systemctl stop mongodb
mongod查询数据出错:原因是因为没有指定数据库的登录权限
show dbs
2020-04-27T20:05:44.642+0800 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { listDatabases: 1.0 }",
"code" : 13,
"codeName" : "Unauthorized"
} :
设置密码
1、mongodb是没有默认管理员账号,所以要先添加管理员账号,再开启权限认证。
2、切换到admin数据库,添加的账号才是管理员账号。
3、用户只能在用户所在数据库登录,包括管理员账号。
4、管理员可以管理所有数据库,但是不能直接管理其他数据库,要先在admin数据库认证后才可以。这一点比较怪
以用户管理员身份登录,并切换数据库,创建数据库用户:
use admin
switched to db admin
db.createUser({user:"admin",pwd:"123456",roles:["root"]})
mongodb的内置roles 超级用户角色:root
登陆admin账号
use admin
switched to db admin
db.auth('admin','123456')
1
查看mongodb最大连接数
db.serverStatus().connections;
{ "current" : 1, "available" : 818, "totalCreated" : 1 }将节点配置组成集群需要2个节点执行一遍
> use admin
switched to db admin
e2mongo:SECONDARY> cfg={ _id:"e2mongo",members:[{_id:0,host:'192.168.0.8:27017',priority:2},{_id:1,host:'192.168.0.25:27017',priority:1},{_id:2,
host:'192.168.0.29:27017',arbiterOnly:true}] };
{
"_id" : "test",
"members" : [
{
"_id" : 0,
"host" : "10.0.0.3:27017",
"priority" : 2
},
{
"_id" : 1,
"host" : "10.0.0.4:27017",
"priority" : 1
},
{
"_id" : 2,
"host" : "10.0.0.5:27017",
"arbiterOnly" : true
}
]
}
初始化副本集的配置
> rs.initiate(config)
{
"ok" : 0,
"errmsg" : "'10.0.0.5:27017' has data already, cannot initiate set.",
"code" : 110,
"codeName" : "CannotInitializeNodeWithData"
}
10.0.0.5有数据,无法初始化设置。10.0.0.5删除数据完成初始化
rm -rf /data/mongo/data/*
> rs.initiate(config)
{ "ok" : 1 }
查看副本集状态
test:OTHER> rs.config()
{
"_id" : "test",
"version" : 1,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "10.0.0.3:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 2,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "10.0.0.4:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.0.0.5:27017",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : 60000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5eb152b2c0b76bcc5e6f59c6")
}
}
test:SECONDARY>
查看主节点信息
> rs.isMaster()
{
"ismaster" : false,
"secondary" : false,
"info" : "Does not have a valid replica set config",
"isreplicaset" : true,
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2020-05-05T11:58:24.985Z"),
"maxWireVersion" : 5,
"minWireVersion" : 0,
"readOnly" : false,
"ok" : 1
}
测试数据
执行如下命令,在主节点上插入一条数据
use test
switched to db test
db.test.insertOne({"name": "kenny"})
{
"acknowledged" : true,
"insertedId" : ObjectId("5eb178946b48970d07e529f5")
}
db.test.find()
{ "_id" : ObjectId("5eb178946b48970d07e529f5"), "name" : "kenny" }进入任何一个从节点,查看数据是否被同步。
当我们要查看从节点数据时,发现出错,这是因为从节点默认情况下是拒绝读取的,因此需开启读取功能 :rs.slaveOk()test:SECONDARY> db.test.find() Error: error: { "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435, "codeName" : "NotMasterNoSlaveOk" } test:SECONDARY> rs.slaveOk() test:SECONDARY> db.test.find() { "_id" : ObjectId("5eb178946b48970d07e529f5"), "name" : "kenny" }
测试重新选举主节点
在3个节点上分别使用rs.isMaster()命令rs.isMaster() { "hosts" : [ "10.0.0.3:27017", "10.0.0.4:27017" ], "arbiters" : [ "10.0.0.5:27017" ], "setName" : "test", "setVersion" : 1, "ismaster" : true, "secondary" : false, "primary" : "10.0.0.3:27017", "me" : "10.0.0.3:27017", "electionId" : ObjectId("7fffffff0000000000000001"), "lastWrite" : { "opTime" : { "ts" : Timestamp(1588689358, 1), "t" : NumberLong(1) }, "lastWriteDate" : ISODate("2020-05-05T14:35:58Z") }, "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 1000, "localTime" : ISODate("2020-05-05T14:35:59.909Z"), "maxWireVersion" : 5, "minWireVersion" : 0, "readOnly" : false, "ok" : 1 }
关闭主节点,从节点查看从secondary变成了primary
test:SECONDARY> rs.isMaster() { "hosts" : [ "10.0.0.3:27017", "10.0.0.4:27017" ], "arbiters" : [ "10.0.0.5:27017" ], "setName" : "test", "setVersion" : 1, "ismaster" : true, "secondary" : false, "primary" : "10.0.0.4:27017", "me" : "10.0.0.4:27017", "electionId" : ObjectId("7fffffff0000000000000002"), "lastWrite" : { "opTime" : { "ts" : Timestamp(1588690181, 1), "t" : NumberLong(2) }, "lastWriteDate" : ISODate("2020-05-05T14:49:41Z") }, "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 1000, "localTime" : ISODate("2020-05-05T14:49:48.529Z"), "maxWireVersion" : 5, "minWireVersion" : 0, "readOnly" : false, "ok" : 1 } test:PRIMARY>
systemctl restart mongodb
tail -f /data/mongo/log/mongodb.log
ACCESS [main] error opening file: /data/mongo/keyfile: Permission denied
l l /data/mongo/
-rw-------. 1 root root 996 6月 16 23:14 keyfile
chown -R mongodb:mongodb /data/mongo/
MongoDB安装参考文档:
http://blog.itpub.net/31547523/viewspace-2214742/
集群模式对比:
https://blog.csdn.net/haoding205/article/details/82351753
集群模式原理:
https://www.cnblogs.com/nulige/p/7613721.html