第 20 章 启动和停止MongoDB

我们在第2章中学习了有关启动MongoDB的基本命令。本章我们将就生产环境中配置MongoDB的重要选项展开深入的学习,内容包括:

  • 常用选项;
  • 启动和停止MongoDB;
  • 安全相关选项;
  • 使用日志时的注意事项。

20.1 从命令行启动

执行mongod程序即可启动MongoDB服务器,mongod在启动时可使用许多可配置选项,在命令行中运行mongod --help可列出这些选项。下列选项十分常用,需着重注意。

  • --dbpath

    使用此选项可指定一个目录为数据目录。其默认值为/data/db/(在Windows中则为MongoDB可执行文件所在磁盘卷中的\data\db目录)。机器上的每个mongod进程都需要属于自己的数据目录,即若在同一机器上运行三个mongod实例,则需三个独立的数据目录。mongod启动时,会在其数据目录中创建一个mongod.lock文件,以阻止其他mongod进程使用此数据目录。若尝试启动另一个使用相同数据目录的MongoDB服务器,则会出现错误提示:

"Unable to acquire lock for lockfilepath: /data/db/mongod.lock."

  • --port

    此选项用以指定服务器监听的端口号。mongod默认占用27017端口,除其他mongod进程外,其余程序不会使用此端口。若要在同一机器上运行多个mongod进程,则需为它们指定不同的端口。若尝试在已被占用的端口启动mongod,则会出现错误提示:

    "Address already in use for socket: 0.0.0.0:27017"

  • --fork

    启用此选项以调用fork创建子进程,在后台运行MongoDB。

首次启动mongod而数据目录为空时,文件系统需几分钟时间分配数据库文件。预分配结束,mongod可接收连接后,父进程才会继续运行。因此,fork可能会发生挂起。可查看日志中的最新记录得知正在进行的操作。启用--fork选项时,必须同时启用--logpath选项。

  • --logpath

    使用此选项,所有输出信息会被发送至指定文件,而非在命令行上输出。假设我们拥有该目录的写权限,若指定文件不存在,启用该选项后则会自动生成一个文件。若指定日志文件已存在,选项启用后则会覆盖掉该文件,并清除所有旧的日志条目。如需保留旧日志,除--logpath选项外,强烈建议使用--logappend选项。

  • --directoryperdb

    启用该选项可将每个数据库存放在单独的目录中。我们可由此按需将不同的数据库挂载到不同的磁盘上。该选项一般用于将本地数据库或副本放置于单独的磁盘上,或在磁盘空间不足时将数据库移动至其他磁盘。也可将频繁操作的数据库挂载到速度较快的磁盘上,而将不常用的数据库放到较慢的磁盘上。总之该选项能使我们在今后更加灵活地操作数据库。

  • --config

    额外加载配置文件,未在命令行中指定的选项将使用配置文件中的参数。该选项通常用于确保每次重新启动时的选项都是一样的。详细内容请参见20.1.1节。

例如,要在后台启动一个服务器,监听5586端口,并将所有输出信息发送至mongodb.log文件中,可运行如下命令:

  1. $ ./mongod --port 5586 --fork --logpath mongodb.log --logappend
  2. forked process: 45082
  3. all output going to: mongodb.log

注意,mongod可能在意识到自身启动前,便开始预配置日志文件。这时,直到预配置完成,fork命令才会返回命令提示符。可查看mongodb.log文件(或重定向日志文件)末尾,观察这一操作过程。

首次安装启动MongoDB时,应查看一下日志。这一点很容易被忽视,尤其是使用初始化脚本来启动MongoDB的时候。但日志中常包含重要的警告信息,及时解决这些问题可预防随之而来的错误。如启动时没有出现任何警告,那么就一切就绪了。(启动时发出的警告信息会同时出现在shell里。)

如在启动时出现了警告信息,应把它们记录下来。MongoDB会因以下问题发出警告:运行于32位的机器上(MongoDB并非为32位机器设计);启用了NUMA(Non-Uniform Memory Access,非均匀访存模型,启用此会严重拖慢应用的运行速度);或者系统所允许打开的文件描述符(descriptor)数目过少(MongoDB需使用大量的文件描述符)。

重启数据库时,日志的前部不会发生更改,所以一旦了解了日志内容,就完全可以使用初始化脚本来运行MongoDB,而不用去考虑日志。然而,在安装、升级,或从崩溃中恢复后,都应重新检查日志,以确保MongoDB和系统相契合。

启动数据库时,MongoDB会将一个文档写入local.startup_log集合中,该集合包含了 MongoDB的版本、其所基于的系统,以及所用的标记:

  1. > db.startup_log.findOne()
  2. {
  3. "_id" : "spock-1360621972547",
  4. "hostname" : "spock",
  5. "startTime" : ISODate("2013-02-11T22:32:52Z"),
  6. "startTimeLocal" : "Mon Feb 11 17:32:52.547",
  7. "cmdLine" : {
  8. },
  9. "pid" : 28243,
  10. "buildinfo" : {
  11. "version" : "2.4.0-rc1-pre-",
  12. ...
  13. "versionArray" : [
  14. 2,
  15. 4,
  16. 0,
  17. -9
  18. ],
  19. "javascriptEngine" : "V8",
  20. "bits" : 64,
  21. "debug" : false,
  22. "maxBsonObjectSize" : 16777216
  23. }
  24. }

该集合可用于跟踪数据库升级或更改后的运行状况。

使用配置文件

MongoDB支持从文件中读取配置信息。当使用的选项很多,或自动化启动任务时,使用配置文件就十分实用。使用-f--config标记,告知服务器使用配置文件。例如,运行mongod --config ~/.mongodb.conf,从而使用~/.mongodb.conf作为配置文件。

配置文件中支持的参数和在命令行中的参数完全相同。以下是一个配置文件的例子:

  1. # Start MongoDB as a daemon on port 5586
  2. port = 5586
  3. fork = true # daemonize it!
  4. logpath = /var/log/mongodb.log
  5. logappend = true

该配置文件指定的参数与之前启动时在命令行中指定的参数相同。文件中也展现了MongoDB配置文件的主要内容:

  • 后的内容,会被作为注释忽略掉;

  • 指定参数的语法是option = value,其中option的名称区分大小写;
  • 在命令行中类似--fork的开关选项,应把fork的值设为true

20.2 停止MongoDB

安全停止运行中的MongoDB服务器,与安全启动该服务器一样重要。有若干不同选项可有效地完成这一操作。

关闭运行中的服务器,最简洁的方法是使用shutdown命令——{"shutdown" : 1}。这是一个管理员命令,必须运行在admin数据库上。shell提供了一个辅助函数,用以简单地执行shutdown命令:

  1. > use admin
  2. switched to db admin
  3. > db.shutdownServer()
  4. server should be down...

在主节点(primary)上运行shutdown命令时,服务器在关闭前,会先等待备份节点(secondary)追赶(catch up)主节点以保持同步。这将回滚的可能性降至最低,但shutdown操作有失败的可能性。如几秒钟内没有备份节点成功同步,则shutdown操作失败,主节点亦不会停止运行:

  1. > db.shutdownServer()
  2. {
  3. "closest" : NumberLong(1349465327),
  4. "difference" : NumberLong(20),
  5. "errmsg" : "no secondaries within 10 seconds of my optime",
  6. "ok" : 0
  7. }

可使用force选项,强制关闭主节点:

  1. db.adminCommand({"shutdown" : 1, "force" : true})

这相当于发送一个SIGINT或SIGTERM信号(三种做法都能使MongoDB安全地停止运行,但可能会有数据未能完成同步)。如服务器正在终端中作为前台进程运行,那么按下Ctrl-C快捷键也能发送一个SIGINT信号。另外,kill之类的命令也可用于发送这些信号。假设mongod的 PID(Process identifier,进程标识符)为10014,那么相应的命令就是kill -2 10014(发送 SIGINT信号)或kill 10014(发送SIGTERM信号)。

mongod收到SIGINT或SIGTERM信号后,会安全地停止运行。这意味着mongod会等当前正在进行的操作或文件预分配结束(耗时一定时间),再关闭所有打开的连接,将缓存写入磁盘,继而结束运行。

20.3 安全性

不要将MongoDB服务器直接暴露在外网上。应尽可能地限制外部对MongoDB的访问。最好的方式是设置防火墙,只允许内部网络地址对MongoDB的访问。第23章介绍了MongoDB服务器与客户端间的必要连接。

除使用防火墙外,也可在配置文件中加入以下选项来增强安全性。

  • --bind_ip

指定MongoDB监听的接口。我们通常将其设置为一个内部IP地址,从而保证应用服务器和集群中其他成员的访问,同时拒绝外网的访问。如MongoDB与应用服务器运行于同一台机器上,则可将其设为localhost。但配置服务器和分片需要其他机器的访问,所以不应设为localhost

  • --nohttpinterface

MongoDB启动时,默认在端口1000启动一个微型的HTTP服务器。该服务器可提供一些系统信息,但这些信息均可在其他地方找到。对于一个可能只需通过SSH访问的机器,没有必要将这些信息暴露在外网上。

除非正在进行开发,否则请关闭此选项。

  • --nounixsocket

如不打算使用UNIX socket来进行连接,则可禁用此选项。只有在本地,即应用服务器和MongoDB运行在同一台机器上时,才能使用socket进行连接。

  • --noscripting

该选项完全禁止服务器端JavaScript脚本的运行。大多数报告的MongoDB安全问题都与 JavaScript有关。如程序允许的话,禁止JavaScript通常会更安全一些。

一些shell中的辅助函数依赖于服务器端的JavaScript,尤其是sh.status()。在一台禁止了JavaScript的服务器上运行这些辅助函数时,会出现错误提示。

不要启用REST操作界面。该界面是默认禁用的,开启后可在服务器上执行很多命令,但并非为生产环境所设计。

20.3.1 数据加密

截止至撰写本书时,MongoDB还未提供内置数据加密机制。如需对数据进行加密,可使用加密文件系统。另一种做法是手动加密某些字段,但MongoDB无法查询加密的值。

20.3.2 SSL安全连接

连接至MongoDB传输的数据默认不被加密。然而,MongoDB支持使用SSL连接。由于授权的原因,默认版本中并未包含SSL,可从http://www.10gen.com下载一个支持SSL的版本。也可以自己编译MongoDB的源代码启用SSL。请查阅本国语言的驱动程序文档,了解创建SSL连接的方法。

20.4 日志

mongod默认将日志发送至stdout(标准输出,通常为终端)。大多初始化脚本会使用--logpath选项,将日志发送至文件。如在同一台机器上有多个MongoDB实例(比如说一个mongod和一个mongos),注意保证各实例的日志分别存放在单独的文件中。确保知道日志的存放位置,并拥有文件的读访问权限。

MongoDB会输出大量日志消息,但请不要使用--quiet选项(该选项会隐藏部分日志消息)。保持日志级别为默认值通常不错,此时日志中有足够的信息进行基本调试(如耗时过长或启动异常的原因等),但日志占用的空间并不大。调试应用某特定问题时,可使用一些选项从日志中获取更多信息。

首先,在重启MongoDB时,可通过在参数中附加数目更多的“v”(即 -v、-vv、-vvv、-vvvv或 -vvvvv),或运行如下setParameter命令,完成日志级别(log level)的更改。

  1. > db.adminCommand({"setParameter" : 1, "logLevel" : 3})

记得将日志级别重设为0,否则日志中会存在过多不必要的内容。可将日志级别调高至5,这时 mongod会在日志中记录几乎所有的操作,包括每一个请求所处理的内容。由于mongod将所有内容都写入了日志文件,因此可产生大量的磁盘读写操作(IO),从而拖慢一个忙碌的系统。如需即时看到正在进行的所有操作,打开分析器不失为更好的方法:

MongoDB默认记录耗时超过100毫秒的查询信息。如100毫秒不适用于应用,可通过 setProfilingLevel命令来更改此阈值:

  1. > // Only log queries that take longer than 500ms (只记录耗时超过500毫秒的查询操作)
  2. > db.setProfilingLevel(1, 500)
  3. { "was" : 0, "slowms" : 100, "ok" : 1 }
  4. > db.setProfilingLevel(0)
  5. { "was" : 1, "slowms" : 500, "ok" : 1 }

上述第二条指令将关闭分析器,但第一条指令中以毫秒为单位的值将继续作为所有数据库中日志记录的阈值而生效。也可使用--slowms选项重启MongoDB来更改这一阈值。

最后,设置一个计划任务以便每天或每周分割(rotate)日志文件。如使用--logpath选项启动MongoDB,向进程发送一个SIGUSR1信号即使其对日志进行分割。也可使用logRotate命令以达到相同目的:

  1. > db.adminCommand({"logRotate" : 1})

如不是通过--logpath选项启动的MongoDB,则不能对日志进行分割。