10.2 监控与诊断

04-13Ctrl+D 收藏本站

关灯 直达底部

在生产环境中部署完MongoDB,你就希望能了解它的运转情况。如果系统性能在慢慢下降或者经常发生故障,你希望能够知道这些情况,这就该用到监控了。让我们先从最简单的监控开始:日志。随后我们会看一些内置命令,它们能提供正在运行的MongoDB服务器的大多数信息;这些命令是mongostat工具和Web控制台的基础,我会对mongostat工具和Web控制台做个简要说明。我还会推荐几个外部监控工具。本节最后会介绍两个诊断工具:bsondumpmongosniff

10.2.1 日志

日志是第一级监控,正因如此,你应该计划保留所有部署的MongoDB的日志。1通常这都不是问题,因为MongoDB在后台运行时要求你指定--logpath选项。此外,还有一些需要留意的额外设置。要开启详细日志(verbose logging),在启动mongod进程时加上-vvvvv选项(v越多,输出越详细)。举例来说,如果需要调试一些代码,想要在日志里记录下每个查询,这就很方便。但是也要注意,详细日志会让日志文件变得很大,可能会影响服务器的性能。

1. 不要简单地通过管道将日志输出到/dev/nullstdout

其次,可以在启动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是进程所映射的虚拟内存的兆字节数,mappedvirtual的子集,标明那些内存里有多少是只用来映射数据文件的。本例中,有大约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数据库运行不同统计命令。serverStatusdbstatscollstats命令通常就能提供需要的所有信息,你能直接通过HTTP REST接口获得所有这些信息,不需要使用驱动。

10.2.4 诊断工具(mongosniffbsondump

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: -1
127.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)以及那些字段的大小。