天天看点

mongodb3.0.0版本协议分析

作者:程序员在北京漂

最近项目使用 MongoDB ,刚好又用WireShark抓包分析一些问题。于是顺带了解一下客户端 和 mongodb 通信的过程,简单分析一下mongodb的协议。

介绍

MongoDB有线协议是一个简单的基于套接字的请求-响应 样式协议。客户端通过 常规 TCP/IP 套接字。

TCP/IP 套接字

客户端应使用常规 TCP/IP 套接字连接到数据库。

Port

默认端口号mongod和mongos实例为 27017。的端口号mongod和mongos是可配置的,可能会有所不同。

字节排序

MongoDB线协议中的所有整数都使用小端字节顺序: 也就是说,最低有效字节优先。

消息类型和格式

MongoDB 使用OP_MSG两个客户端的操作码 请求和数据库回复。有几种消息格式用于 旧版本的MongoDB已被弃用,取而代之的是.OP_MSG

注意:

  1. 此页面使用类似 C 来描述消息 结构。struct
  2. 本文档中使用的类型(、等)为 与cstringint32BSON 规格.
  3. 为了表示重复,文档使用来自 这BSON 规格. 例如,指示一个或多个 指定的类型可以一个接一个地写入套接字。int64*
  4. 标准邮件头键入为 。整数 常量以大写字母表示(例如 对于整数值 0).MsgHeaderZERO

标准消息头

通常,每个消息由一个标准消息头和特定于请求的数据组成。标准消息头的结构如下:

struct MsgHeader {

int32 messageLength; // total message size, including this

int32 requestID; // identifier for this message

int32 responseTo; // requestID from the original request

// (used in responses from db)

int32 opCode; // request type - see table below for details

}

字段含义:

messageLength 消息的总大小(以字节为单位)。此总数包括 4 个字节,用于保存消息长度。
requestID 客户端或数据库生成的标识符,该标识符唯一 标识此消息。对于客户端生成的情况 消息(例如OP_QUERY和OP_GET_MORE),它将在 的领域responseToOP_REPLY消息。客户端可以使用 和 字段将查询响应与 发起查询。requestIDresponseTo
responseTo 对于来自数据库的消息,这将取自requestIDOP_QUERY或OP_GET_MORE来自客户端的消息。 客户端可以使用 和 字段 将查询响应与原始查询相关联。requestIDresponseTo
opCode 消息类型。看请求操作码了解详情。

MongoDB 支持的 opCode 参考下表:

mongodb3.0.0版本协议分析

这一次我们主要关心OP_REPLY,OP_QUERY 和 OP_GET_MORE。下面我们分别查看一下这几个opCode的结构

OP_QUERY

Deprecated in MongoDB 5.0.

The OP_QUERY message is used to query the database for documents in a collection. The format of the OP_QUERY message is:

struct OP_QUERY {

MsgHeader header; // standard message header

int32 flags; // bit vector of query options. See below for details.

cstring fullCollectionName ; // "dbname.collectionname"

int32 numberToSkip; // number of documents to skip

int32 numberToReturn; // number of documents to return

// in the first OP_REPLY batch

document query; // query object. See below for details.

[ document returnFieldsSelector; ] // Optional. Selector indicating the fields

// to return. See below for details.

}

header 消息标头,如中所述标准邮件头。
flags 用于指定操作标志的位向量。位值 对应以下内容:
  • 0是保留的。必须设置为 0。
  • 1对应于 TailableCursor。可尾表示光标是 检索最后一个数据时未关闭。而是光标 标记最终对象的位置。您可以使用 光标稍后,从它所在的位置,如果更多数据 收到。像任何“潜在光标”一样,光标可能变成 在某些时候无效(CursorNotFound) - 例如,如果 它引用的最终对象被删除。
  • 2对应于奴隶确定。允许查询副本从属服务器。 通常,这些返回一个错误,命名空间“local”除外。
  • 3对应于OplogReplay。从MongoDB 4.4开始,你 不需要指定此标志,因为优化 对于对oplog的合格查询,自动发生。看oplog重播了解更多信息。
  • 4对应于 NoCursorTimeout。服务器正常 空闲游标在非活动期后超时(10 分钟) 以防止内存过多使用。设置此选项可防止出现这种情况。
  • 5对应于等待数据。与 TailableCursor 一起使用。如果我们 在数据的末尾,阻止一段时间而不是 不返回任何数据。超时期限后,我们返回为 正常。
  • 6对应于排气。全力以赴地流式传输数据 在多个“更多”包中,假设客户端 将完全读取查询的所有数据。拉动时速度更快 大量的数据,并且知道您想将其全部拉下来。注:该 不允许客户端不读取所有数据,除非 关闭连接。
  • 7对应于“部分”。从 如果某些分片关闭(而不是抛出错误),则为 mongos)
  • 8-31是保留的。必须设置为 0。
fullCollectionName 完整的集合名称;即命名空间。完整系列 name 是数据库名称与 集合名称,使用 a 作为串联。为 例如,对于数据库和集合, 完整的集合名称为 。.foobarfoo.bar
numberToSkip 设置要省略的文档数 - 从第一个开始 结果数据集中的文档 - 返回结果时 查询。
numberToReturn 限制第一个中的文档数OP_REPLY消息到查询。但是,数据库 仍将建立游标并返回 客户端(如果结果多于 )。如果 客户端驱动程序提供“限制”功能(如 SQL LIMIT 关键字),则由客户端驱动程序确保没有 超过指定数量的文档将返回到 调用应用程序。如果是,则数据库将 使用默认返回大小。如果数字为负数,则 数据库将返回该数字并关闭光标。没有进一步 可以获取该查询的结果。如果是,服务器会将其视为(关闭光标 自动)。cursorIDnumberToReturnnumberToReturn0numberToReturn1-1
query 表示查询的 BSON 文档。查询将包含 一个或多个元素,所有这些元素都必须与文档匹配 包含在结果集中。可能的元素包括 、 、 和 。$query$orderby$hint$explain
returnFieldsSelector 自选。限制返回的字段中字段的 BSON 文档 文件。包含一个或多个 元素,每个元素都是应为 返回,和整数值 。在 JSON 表示法中,a 限制为字段 ,并且将是:returnFieldsSelector1returnFieldsSelectorabc
{ a : 1, b : 1, c : 1}           

数据库OP_QUERY将使用OP_REPLY消息。

OP_REPLY

在MongoDB 5.0中已弃用。

该消息由数据库发送,以响应OP_REPLYOP_QUERY或OP_GET_MORE消息。OP_REPLY消息的格式为:

struct {
MsgHeader header; // standard message header
int32 responseFlags; // bit vector - see details below
int64 cursorID; // cursor id if client needs to do get more's
int32 startingFrom; // where in the cursor this reply is starting
int32 numberReturned; // number of documents in the reply
document* documents; // documents
}
header 消息标头,如中所述标准邮件头。
responseFlags 用于指定标志的位向量。位值 对应以下内容:
  • 0对应于 CursorNotFound。在 已调用,但游标 ID 在服务器上无效。返回 结果为零。getMore
  • 1对应于查询失败。在查询失败时设置。 结果包含一个包含“$err”字段的文档 描述故障。
  • 2对应于 ShardConfigStale。驱动程序应忽略 这。只mongos将永远看到这套,其中 在这种情况下,它需要从服务器更新配置。
  • 3对应于等待能力。在服务器时设置 支持“等待数据查询”选项。如果没有,则客户端 应该在可尾光标的 getMore 之间睡一会儿。 Mongod 版本 1.6 支持 AwaitData,因此始终设置 等待能力。
  • 4-31是保留的。忽视。
cursorID 这个OP_REPLY是其中的一部分。在事件中 查询的结果集适合一条OP_REPLY消息,将为 0。这必须在任何cursorIDcursorIDcursorIDOP_GET_MORE用于获取更多信息的消息 数据,并且当不再时也必须由客户端关闭 需要通过OP_KILL_CURSORS消息。
startingFrom 光标中的起始位置。
numberReturned 答复中的文档数。
documents 退回的文档。

OP_GET_MORE

在MongoDB 5.0中已弃用。

OP_GET_MORE消息用于在数据库中查询 收集。OP_GET_MORE消息的格式为:

struct {

MsgHeader header; // standard message header

int32 ZERO; // 0 - reserved for future use

cstring fullCollectionName; // "dbname.collectionname"

int32 numberToReturn; // number of documents to return

int64 cursorID; // cursorID from the OP_REPLY

}

header 消息标头,如中所述标准邮件头。
ZERO 整数值为 0。保留供将来使用。
fullCollectionName 完整的集合名称;即命名空间。完整系列 name 是数据库名称与 集合名称,使用 a 作为串联。为 例如,对于数据库和集合, 完整的集合名称为 。.foobarfoo.bar
numberToReturn 限制第一个中的文档数OP_REPLY消息到查询。但是,数据库 仍将建立游标并返回 客户端(如果结果多于 )。如果 客户端驱动程序提供“限制”功能(如 SQL LIMIT 关键字),则由客户端驱动程序确保没有 超过指定数量的文档将返回到 调用应用程序。如果是,则数据库将 使用默认返回大小。cursorIDnumberToReturnnumberToReturn0
cursorID 游标标识符出现在OP_REPLY.这一定是来自 数据库。

数据库OP_GET_MORE将使用OP_REPLY消息。

通过wireshark抓包工具抓包分析:

  1. 登陆包

1.1Package

mongodb3.0.0版本协议分析

数据包:

0000 81 01 00 00 0d 12 00 00 00 00 00 00 d4 07 00 00 ............Ô...

0010 00 00 00 00 61 64 6d 69 6e 2e 24 63 6d 64 00 00 ....admin.$cmd..

0020 00 00 00 01 00 00 00 5a 01 00 00 08 69 73 6d 61 .......Z....isma

0030 73 74 65 72 00 01 03 63 6c 69 65 6e 74 00 08 01 ster...client...

0040 00 00 03 64 72 69 76 65 72 00 2b 00 00 00 02 6e ...driver.+....n

0050 61 6d 65 00 07 00 00 00 6e 6f 64 65 6a 73 00 02 ame.....nodejs..

0060 76 65 72 73 69 6f 6e 00 08 00 00 00 33 2e 32 2e version.....3.2.

0070 37 2d 32 00 00 03 6f 73 00 58 00 00 00 02 74 79 7-2...os.X....ty

0080 70 65 00 0b 00 00 00 57 69 6e 64 6f 77 73 5f 4e pe.....Windows_N

0090 54 00 02 6e 61 6d 65 00 06 00 00 00 77 69 6e 33 T..name.....win3

00a0 32 00 02 61 72 63 68 69 74 65 63 74 75 72 65 00 2..architecture.

00b0 04 00 00 00 78 36 34 00 02 76 65 72 73 69 6f 6e ....x64..version

00c0 00 0b 00 00 00 31 30 2e 30 2e 32 32 36 32 31 00 .....10.0.22621.

00d0 00 02 70 6c 61 74 66 6f 72 6d 00 2c 00 00 00 4e ..platform.,...N

00e0 6f 64 65 2e 6a 73 20 76 31 30 2e 31 31 2e 30 2c ode.js v10.11.0,

00f0 20 4c 45 2c 20 6d 6f 6e 67 6f 64 62 2d 63 6f 72 LE, mongodb-cor

0100 65 3a 20 33 2e 32 2e 37 2d 32 00 03 61 70 70 6c e: 3.2.7-2..appl

0110 69 63 61 74 69 6f 6e 00 2d 00 00 00 02 6e 61 6d ication.-....nam

0120 65 00 1e 00 00 00 4e 6f 53 51 4c 42 6f 6f 73 74 e.....NoSQLBoost

0130 65 72 56 35 2e 32 2e 31 32 5f 31 30 34 34 36 2e erV5.2.12_10446.

0140 31 33 36 00 00 00 04 63 6f 6d 70 72 65 73 73 69 136....compressi

0150 6f 6e 00 05 00 00 00 00 02 73 61 73 6c 53 75 70 on.......saslSup

0160 70 6f 72 74 65 64 4d 65 63 68 73 00 10 00 00 00 portedMechs.....

0170 61 64 6d 69 6e 2e 72 6f 6f 74 32 32 32 32 32 00 admin.root22222.

0180 00 .

81 01 00 00

位置:0,3

含义:数据包长度

d4 07 00 00

位置:12-15;

含义:opCode:query(2004)

73 61 73 6c 53 75 70 70 6f 72 74 65 64 4d 65 63 68 73 00

含义:saslSupportedMechs

10 00 00 00

含义:长度

61 64 6d 69 6e 2e 72 6f 6f 74 32 32 32 32 32

含义:验证数据库.用户名

1.find查询

1.1、Sql

db.studend.find()//单行注释

1.2、Package

mongodb3.0.0版本协议分析

0000 3d 00 00 00 ff 05 00 00 00 00 00 00 d4 07 00 00 =...ÿ.......Ô...

0010 00 00 00 00 74 61 72 67 65 74 2e 73 74 75 64 65 ....target.stude

0020 6e 64 00 00 00 00 00 e8 03 00 00 12 00 00 00 03 nd.....è........

0030 24 71 75 65 72 79 00 05 00 00 00 00 00 $query.......

1.3、Analyse分析

3d 00 00 00

位置:0,3

含义:数据包长度

d4 07 00 00

位置:12-15;

含义:opCode:query(2004)

74 61 72 67 65 74 2e 73 74 75 64 65 6e 64 00

位置:20 – 第一个00

含义:完整集合名称 dbname. Collectionname

fullCollectionName:target.student

位置:00

含义:结束位

12 00 00 00

含义:query总长度

03

含义:数据类型:Type:Document(0x03)

24 71 75 65 72 79 00

含义:$query 查询

1.4 响应包

mongodb3.0.0版本协议分析

这次先到这吧,参考官方文档获取更详细的信息

协议介绍官方文档地址:

https://docs.mongodb.com/v5.0/reference/mongodb-wire-protocol/#std-label-wire-op-msg