MongoDB是用C++编写的,由10gen积极维护。该项目能在所有主流操作系统上编译,包括Mac OS X、Windows和大多数Linux。mongodb.org上提供了这些平台的预编译二进制包。MongoDB是开源的,遵循GNU-AGPL许可,GitHub上可以免费获取到源代码,而且经常会接受来自社区的贡献,但这一项目主要还是由10gen的核心服务器团队来领导的,绝大多数提交亦来自该团队。
GNU-AGPL
GNU-AGPL是一个颇受争议的许可。实践中,它表示源代码能被免费获取,而且它鼓励社区的贡献。GNU-AGPL的主要局限是,出于社区的利益,任何对源代码的修改都必须公布出来。对于那些想保护其核心服务器增强特性的公司来说,10gen提供了特殊的商业许可。
MongoDB 1.0发布于2009年11月。基本每三个月人们便发布它的一个主要版本,偶数发行号1代表稳定分支,奇数代表开发分支。在本书编写时,最新版本是v2.02。
1. release number,即版本号中的第二个数字。——译者注2. 你应该总是使用稳定版本,例如2.0.1版。
下文概述了MongoDB自带的组件,并粗略描述了工具和面向MongoDB开发应用程序所需的语言驱动。
1.3.1 核心服务器
通过可执行文件mongod
(Windows上是mongodb.exe)可以运行核心服务器。mongod
服务器进程使用一个自定义的二进制协议从网络套接字上接收命令。mongod
进程的所有数据文件默认都存储在/data/db3里。
3. Windows里是c:datadb。
mongod
有多种运行模式,最常见的是作为副本集中的一员。因为推荐使用复制,通常副本集由两个副本组成,再加一个部署在第三台服务器上的仲裁进程4(arbiter process)。对于MongoDB的自动分片架构而言,其组件包含配置为预先分片的副本集的mongod
进程,以及特殊的元数据服务器,称为配置服务器(config server)。另外还有单独的名为mongos
的路由服务器向适当的分片发送请求。
4. 这些仲裁进程都是轻量级的,也就是说能方便地运行在应用服务器上。
相比其他的数据库系统,例如MySQL,配置一个mongod
进程相对比较简单。虽然可以指定标准端口和数据目录,但没有什么调优数据库的选项。在大多数RDBMS中,数据库调优意味着通过一大堆参数来控制内存分配等内容,这已经变成了一门黑魔法。MongoDB的设计哲学指出,内存管理最好是由操作系统而非DBA或应用程序开发者来处理。如此一来,数据文件通过mmap
系统调用被映射成了系统的虚拟内存。这一举措行之有效地将内存管理的重任交给了操作系统内核。本书中我还会更多地阐述与mmap
相关的内容,不过目前你只需要知道缺少配置参数是一个系统设计亮点,而非缺陷。
1.3.2 JavaScript Shell
MongoDB命令行Shell是一个基于JavaScript的工具,用于管理数据库和操作数据。可执行文件mongo会加载Shell并连接到指定的mongod
进程。MongoDB Shell的功能和MySQL Shell差不多,主要的区别在于不使用SQL,大多数命令使用的是JavaScript表达式。举例来说,可以像下面这样选择一个数据库,向users
集合中插入一个简单的文档:
> use mongodb-in-action> db.users.insert({name: /"Kyle/"})
第一条命令指明了想使用哪个数据库,MySQL的用户一定不会对此感到陌生。第二条命令是一个JavaScript表达式,插入一个简单的文档。要查看插入的结果,可以使用以下查询:
> db.users.find{ _id: ObjectId(/"4ba667b0a90578631c9caea0/"), name: /"Kyle/" }
find
方法返回了之前插入的文档,其中添加了一个对象ID。所有文档都要有一个主键,存储在_id
字段里。只要能保证唯一性,也可以输入一个自定义_id
。如果省略了_id
,则会自动插入一个MongoDB对象ID。
除了可以插入和查询数据,Shell还可以用于运行管理命令。例如,查看当前数据库操作、检查到从节点的复制状态,以及配置一个用于分片的集合。如你所见,MongoDB Shell着实是一个强大的工具,值得好好掌握。
说了这么多,你那些和MongoDB相关的大量工作都是通过特定编程语言编写的应用程序来完成的。想知道这究竟是如何办到的,必须先了解一下MongoDB语言驱动。
1.3.3 数据库驱动
如果之前把数据库驱动想象成捣腾低级设备的梦魇,那你大可放心,MongoDB的驱动很容易使用。MongoDB团队竭尽全力在提供符合特定语言风格的API,并同时保持跨语言的、相对统一的接口。举例来说,所有驱动都实现了向集合保存文档的类似方法,但不同语言里文档本身的表述通常会有所不同,驱动尽量会对特定语言表现得更自然一些。例如,在Ruby中就是使用一个Ruby散列,在Python中字典更合适一点,Java中缺少类似的语言原语,需要用一个实现了 LinkedHashMap
的特殊文档构建器类来表示文档。
因为驱动程序为数据库提供了一个以语言为中心的富接口,在构建应用程序时几乎不再需要驱动程序之外的抽象了。这与使用RDBMS的应用程序设计截然不同,在数据库的关系型数据模型和大多数现代编程语言的面向对象模型之间几乎都需要有一个库来做中介。虽然不需要对象关系映射器(object-relational mapper),但很多开发者都喜欢在驱动上做一层薄薄的封装,用它来处理关联、验证和类型检查5。
5. 在本书编写时,一些流行的包装器包括Java的Morphia、PHP的Doctrine以及Ruby的MongoMapper。
本书编写时,10gen官方支持C、C++、C#、Erlang、Haskell、Java、Perl、PHP、Python、Scala和Ruby的驱动,而且这个列表还在不断增长。如果你需要支持其他语言,通常都会有一个社区支持的驱动。如果对于某语言还没有社区支持的驱动,mongodb.org的文档里有用于构建新驱动的规范。官方支持的驱动被大量使用在生产环境中,而且这些驱动都遵循Apache许可,因此想要编写驱动的人可以免费获取到大量优秀的示例。
从第3章开始,我会描述驱动是如何工作的,以及如何使用它们编写程序。
1.3.4 命令行工具
MongoDB自带了很多命令行工具。
mongodump
和mongorestore
,备份和恢复数据库的标准工具。mongodump
用原生的BSON格式将数据库的数据保存下来,因此最好只是用来做备份,其优势是热备时非常有用,备份后能方便地用mongorestore
恢复。mongoexport
和mongoimport
,用来导入导出JSON、CSV和TSV数据,数据需要支持多种格式时很有用。mongoimport
还能用于大数据集的初始导入,但是在导入前顺便还要注意一下,为了能充分利用好MongoDB通常需要对数据模型做些调整。在这种情况下,通过使用驱动的自定义脚本来导入数据会更方便一些。mongosniff
,这是一个网络嗅探工具,用来观察发送到数据库的操作。基本就是把网络上传输的BSON转换为易于人们阅读的Shell语句。mongostat
,与iostat
类似,持续轮询MongoDB和系统以便提供有帮助的统计信息,包括每秒操作数(插入、查询、更新、删除等)、分配的虚拟内存数量以及服务器的连接数。
稍后会在书中讨论另外两个工具:bsondump
和mongofiles
。