Skip to content

Commit

Permalink
mysql docs
Browse files Browse the repository at this point in the history
  • Loading branch information
fengzhao committed Nov 1, 2024
1 parent 0e34da0 commit 79151ad
Showing 1 changed file with 81 additions and 6 deletions.
87 changes: 81 additions & 6 deletions docs/foundmental/1.MySQL协议分析与抓包概述.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,32 @@ MySQL 客户端和服务器之间的通信怎么实现?协议特征有哪些

- 错误处理:MySQL 协议支持服务器返回错误信息,包括错误代码和错误描述,以便客户端处理异常情况。

- 安全连接:MySQL 协议支持通过 SSL/TLS 进行通信加密,保护会话数据的安全性。
- 安全连接:MySQL 协议支持通过 `SSL/TLS` 进行通信加密,保护会话数据的安全性。

- 广泛使用 flag 标记位:在握手阶段的登录请求响应报文中包含了服务端能力flag字段,以及业务通讯中的数据报文中也可以包含服务器状态flag标记位。


#### 数据包格式

MySQL的客户端和服务端交互是以数据包(Packet) 为单位进行的, 每个包的大小长度有限制, 最长为 2^24 -1 个字节(即 16MB)。`max_allowed_packet` 表示 MySQL Server 或者客户端接收的 packet 的最大大小,packet 即数据包,MySQL Server 和客户端上都有这个限制。**注意,这里说的数据包大小是指 MySQL 应用层对数据的约定,在网络协议封装中,TCP 层和 IP 层各自都有各自的单个数据报文限制,即 MTU 和 MSS 等**

若包长度过大, 则客户端需要自行将包分片, 使得每段的长度在 MySQL 包的最大长度之下, MySQL Packet 由 Header 和 Body 组成, Header 包含两个字段: 包长度(payload_length)、序列号(sequence_id), Body 则是包的主体部分, 它的长度由 Header 中的 payload_length 字段指示, 包长度字段固定使用 int<3> 类型, 序列号固定使用 int<1> 类型, 当客户端和服务端开始交互时, 由客户端初始化 0 序列号, 之后每次交互, 数据发出方都基于前一个 sequence_id 增一, sequence_id 不是恒定唯一的, 当交互次数足够多后, 它会重新回到 0。



| 名称 | 数据类型 | 占用空间 | 解析 | |
| ------------------------------- | -------- | -------- | ------ | ---- |
| Packet Length(payload_length) | int<3> | 3byte | 包长 | |
| sequence_id | int<1> | | 包序号 | |
| payload | | | | |

因为前三个字节最大只能表达16M的长度,这是三个字节表达无符号整型的极限,所以,每次客户端可以接受到的单个最大数据包为16M+4个字节。

对于`payload`部分大于等于16MB的,MySQL会将数据进行切分,每16MB为一部分,然后将切分的数据按照数据包的格式封装,进行发送,直到切分的数据部分长度小于16MB。







Expand Down Expand Up @@ -216,6 +241,58 @@ MySQL 连接的方式有多种, 比如 TCP/IPv4、TCP/IPv6、UNIX domain sockets





#### 命令执行阶段

命令执行阶段在官网文档中,叫 `Command Phase`。在这个阶段,就有点像 HTTP 的请求响应这种一问一答的通信模型。

首先,客户端发送一个序号(sequence-id)为0的首包。



##### 客户端命令请求报文

客户端可以发送各种不同类型的命令包,payload中的第一个byte描述`command-type`。这个type在include/my_command.h中以enum_server_command枚举方式定义

命令:用于标识当前请求消息的类型,例如切换数据库(0x02)、查询命令(0x03)等。命令值的取值范围及说明如下表(参考MySQL源代码/include/mysql_com.h头文件中的定义。




在官网中,把这些类型分为`Text Protocol`,`Utility Commands`,`Prepared Statements`,`Stored Programs`

其中,最主要的是 `COM_QUERY` 消息报文,这个是最常见的请求消息类型,当用户执行SQL语句时发送该消息。


##### 回包报文

常见MySQL返回的报文有`Data Packet`, `OK Packet`, `EOF Packe`t`, 和`ERROR Packet`。回包格式主要取决于查询是否需要返回结果集。

对于诸如 `COM_PING`, `IUD Query` 等不需要返回结果集的命令, 以及连接阶段的登录成功。`MySQL server`如果正确执行这个查询, 会返回 OK 报文给 client。





**OK Packet**

对于OK包,在 `sql/protocol_classic.cc -> net_send_ok()` 函数中定义的数据包结构。[The Payload of an OK Packet](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html)

在5.7.5版本之后,OK Packet也可以用于表示EOF信息,原先的 EOF_Packet被废弃了。

- 如果 header = 0x00 并且packer 长度大于7,说明这个包是 OK 数据包
- 如果 header = 0xFE 并且 packer 长度小于9,说明这个包是 EOF 包

如果设置了`CLIENT_PROTOCOL_41`标记位,即MySQL 版本大于4.1。 该数据包包含一个警告计数。








### 协议数据类型

协议数据类型是与语言无关的数据类型, 可以理解为 `wire type`, 它们是网络字节流中的数据类型。
Expand All @@ -228,10 +305,6 @@ MySQL 连接的方式有多种, 比如 TCP/IPv4、TCP/IPv6、UNIX domain sockets

### 数据包格式

MySQL 的客户端和服务端交互是以数据包(Packet) 为单位进行的, 每个包的大小长度有限制, 最长为 2^24 -1 个字节(即 16MB)。`max_allowed_packet` 表示 MySQL Server 或者客户端接收的 packet 的最大大小,packet 即数据包,MySQL Server 和客户端上都有这个限制。**注意,这里说的数据包大小是指 MySQL 应用层对数据的约定,在网络协议封装中,TCP 层和 IP 层各自都有各自的单个数据报文限制,即 MTU 和 MSS 等**

若包长度过大, 则客户端需要自行将包分片, 使得每段的长度在 MySQL 包的最大长度之下, MySQL Packet 由 Header 和 Body 组成, Header 包含两个字段: 包长度(payload_length)、序列号(sequence_id), Body 则是包的主体部分, 它的长度由 Header 中的 payload_length 字段指示, 包长度字段固定使用 int<3> 类型, 序列号固定使用 int<1> 类型, 当客户端和服务端开始交互时, 由客户端初始化 0 序列号, 之后每次交互, 数据发出方都基于前一个 sequence_id 增一, sequence_id 不是恒定唯一的, 当交互次数足够多后, 它会重新回到 0。




Expand Down Expand Up @@ -295,7 +368,9 @@ MySQL 采用的是挑战-响应方式来进行身份认证。由服务端生成

![alt text](./response_ok.png)

Response OK ,成功响应,这个没什么好说的。


Response OK ,成功响应,这个没什么好说的。返回的核心字段是 Server Status 这些各种 flag 标记位。



Expand Down

0 comments on commit 79151ad

Please sign in to comment.