在生产环境中部署完MongoDB,你就希望能了解它的运转情况。如果系统性能在慢慢下降或者经常发生故障,你希望能够知道这些情况,这就该用到监控了。让我们先从最简单的监控开始:日志。随后我们会看一些内置命令,它们能提供正在运行的MongoDB服务器的大多数信息;这些命令是mongostat
工具和Web控制台的基础,我会对mongostat
工具和Web控制台做个简要说明。我还会推荐几个外部监控工具。本节最后会介绍两个诊断工具:bsondump
和mongosniff
。
10.2.1 日志
日志是第一级监控,正因如此,你应该计划保留所有部署的MongoDB的日志。1通常这都不是问题,因为MongoDB在后台运行时要求你指定--logpath
选项。此外,还有一些需要留意的额外设置。要开启详细日志(verbose logging),在启动mongod
进程时加上-vvvvv
选项(v
越多,输出越详细)。举例来说,如果需要调试一些代码,想要在日志里记录下每个查询,这就很方便。但是也要注意,详细日志会让日志文件变得很大,可能会影响服务器的性能。
1. 不要简单地通过管道将日志输出到/dev/null
或stdout
。
其次,可以在启动mongod
时使用--logappend
选项,这会让日志追加到现有日志文件后面,而非覆盖它。
最后,如果有一个长时间运行的MongoDB进程,你可能想写一个脚本周期性地滚动日志文件,为此,MongoDB提供了logrotate
命令,可以像这样在Shell里运行该命令:
> use admin> db.runCommand({logrotate: 1})
向进程发送SIGUSR1
信号也能运行logrotate
命令,下面是如何向进程号为12345的进程发送SIGUSR1
信号:
$ kill -SIGUSR1 12345
10.2.2 监控工具
本节我会介绍MongoDB自带的监控命令和工具。
1. 数据库命令
有三个展示MongoDB内部状态的数据库命令,它们是所有MongoDB监控应用程序的基础。
serverStatus
serverStatus
命令的输出真是名副其实的内容丰富。统计的所有信息当中包含页错误、B树访问率、打开连接数,以及总的插入、更新、查询和删除。下面是一段节选后的serverStatus
命令输出:
> use admin> db.runCommand({serverStatus: 1}){ /"host/" : /"ubuntu/", /"version/" : /"1.8.0/", /"process/" : /"mongod/", /"uptime/" : 246562, /"localTime/" : ISODate(/"2011-03-13T17:01:37.189Z/"), /"globalLock/" : { /"totalTime/" : 246561699894, /"lockTime/" : 243, /"ratio/" : 9.855545289656455e-10, /"currentQueue/" : { /"total/" : 0, /"readers/" : 0, /"writers/" : 0 }, }, /"mem/" : { /"bits/" : 64, /"resident/" : 3580, /"virtual/" : 9000, /"mapped/" : 6591 } /"ok/" : 1 }
globalLock
部分很重要,因为它揭示了服务器花在写锁上的总时间。这里的高比例说明写操作有瓶颈。currentQueue
也许是更具体的瓶颈表述,如果有大量的读或写等在队列里,那么就该进行某种优化了。
mem
部分显示了mongod
进程是如何使用内存的。bits
字段说明这是一台64位的机器。resident
是MongoDB所占用的物理内存数量。virtual
是进程所映射的虚拟内存的兆字节数,mapped
是virtual
的子集,标明那些内存里有多少是只用来映射数据文件的。本例中,有大约6.5 GB的数据文件被映射到了虚拟内存里,其中3.5 GB是物理内存。我反复强调,理想情况下工作集应该能被放到内存里,mem
部分能提供一个大概的信息,说明情况是否如此。
每个版本的MongoDB里,serverStatus
的输出都会有所变化并得以改进,因此像本书这样在非永久性媒介里为该命令编写文档并不总是很有帮助。你可以在http://www.mongodb.org/display/DOCS/serverStatus看到该命令的最新详细说明。
top
top
命令会显示每个数据库的操作计数器。如果应用程序使用了多个物理数据库,或者你想看看操作的平均耗时,那么这是个有用的命令。下面是一些示例输出:
> use admin> db.runCommand({top: 1}) {/"totals/" : { /"cloud-docs/" :{ /"total /" : { /"time/" : 194470, /"count/" : 20 }, /"readLock/" : { /"time/" : 324, /"count/" : 12 }, /"writeLock/" : { /"time/" : 194146, /"count/":8}, /"queries /" : { /"time/" : 194470, /"count/" : 20 }, /"getmore /" : { /"time/" : 0, /"count/":0}},/"ok/" : 1}
此处可以看到很多时间都花在了写锁上,值得深入调查一下,看看写操作是否有可以优化的地方。
db.currentOp
能知道MongoDB目前正在做什么常常很有用,db.currentOp
方法就能揭示这个信息,它会返回当前正在运行的所有操作,以及正在等待运行的其他操作。下面是该方法的输出示例,它是在上一章里配置的分片集群上运行的:
db.currentOp[{ /"opid/" : /"shard-1-test-rs:1232866/", /"active/" : true, /"lockType/" : /"read/", /"waitingForLock/" : false, /"secs_running/" : 11, /"op/" : /"query/", /"ns/" : /"docs.foo/", /"query/" : { /"$where/" : /"this.n > 1000/" }, /"client_s/" : /"127.0.0.1:38068/", /"desc/" : /"conn/" }]
现在正在执行一条特别慢的查询,可以看到它已经运行了11 s了,和所有查询一样,它会占用读锁。如果这个操作有问题,你可能会想调查一下它的调用源,可以看看client
字段。啊呀,这是一个分片集群,因此调用源是mongos
进程,正如client_s
字段名所标识的那样。如果要杀掉这个操作,可以将opid
传给db.killOp
方法:
db.killOp(/"shard-1-test-rs:1232866/"){ /"op/" : /"shard-1-test-rs:1233339/", /"shard/" : /"shard-1-test-rs/", /"shardid/" : 1233339}
如果想要查看当前MongoDB服务器上正在运行的所有操作的列表,可以使用如下虚拟命令:
db[/'$cmd.sys.inprog/'].find({$all: 1})
2. mongostat
db.currentOp
方法只会显示特定时刻排在队列中或者正在执行的操作。类似的,serverStatus
命令只提供某一时间点上不同系统字段和计数器的快照。但是,有些时候你需要系统实时活动的视图,这时就该mongostat
登场了。mongostat
效仿iostat
和其他类似的工具,以固定时间间隔查询服务器信息,显示统计数据的矩阵,从每秒插入数到常驻内存量,再到B树页丢失频率。
可以在localhost
上调用mongostat
命令,显示信息每秒滚动一次:
$ mongostat
mongostat
命令同样也是高度可配置的,可以通过--help
查看所有选项。它还有一个更出名的特性,即集群发现(cluster discovery);在启动mongostat
时带上--discover
选项,你可以将它指向单个节点,它会发现副本集或分片集群中的剩余节点,随后聚合显示整个集群的统计信息。
3. Web控制台
通过Web控制台,你能以更可视化的方式获得某个运行中的mongod
进程的信息。每个mongod
进程都会监听服务器端口往上第1000个端口的HTTP请求。如果你的mongod
运行在27017端口,那么Web控制台就在28017端口。如果运行在localhost
上,可以将Web浏览器指向http://localhost:28017,你会看到如图10-1所示的页面。
开启服务器的基本REST接口后,还能获得更多状态信息。如果在启动mongod
时加上--rest
,就能开启很多额外的Web控制台命令,Web控制台的登录页面上有指向它们的链接。
图10-1 MongoDB Web控制台
10.2.3 外部监控应用程序
大多数重要的部署都要求有外部监控应用,Nagios和Munin是两款流行的开源监控系统,很多MongoDB部署都用它们来进行监控。两款工具都只需安装一个简单的开源插件就能监控MongoDB。
编写一个针对某款监控应用程序的插件并非难事,一般都涉及针对某个在线MongoDB数据库运行不同统计命令。serverStatus
、dbstats
和collstats
命令通常就能提供需要的所有信息,你能直接通过HTTP REST接口获得所有这些信息,不需要使用驱动。
10.2.4 诊断工具(mongosniff
、bsondump
)
MongoDB包含两个诊断工具。第一个是mongosniff
,它能侦听客户端发给MongoDB服务器的数据包并将其以易于理解的形式输出。如果恰好要编写一个驱动或是调试一个错误连接,那这就是最好的工具。可以像下面这样启动mongosniff
,监听本地网络接口的默认端口:
sudo mongosniff --source NET I0
有客户端(比方说MongoDB Shell)连接上来之后,你会得到一个简单易读的网络交互情况:
127.0.0.1:58022 -->> 127.0.0.1:27017 test.$cmd 61 bytes id:89ac9c1d 2309790749 query: { isMaster: 1.0 } ntoreturn: -1127.0.0.1:27017 <<-- 127.0.0.1:58022 87 bytes reply n:1 cursorId : 0 { ismaster: true, ok: 1.0 }
通过--help
可以看到mongosniff
的所有选项。
另一个有用的工具是bsondump
,允许你查看原始BSON文件。BSON文件是由mongodump
工具(稍后会讨论它)和副本集回滚来生成的。2举例来说,假设你导出了一个只有单个文档的集合。如果那个集合最终被放到一个名为users.bson
的文件里,那么可以轻松地用如下命令查看文件内容:
2. 还有其他一些情况下你也会看到原始BSON文件,但是MongoDB的数据文件并非其中之一,所以不要尝试用bsondump
查看它们。
$ bsondump users.bson{ /"_id/" : ObjectId( /"4d82836dc3efdb9915012b91/" ), /"name/" : /"Kyle/" }
可以看到,bsondump
默认将BSON输出为JSON。如果正进行重要的调试工作,你需要查看真正的BSON类型构成及大小。为此,以调试模式运行工具:
$ bsondump --type=debug users.bson--- new object --- size : 37 _id type: 7 size: 17 name type: 2 size: 15
该命令显示了对象的总大小(37字节)、两个字段的类型(7和2)以及那些字段的大小。