Mongodb 笔记08 了解应用的动态、数据管理、持久性

时间:2022-08-30 20:20:25

了解应用的动态

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"参数的值,保证写入操作写入到主节点和备份节点中,其中只有对主节点的写入可保证持久性。