了解应用的动态
1. 了解正在进行的操作:db.currentOp() , 可以加过滤条件,从而只显示符合条件的结果。
1). 寻找有问题的操作:db.currentOp() 最常见的操作就是用来寻找速度较慢的操作
2). 终止操作的执行:将该操作的opid作为参数,执行db.killOp()来终止该操作的执行。并非所有操作都能被终止。一般来讲,只有交出了锁的进程才能被终止。
3). 假象:在查找哪些操作耗时过长时,可能会发现一些长时间运行的内部操作。所有local.oplog.rs中长时间运行的请求,以及所有回写监听命令,都可以被忽略掉。
4). 避免幽灵操作:阻止幽灵写入的最好方式是使用应答式写入,即每次写入操作都会等待上一次写入操作完成后才进行下去。
2. 使用系统分析器:可以利用系统分析器来查找耗时过长的操作。系统分析器会记录特殊集合system.profile中的操作,但会导致整体性能下降,所以应该只在需要时候开启。
可在shell中运行db.setProfilingLevel()来开启分析器:db.setProfilingLevel(2) 级别为2,意味着"分析器会记录所有内容",性能损失大。
可将分析器级别设置为1,即只显示长耗时的操作。级别为1默认记录耗时大于100ms的操作。也可以自定义"耗时过长"的标准,把耗时值作为函数的第二个参数。db.setProfilingLevel(1,500)
将分析级别设为0可关闭分析器。通常情况下,不要将耗时值slows的值设置的过小。即使分析器处于关闭状态,slowns也会对mongod有所影响,因为它决定了哪些操作将作为耗时过长操作
被记录到日志中。
3. 计算空间消耗:
1). 文档:使用Object.bsonsize()函数:Object.bsonsize({_id:ObjectId()}) Object.bsonsize(db.users.findOne())
2). 集合:stats函数可用来显示一个集合的信息:db.boards.stats()
3). 数据库:db.stats() 在一个繁忙的系统上列出数据库信息会非常慢,而且会阻碍其他操作,应避免此类操作。
4. 使用mongotop和mongostat
1). mongotop类似于UNIX中的top工具,可以概述那个集合最为繁忙。通过运行mongotop-locks ,从而得知每个数据库的状态。
2). mongostat 提供服务器的信息。mongostat默认每秒输出一次包含当前状态的列表,可在命令行中传入参数更改时间间隔。每个字段都会给出自上一次被输出以来,所对应的活动发生次数。
3). 想要获得数据库中正在进行的操作快照,mongostat是很好的选择,但如果要对数据库进行长期监控昂,类似MMS的工具可能更为适合。
数据管理
1. 配置身份验证
1). 身份验证基本原理:admin(管理员)和local(本地)是两个特殊的数据库,他们当中的用户可对任何数据库进行操作。这两个数据库中的用户可被看做是超级用户。经认证后,管理员用户可对任何数据库
进行读写,同时能执行某些只有管理员才能执行的命令,如listDatabases和shutdown。
在shell中用addUser创建用户时,经第三个参数readOnly设置为true,即可创建一个只读权限用户。
2). 配置身份验证:启用身份验证后,客户端必须登录才能进行读写。然而,在MongoDB中有一点值得注意:在admin数据库中建立用户前,服务器上的"本地"客户端可对数据库进行读写。
一般情况下正常新建管理员用户进行身份验证即可避免上的问题,但分片例外,因为数据库admin会被保存到配置服务器上。可以将网络配置为只允许客户端访问mongos进程即可,或者在分片添加管理员账户。
3). 身份验证的工作原理:数据库中的用户是作为文档被保存在器system.users集合中的。这种用以保存用户信息的文档结构是{user:username,readOnly:true,pwd:password hash} 。其中password hash
是基于username和密码生成的散列值。
2. 建立和删除索引:建立和删除索引是数据库最耗费资源的操作之一,所以应小心地安排建立索引
1). 在独立服务器上建立索引:db.foo.ensureIndex({"somefield":1},{"background":true})
2). 在副本集上建立索引:
3). 在分片集群上建立索引:在分片集群上建立索引,与在副本集中建立索引的步骤相同,不过需要在每个分片上分布建立一次。首先,关闭均衡器,然后按照 副本集建立索引的步骤,依次在每个分片中进行操作,
即把每个分片当做一个单独的副本集。最后,通过mongos运行ensureIndex,并重启均衡器。
只有在现存分片中添加索引时才需要这样做,新的分片会在开始接收集合数据块时抓取集合的索引。
4). 删除索引:使用dropIndexes命令并制定索引名来删除索引:db.runCommand({"dropIndexes":foo,"index":"alphabet"}) 。索引名为“*”时会删除一个集合上的所有索引,但这种方法无法删除"_id"索引。
只有删除整个集合才能删除掉该索引。删除集合中的全部文档不会对索引产生影响,新文档插入后索引仍可正常增加。
5). 注意内存溢出杀手(OOM Killer):Linux的内存溢出杀手负责终止使用过多内存的进程。考虑到MongoDB使用内存的方式,除了在建立索引的情况下,它通常不会遇到这种问题。如果在建立索引时,mongod突然消失,请检查
/var/log/messages文件,其中记录了OOM Killer 的输出信息。在后台建立索引或增加交换空间可避免此类情况。如果有机器的惯例权限,可以将MongoDB设置为不可被OOM Killer终止。
3. 预热数据:
1). 将数据库移至内存:如果需要将数据库移至内存中,可使用UNIX中的dd工具,从而在启动mongod前载入数据文件。将/data/db/brains.*替换为/data/db/*可将真个数据目录载入内存。如将一个或一组数据库载入
内存,需占的内存又要比实际内存大的话,则其中一些数据会立即被清除出内存。
mongod 启动时,会向操作系统请求数据文件。如果操作系统发现内存中已经存在了这些数据文件,就可以立即访问mongod。
2). 将集合移至内存:MongoDB提供了touch命令来预热数据。启动mongod(也许在另一个端口,或关闭防火墙对它的限制),对一个集合使用touch命令,从而将其载入内存:
db.runCommand({"touch":"logs","data":true,"index":true}) 将logs集合中的所有文档和索引载入内存。可以指定值载入文档或只载入索引。注意内存的使用情况。
3). 自定义预热:
a. 加载一个特定的索引
b. 加载最近更新文档
c. 记载最近创建的文档:利用最近创建文档的时间戳进行文档查询。ObjectId中包含时间戳。
d. 重放应用使用记录:MongoDB提供名为诊断日志的功能来记录和回放操作流水。启动诊断日志会造成性能损失,所以最好通过临时使用的方式来获得一份"有代表性的操作流水"
4. 压缩数据:为消除空区段,并高效重整集合,可使用compact命令:db.runCommand({"compact":"collName"})
压缩操作会消耗大量资源,不应再mongod向客户端提供服务时,计划压缩操作。推荐做法类似于建立索引的做法,即在每个备份节点中对数据执行压缩操作,然后关闭主节点,进行最后压缩操作。
压缩会将文档尽可能地安排在一起,文档间的间隔参数默认为1.如需更大的间隔参数,可使用额外的参数来指定它:db.runCommand({"compact":"collname","paddingFactor":1.5}) ,最大值为4
可以通过repair命令来回收磁盘空间。repair命令会对所有数据进行复制,所以必须拥有和当前数据文件一样大小的额空余磁盘空间。在启动mongod时使用--repair选项(如需要,还可以使用--repairepath
选项)来进行修复。可以在shell中调用db.repairDatabase()来修复数据库。
5. 移动集合:
1). 可使用renameCollection命令重命名集合:db.sourceColl.renameCollection("newname") , 执行这个命令时可以传入第二个参数,从而决定当名为newname的集合存在时如何处理。true 会
删除名为newname的集合,false ,会抛出错误。
2). 想要在数据库间移动集合,必须进行转储和恢复操作,或手动复制集合中的文档。
cloneCollection将一个集合移动到另一个不同的mongod中:db.runCommond({"cloneCollection":collName,"from":"hostname":27017})
6. 预分配数据数据文件:
持久性
1. 如磁盘和软件正常运行,则MongoDB能够在系统崩溃或强制关闭后,确保数据的完整性。
2. 日志系统的用途:MongoDB会在进行写入时创建一条日志,日记中包含了此次写入操作具体更改的磁盘地址和字节。因此,一旦服务器突然停机,可以在启动时对日志进行重放,从而重新执行
那些停机前没有能够刷新到磁盘的写入操作。数据文件默认每60秒刷新一次,因此日志文件值需记录约60秒的写入内容。日记系统为此预先分配了若干个空间文件,这些文件存放在/data/db/journal目录中,
文件名为_j.0,_j.1等。数据库正常关闭日志文件会被清除。如发生崩溃,mongod会在启动时重放日志文件,同时显示出大量的校验信息。
1). 批量提交写入操作:MongoDB默认每隔100毫秒,或是写入数据达到若干兆字节时,便会将这些操作写入日记。这意味着MongoDB会成批量地提交更改,即每次写入不会立即刷新到磁盘。不过默认设置
下,系统发生崩溃时,最多丢失100毫秒的写入。可通过向getLastEror传递 j 选项,来确保写入操作的成功。设置此选项后,大约等待30毫秒。对一些重要的数据,可以使用此选项。
2). 设定提交时间间隔:运行setParameter命令,设定journalCommitInterval的值(最小为2毫秒,最大为500毫秒)。无论时间间隔设置为多少,使用带有"j":true的getLastError命令都会将该值减少到原来的三分之一。
3. 关闭日记系统:如果写入数据的价值不及写入速度降低带来的损失,我们可能会禁用日记系统。如果希望系统崩溃后能继续工作,有以下几种方法:
1). 替换数据文件
2). 修复数据文件:mongod自带两种修复工具,一种是mongod内置的,一种是mongodump内置的。mongodump的修复更接近底层。 --repair.
3). mongod.lock 文件:异常退出时会有mongod.lock文件,阻碍mongod重新启动,标志我们需要先修复数据。也可以通过删除该文件重启mongod(生产环境不建议).
4). 隐蔽的异常退出:
4. MongoDB无法包保证的事项:在硬盘或文件系统出现故障的情况下,MongoDB无法保证操作的持久性。
5. 检验数据损坏:可以使用validate命令,检验集合是否有损坏:db.foo.validate()
6. 副本集的持久性:可以通过db.runCommand({"getLastError":1,"j":true,"w":"majority"}) 中的"w"参数的值,保证写入操作写入到主节点和备份节点中,其中只有对主节点的写入可保证持久性。