mongoDB的操作总结
1、mongodb副本集数据同步
从mongodb2.0开始支持链式复制,并且默认是开启的,是根据second节点之间的ping time和网络距离进行选择那个second作为数据的同步节点,链式复制的优点:可以减少master的资源消耗,减少负载。缺点:节点之间同步数据本来就不可避免会有数据的延迟,执行链式复制的过程会使这个时间增大,该second节点的数据就会比其他的更落后于master,所以在读取数据的时候就会有一些问题,比如读取数据读不到,后端服务就会抛错,导致用户能感知到,非常不好,当然可以通过降低数据延迟来缓解,保证节点见的网络带宽流畅、io等。
方案
了解了副本集之间的复制方式,接下来就开始着手解决这个数据延迟的问题,从官网来看有两种方式:使用rs.syncFrom()设置同步源、禁用掉链式复制
1、rs.syncFrom
官网对于这个命令的介绍:
Provides a wrapper around the replSetSyncFrom
, which allows administrators to temporarily override the default sync target for the current member. Specify the name of the member you want to replicate from in the form of [hostname]:[port]
.
Changed in version 3.2: MongoDB 3.2 replica set members with 1 vote
cannot sync from members with 0votes
.
>rs.syncFrom("myHost:27017");
2、禁用掉链式复制
Disable Chained Replication
To disable chained replication, set the settings.chainingAllowed
field in Replica Set Configuration to false
.
If chained replication is disabled, you still can use replSetSyncFrom
to specify that a secondary replicates from another secondary. But that configuration will last only until the secondary recalculates which member to sync from.(禁用了链式复制以后,还是可以通过replSetSyncFrom指定复制源为second,但是必须要有投票权
)
You can use the following sequence of commands to set settings.chainingAllowed
to false
:
cfg = rs.config() cfg.settings.chainingAllowed = false rs.reconfig(cfg)
Re-enable Chained Replication
To re-enable chained replication, set settings.chainingAllowed
to true
. You can use the following sequence of commands:
cfg = rs.config() cfg.settings.chainingAllowed = true rs.reconfig(cfg)
3、常用监控方法
rs.printSlaveReplicationInfo() 打印数据同步延迟信息
rs.printReplicationInfo() 打印oplog信息
具体遇到数据同步延迟的,需要具体分析当时的情况,不能盲目的修改。首先考虑节点服务器的负载情况和当时的网络环境是否正常,有的时候可能是网络环境导致的,排除这些原因后,再去考虑修改同步源。这样要做好读写分离,否则master的压力会非常大。如果master的压力太大就要做一些处理,比如切换一下msater升级资源或使用replSetSyncFrom切换同步源到second上。
4. 更改节点优先级
修改节点的优先级可以触发重新选举,这样可以人工指定主节点。
使用如下命令,在主节点登录,将192.168.1.3提升为Master。
rs.conf(); cfg=rs.conf(); cfg.members[0].priority=1 cfg.members[1].priority=1 cfg.members[2].priority=10 rs.reconfig(cfg);
需要注意的是,修改节点优先级需要登录Master节点运行。否则报错。
再次查看集群状态,可以看到192.168.1.3已经作为Master运行
5 .节点类型
MongoDB的节点类型有主节点(Master),副本节点(Slave或者称为Secondary),仲裁节点,Secondary-Only节点,Hidden节点,Delayed节点和Non-Voting节点。
仲裁节点不存储数据,只是负责故障转移的群体投票,这样就少了数据复制的压力。
Secondary-Only:不能成为primary节点,只能作为secondary副本节点,防止一些性能不高的节点成为主节点。
Hidden:这类节点是不能够被客户端制定IP引用,也不能被设置为主节点,但是可以投票,一般用于备份数据。
Delayed:可以指定一个时间延迟从primary节点同步数据。主要用于备份数据,如果实时同步,误删除数据马上同步到从节点。所以延迟复制主要用于避免用户错误。
Non-Voting:没有选举权的secondary节点,纯粹的备份数据节点。
6 .设置隐藏节点(Hidden)
隐藏节点可以在选举中投票,但是不能被客户端引用,也不能成为主节点。也就是说这个节点不能用于读写分离的场景。
将192.168.1.3设置为隐藏节点。
注意,只有优先级为0的成员才能设置为隐藏节点。
如果设置优先级不为0的节点为隐藏节点,则报错如下
使用如下命令设置隐藏节点
cfg=rs.conf(); cfg.members[0].priority=10 cfg.members[1].priority=1 cfg.members[2].priority=0 cfg.members[2].hidden=1 rs.reconfig(cfg);
设置完成之后,使用rs.status()查看该节点还是SECONDARY状态。
但是通过rs.isMaster()和rs.conf()可以看到这个节点的变化。
rs.isMaster()的hosts中192.168.1.3节点已经不可见
并且rs.conf()显示该节点状态为hidden
7 .设置仲裁节点
仲裁节点不存储数据,只是用于投票。所以仲裁节点对于服务器负载很低。
节点一旦以仲裁者的身份加入集群,他就只能是仲裁者,无法将仲裁者配置为非仲裁者,反之也是一样。
另外一个集群最多只能使用一个仲裁者,额外的仲裁者拖累选举新Master节点的速度,同时也不能提供更好的数据安全性。
初始化集群时,设置仲裁者的配置如下
config = { _id:"mvbox", members:[ {_id:0,host:"192.168.1.1:27017"}, {_id:1,host:"192.168.1.2:27017",arbiterOnly:true}, {_id:2,host:"192.168.1.3:27017"}] }
使用仲裁者主要是因为MongoDB副本集需要奇数成员,而又没有足够服务器的情况。在服务器充足的情况下,不应该使用仲裁者节点。
8 .设置延迟复制节点(延迟节点)
MongoDB官方没有增量备份方案,只有一个导出的工具mongodump。
他不能像数据库一样,通过binlog或者归档日志将数据推到事故发生的前一刻。
假设每天凌晨2点使用mongodump备份,而下午5点发生事故,数据库损毁,则凌晨2点到下午5点的数据全部都会丢失。
虽然副本集可以一定程度避免这个问题,但是默认情况下不能避免人为的失误。
比如没有指定筛选条件删除了全部的数据。副本节点会应用这个命令,删除所有副本节点的数据。
在这个场景下,可以使用延迟节点,它会延迟应用复制。
如果主节点发生了人为的失误,而这个操作因为延迟的原因,还没有应用在延迟节点。
这个时候,修改延迟节点的优先级为最高级,使他成为新的Master服务器。
延迟节点的优先级必须为0.这个和hidden节点是一样的。
设置192.168.1.2为延迟节点
cfg=rs.conf(); cfg.members[1].priority=0 cfg.members[1].slaveDelay=3600 rs.reconfig(cfg);
slaveDelay的单位是秒
在192.168.1.1主节点删除一个集合所有数据,模拟人为失误。
db.users.remove({});
在192.168.1.3查看,发现数据已经全部丢失。
db.users.find();
而在192.168.1.2延迟节点,可以看到因为延迟复制的缘故,数据还在。
这个时候千万不要提升延迟节点的优先级。因为这样他会立即应用原主节点的所有操作,并成为新的主节点。这样误操作就同步到了延迟节点。
首先,关闭副本集中其他的成员,除了延迟节点。
删除其他成员数据目录中的所有数据。确保每个其他成员的数据目录都是空的(除了延迟节点)
重启其他成员,他们会自动从延迟节点中恢复数据(且并不改变之前的节点配置)。
9 .设置Secondary-Only节点
Priority为0的节点永远不能成为主节点,所以设置Secondary-only节点只需要将其priority设置为0.
10 .设置Non-Voting节点
假设设置192.168.1.1不能投票,则使用如下命令
cfg=rs.conf(); cfg.members[0].votes=0; rs.reconfig(cfg);
11 .副本集成员状态
副本集成员状态指的是rs.status()的stateStr字段
STARTUP:刚加入到复制集中,配置还未加载 STARTUP2:配置已加载完,初始化状态 RECOVERING:正在恢复,不适用读 ARBITER: 仲裁者 DOWN:节点不可到达 UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂 REMOVED:移除复制集 ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态 FATAL:出错。查看日志grep “replSet FATAL”找出错原因,重新做同步 PRIMARY:主节点 SECONDARY:备份节点
12. 读写分离
如果Master节点读写压力过大,可以考虑读写分离的方案。
不过需要考虑一种场景,就是主服务器的写入压力非常的大,所以副本节点复制的写入压力同样很大。
这时副本节点如果读取压力也很大的话,根据MongoDB库级别读写锁的机制,
很可能复制写入程序拿不到写锁,从而导致副本节点与主节点有较大延迟。
如果进行读写分离,首先需要在副本节点声明其为slave,
db.getMongo().setSlaveOk();
其中的ReadRreference有几种设置:
primary:默认参数,只从主节点上进行读取操作;
primaryPreferred:大部分从主节点上读取数据,只有主节点不可用时从secondary节点读取数据。
secondary:只从secondary节点上进行读取操作,存在的问题是secondary节点的数据会比primary节点数据“旧”。
secondaryPreferred:优先从secondary节点进行读取操作,secondary节点不可用时从主节点读取数据;
nearest:不管是主节点、secondary节点,从网络延迟最低的节点上读取数据。
MongoDB客户端配置,可以提出来做成spring注入,设置最大连接数什么的。
MongoClientOptions options = MongoClientOptions.builder().maxWaitTime(1000 * 60 * 2) .connectionsPerHost(500).build(); mongoClient = new MongoClient(Arrays.asList(new ServerAddress("10.205.68.57", 8700), new ServerAddress("10.205.68.15", 8700), new ServerAddress("10.205.69.13", 8700)), options); mongoClient.setReadPreference(ReadPreference.secondaryPreferred());
13.mongodb慢查询的设置
开启慢日志 1.查看mongodb慢日志是否开起 use BJ_Rack; db.getProfilingStatus(); 发现没有开户慢日志 2.开启慢日志,设置超过200毫秒的操作为慢操作 db.setProfilingLevel(1); db.setProfilingLevel(1,200); 超过200ms的才记录 0 不开启 1 记录慢查询 2 记录所有查询 db.getProfilingStatus() 3.查看慢日志内容 得到50个比较慢的操作日志. db.system.profile.find().sort({$natural:-1}) #### 查看查询时间超过某个时间的 use local db.system.profile.find({millis:{$gte:500}}).sort({"ts":-1}).limit(3) #### 查询最慢的查询 db.system.profile.find().sort({"millis":-1}).limit(3) 通过配置文件开启: operationProfiling: mode: slowOp slowOpThresholdMs: 100 查看当前操作 db.currentOp(true); 查看当前节点的连接情况 db.serverStatus().connections