MongoDB 通信协议

简介

MongoDB 通信协议是简单的基于套接字的请求响应风格的协议。客户端和数据库服务器通过长连接的 TCP/IP 套接字来进行交互。

套接字

客户端通过长连接的 TCP/IP 套接字来与数据库连接,没有连接握手阶段。

端口

mongodmongos进程默认端口号为 27017,此外端口是可以配置修改的。

字节序

MongoDB 通信协议的数据采用小端字节序

报文类型格式

报文类型有两种,客户端请求和数据库响应。

注解

  • 本文使用 C 语言风格的结构体来描述报文格式。
  • 文档中使用的类型如 (
    cstring
    ,
    int32
    , 等.) 对应于BSON 类型说明中的数据类型格式
    .
  • 文档中使用星号表示法来表示重复,例如 int64* 表示一个或多个 int64 类型(具体可见BSON 类型说明)可以被一个接一个的往套接字中写入。
  • 本文将标准头部命名为 MsgHeader。整型常量使用大写字母表示 (例如,ZERO 表示整型值 0)。

标准报文头

一般来说,每个消息包含一个标准的消息头紧随其后的是特定数据。标准的消息头的结构如下:

  1. struct MsgHeader {
  2. int32 messageLength; // 总报文大小,包含本字段
  3. int32 requestID; // 报文标识 ID
  4. int32 responseTo; // 数据库响应报文标识 ID,和 requestID 一样,
  5. // 表明响应回该 requestID 对应的请求
  6. int32 opCode; // 请求类型 - 具体参照下表
  7. }
字段 描述
messageLength 报文总长度,使用 4 个字节表示。
requestID 由客户端或服务器生成的报文唯一标识。 例如客户端请求 (OP_QUERYOP_GET_MORE), 将返回 OP_REPLY 报文给 responseTo 字段表示的请求. 客户端可以使用 requestIDresponseTo 字段关联查询响应到原始请求上。
responseTo 服务端响应使用此字段关联到 requestID 对应的查询请求上。
opCode 报文类型,详情见 请求操作码

请求操作码

注释

自 MongoDB 2.6 和maxWireVersion 3, MongoDB 驱动使用数据库命令insert,update, 和delete方式代替 OP_INSERT,OP_UPDATE, 和OP_DELETE操作码方式。许多驱动仍然在使用操作码方式。

重点

OP_COMMANDOP_COMMANDREPLY 是集群内部操作命令,不需要实现。

OP_COMMANDOP_COMMANDREPLY 操作协议格式是非固定的,不支持向后兼容。

协议支持的 操作码 (Opcode) 如下:

操作码 (Opcode) 名 注解
OP_REPLY 1 客户端请求回复。此操作 responseTo 会被设置为对应的 requestID 值。
OP_UPDATE 2001 更新文档。
OP_INSERT 2002 插入新文档。
RESERVED 2003 保留操作,以前用于 OP_GET_BY_OID。
OP_QUERY 2004 集合查询操作。
OP_GET_MORE 2005 OP_QUERY 后获取更多信息的后续操作。 详情见游标 (cursor)。
OP_DELETE 2006 删除文档。
OP_KILL_CURSORS 2007 用于通知数据库客户端游标已经操作完成,需销毁。
OP_COMMAND 2010 集群内部请求命令操作。
OP_COMMANDREPLY 2011 集群内部请求命令 OP_COMMAND 的响应。

客户端请求报文

客户端可以发送指定除OP_REPLYopCode以外的所有请求消息。OP_REPLY被保留供数据库使用。

只有OP_QUERYOP_GET_MORE消息导致数据库的响应。将不会有任何其他消息发送回应。

您可以使用getLastError命令确定消息是否成功。

OP_UPDATE

OP_UPDATE消息用于更新集合中的文档。OP_UPDATE消息的格式如下:

  1. struct OP_UPDATE {
  2. MsgHeader header; // 标准报文头
  3. int32 ZERO; // 0 - 保留给以后使用
  4. cstring fullCollectionName; // "dbname.collectionname"
  5. int32 flags; // 矢量位,见下表
  6. document selector; // 文档查询条件
  7. document update; // 指定要执行的更新
  8. }
字段 描述
header 消息头,如标准消息头中所述
ZERO 整数值为0.保留以备将来使用。
fullCollectionName 完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar
flags 位矢量指定操作的标志。位值对应于以下内容:0对应于Upsert。如果设置,如果没有找到匹配的文档,数据库将把提供的对象插入到集合中。1对应于MultiUpdate.If设置,数据库将更新集合中的所有匹配对象。否则只更新第一个匹配的文件。2-31保留。必须设置为0。
selector BSON文档,指定要更新的文档的选择查询。
update BSON文档,指定要执行的更新。有关指定更新的信息,请参阅MongoDB手册中的更新操作文档。

没有对OP_UPDATE消息的响应。

OP_INSERT

OP_INSERT消息用于将一个或多个文档插入到集合中。OP_INSERT消息的格式是

  1. struct {
  2. MsgHeader header; // 标准的报文头
  3. int32 flags; // 位向量 - 见下面
  4. cstring fullCollectionName; // "dbname.collectionname"
  5. document* documents; // 一个或多个要插入集合的文档
  6. }
字段 描述
header 消息头,如标准消息头中所述
flags 位矢量指定操作的标志。位值对应于以下内容:0对应于ContinueOnError。如果设置,数据库将不会停止处理批量插入,如果一个失败(例如由于重复的ID)。这使得批量插入的行为与一系列单个插入行为类似,只是如果任何插入失败,将会设置lastError,而不仅仅是最后一个。如果发生多个错误,则只有最近一次将由getLastError报告。(1.9.1新增)1-31保留。必须设置为0。
fullCollectionName 完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar
documents 一个或多个要插入到集合中的文档。如果有多个,它们会依次写入到插槽中。

对OP_INSERT消息没有响应。

OP_QUERY

OP_QUERY消息用于在数据库中查询集合中的文档。OP_QUERY消息的格式是:

  1. struct OP_QUERY {
  2. MsgHeader header; // 标准的报文头
  3. int32 flags; // 查询选项的位向量。详情请参阅下文。
  4. cstring fullCollectionName ; // "dbname.collectionname"
  5. int32 numberToSkip; // 要跳过的文件数
  6. int32 numberToReturn; // 表示第一个 OP_REPLY 响应中的文档返回数,
  7. document query; // 查询条件,见下表
  8. [ document returnFieldsSelector; ] // 用于限制返回文档的字段,见下表
  9. }
字段 描述
header 消息头,如标准消息头中所述
flags 位矢量指定操作的标志。位值对应于以下内容:0被预定了。必须设置为0。1对应于TailableCursor。Tailable表示当检索到最后一个数据时光标未关闭。而是光标标记最终对象的位置。如果收到更多的数据,可以稍后再从光标所在的位置继续使用光标。像任何“潜在游标”一样,游标可能在某个点(CursorNotFound)变成无效 - 例如,如果它引用的最终对象被删除。2对应于SlaveOk.Allow查询副本从属。通常这些返回一个错误,除了名字空间“本地”。3对应于OplogReplay。仅使用内部复制 - 不应设置驱动程序。4对应于NoCursorTimeout。闲置时间(10分钟)后,服务器通常超时闲置游标以防止使用过多内存。设置这个选项来防止这个。5对应于AwaitData。与TailableCursor一起使用。如果我们在数据的末尾,阻塞一段时间,而不是没有返回任何数据。超时后,我们照常返回。6对应于排气。假设客户端将完全读取所有查询的数据,将数据全部流式传输到多个“更多”包中。当你拉大量的数据,并知道你想把这一切拉下来,更快。注意:除非关闭连接,否则不允许客户端读取所有数据。7对应于部分。如果一些碎片落下(而不是抛出错误),从蒙哥马斯获得部分结果8-31保留。必须设置为0。
fullCollectionName 完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar
numberToSkip 当返回查询结果时,设置要省略的文档数量 - 从结果数据集中的第一个文档开始。
numberToReturn 将第一个OP_REPLY消息中的文档数限制为查询。但是,cursorID如果有更多的结果,数据库仍然会建立一个游标并返回给客户端numberToReturn。如果客户端驱动程序提供“限制”功能(如SQL LIMIT关键字),则由客户端驱动程序确保不超过指定数量的文档返回给调用应用程序。如果numberToReturn0,数据库将使用默认的返回大小。如果数字是负数,那么数据库将返回该数字并关闭游标。该查询没有进一步的结果可以获取。如果numberToReturn1服务器将把它作为-1(后自动关闭游标)。
query 表示查询的BSON文档。查询将包含一个或多个元素,所有这些元素都必须与要包含在结果集中的文档匹配。可能的因素包括$query$orderby$hint$explain,和$snapshot
returnFieldsSelector 可选的。BSON文件,限制返回的文件中的字段。所述returnFieldsSelector含有一种或多种元素,其中的每一个是应返回字段的名称,以及整数值1。在JSON符号,一个returnFieldsSelector限制的字段ab并且c将是:{ a :1 ,b :1 ,c :1 }

数据库将用OP_REPLY消息响应OP_QUERY消息。

OP_GET_MORE

OP_GET_MORE消息用于在数据库中查询集合中的文档。OP_GET_MORE消息的格式是:

  1. struct {
  2. MsgHeader header; // 标准报文头
  3. int32 ZERO; // 0 - 保留给以后使用
  4. cstring fullCollectionName; // "dbname.collectionname"
  5. int32 numberToReturn; // 返回的文档数量
  6. int64 cursorID; // cursorID 会在 OP_REPLY 中设置
  7. }
字段 描述
header 消息头,如标准消息头中所述
ZERO 整数值为0.保留以备将来使用。
fullCollectionName 完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar
numberToReturn 将第一个OP_REPLY消息中的文档数限制为查询。但是,cursorID如果有更多的结果,数据库仍然会建立一个游标并返回给客户端numberToReturn。如果客户端驱动程序提供了“限制”功能(如SQL LIMIT关键字),则由客户端驱动程序确保不超过指定数量的文档返回给调用应用程序。如果numberToReturn0,数据库将使用默认的返回大小。
cursorID 光标标识符出现在OP_REPLY中。这必须是来自数据库的值。

数据库将用OP_REPLY消息响应OP_GET_MORE消息。

OP_DELETE

OP_DELETE消息用于从集合中删除一个或多个文档。OP_DELETE消息的格式是:

  1. struct {
  2. MsgHeader header; // 标准报文头
  3. int32 ZERO; // 0 - 保留给以后使用
  4. cstring fullCollectionName; // "dbname.collectionname"
  5. int32 flags; // 矢量位,见下表
  6. document selector; // 查询过滤条件,见下表
  7. }
字段 描述
header 消息头,如标准消息头中所述
ZERO 整数值为0.保留以备将来使用。
fullCollectionName 完整的集合名称;即命名空间。完整的集合名称是数据库名称与集合名称.的拼接,使用一个for concatenation。例如,对于数据库foo和集合bar,完整的集合名称是foo.bar
flags 位矢量指定操作的标志。位值对应于以下内容:0对应于SingleRemove。如果设置,数据库将只删除集合中第一个匹配的文档。否则,所有匹配的文件将被删除。1-31保留。必须设置为0。
selector 代表用于选择要删除的文档的查询的BSON文档。选择器将包含一个或多个元素,所有这些元素都必须与要从集合中移除的文档匹配。

没有响应OP_DELETE消息。

OP_KILL_CURSORS

OP_KILL_CURSORS消息用于关闭数据库中的活动光标。这是确保在查询结束时回收数据库资源所必需的。OP_KILL_CURSORS消息的格式是:

  1. struct {
  2. MsgHeader header; // 标准报文头部
  3. int32 ZERO; // 0 - 保留以后使用
  4. int32 numberOfCursorIDs; // CursorID 数量
  5. int64* cursorIDs; // 需要关闭的游标
  6. }
字段 描述
header 消息头,如标准消息头中所述
ZERO 整数值为0.保留以备将来使用。
numberOfCursorIDs 消息中的光标ID的数量。
cursorIDs 游标ID的“数组”被关闭。如果有多个,它们会依次写入到插槽中。

如果游标被读取直到耗尽(读取直到OP_QUERYOP_GET_MORE为游标ID返回0),则不需要终止游标。

OP_COMMAND

警告

OP_COMMAND是集群内部的,不应该由客户端或驱动程序来实现。

OP_COMMAND格式和协议是不稳定的,而不保持向后兼容版本之间可能会改变。

OP_COMMAND是一个有线协议消息,用于在一个MongoDB服务器向另一个MongoDB服务器发出的集群内数据库命令请求。接收数据库发回一个OP_COMMANDREPLY作为对一个响应OP_COMMAND

  1. struct {
  2. MsgHeader header; // 标准报文头部
  3. cstring database; // 要运行该命令的数据库的名称
  4. cstring commandName; // 命令名称
  5. document metadata; // 命令描述信息
  6. document commandArgs; // 命令参数
  7. inputDocs; // 用于输入到命令的零个或多个文档
  8. }
字段 描述
header 标准消息头,如在标准消息头
database 要运行该命令的数据库的名称。
commandName 命令的名称。有关数据库命令的列表,请参阅数据库命令。
metadata 可用于系统将任何元数据附加到不属于命令参数本身的内部命令(由客户端驱动程序提供)
commandArgs 包含命令参数的BSON文档。有关commandName其参数的信息,请参阅文档
inputDocs 作为输入到命令的零个或多个文档。用于需要从客户端发送大量数据的命令,例如批量插入。

数据库响应报文

OP_REPLY

OP_REPLY消息由数据库发送,以响应OP_QUERYOP_GET_MORE消息。OP_REPLY消息的格式是:

  1. struct {
  2. MsgHeader header; // 标准报文头
  3. int32 responseFlags; // 适量位,见下表
  4. int64 cursorID; // 游标 id,在 OP\_GET\_MORE 时会被用到
  5. int32 startingFrom; // 光标起始位置
  6. int32 numberReturned; // 响应中的文档数量
  7. document* documents; // 响应文档
  8. }
字段 描述
header 消息头,如标准消息头中所述
responseFlags 位矢量指定标志。位值对应于以下内容:0对应于CursorNotFound。在getMore被调用时被设置,但是在服务器上的光标ID是无效的。返回零结果。1对应于QueryFailure。查询失败时设置。结果由一个包含描述失败的“$ err”字段的文档组成。2对应于ShardConfigStale。司机应该忽略这一点。只会mongos看到这个集合,在这种情况下,它需要从服务器更新配置。3对应于AwaitCapable。当服务器支持“等待数据查询”选项时设置。如果没有,客户端应该在Tailble游标的getMore之间稍微睡一会儿。Mongod版本1.6支持AwaitData,因此总是设置AwaitCapable。4-31保留。忽视。
cursorID cursorID是OP_REPLY的一部分。如果查询的结果集适合一个OP_REPLY消息,cursorID则该值为0.这cursorID必须在用于获取更多数据的任何OP_GET_MORE消息中使用,并且在不再需要时通过OP_KILL_CURSORS消息必须关闭。
startingFrom 光标起始位置。
numberReturned 响应中的文档数量。
documents 响应文档

OP_COMMANDREPLY

警告

OP_COMMANDREPLY是集群内部的,不应该由客户端或驱动程序来实现。

OP_COMMANDREPLY格式和协议是不稳定的,而不保持向后兼容版本之间可能会改变。

OP_COMMANDREPLY是一个有线协议消息,用于在内部响应由一个MongoDB服务器向另一个服务器发出的集群内OP_COMMAND请求。

格式OP_COMMANDREPLY是:

  1. struct {
  2. MsgHeader header; // 标准报文头
  3. document metadata; // 一个 BSON 格式的命令描述信息
  4. document commandReply; // 一个 BSON 格式的命令响应
  5. document outputDocs; // 返回内容文档
  6. }
字段 描述
header 标准消息头,如在[标准消息头]·(https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/#wp-message-header)。
metadata 可用于系统将任何元数据附加到不属于命令参数本身的内部命令(由客户端驱动程序提供)。
commandReply 包含命令回复的BSON文档。
outputDocs 用于可以返回大量数据的命令,如查找或聚合。这个字段目前没有被使用。