mysql协议重传_MySQL通讯协议(1)数据类型

[TOC]

MySQL通讯协议(1)数据类型

对于大部分开发者来说,并不需要了解MySQL客户端和服务端是如何交互的。但是当业务发展到一定阶段,数据量增大时,分库分表就成了不得不考虑的一种优化措施。目前主流的方案主要有两种,一种是本地代理连接、分析重写SQL、路由、执行、合并结果,一种是把这些放到中间件里。而后一种就必须了解MySQL通讯协议,因为这个中间件要作为客户端与MySQL服务交互,还要作为服务端与MySQL客户端交互。

连接MySQL的协议

协议

支持的操作系统

TCP

全部

使用TCP/IP协议连接本地或远程服务器

SOCKET

Unix

使用Unix socket连接本地服务器

PIPE

Windows

使用Windows named-pipe连接本地服务器

MEMORY

Windows

使用Windows shared-memory连接本地服务器

可见后三种方式都受制于各自平台,且只能连接本地服务器,不符合大部分应用场景。所以,我们接触到的都是基于TCP协议的连接方式。

MySQL通讯协议是基于TCP/IP协议的一个应用层协议,所以TCP/IP协议该有的三次握手、滑动窗口、重传机制都有,这里不再赘述。

概述

MySQL通讯协议被设计用于MySQL客户端和MySQL服务端之间通讯,主要用于:

各种语言实现的连接器,如JDBC驱动

MySQL代理

主从复制之间的通信

基本数据类型

协议里用到的数据类型,有Integer和String两种

Integer

整数类型,分为两种固定长度和

固定长度整数

占用空间固定的无符号整数,有6种int<1>、int<2>、int<3>、int<4>、int<6>、int<8>,尖括号里的数字,代表占用几个字节。可以简单理解成byte、short、int、long,但是实际表示并不一样。因为网络传输的单位是字节,即8个bit,int<2>以上没法直接传输,必须经过简单的编码。

编码方式就是把要编码的值,从右向左,每次拿一个字节,依次排列。

例如一个int<2>类型的值2020,转成二进制:111 11100100,第一个字节:11100100,第二个字节:00000111,所以编码后的数据就是:11100100 00000111 ,用十六进制表示:0xE4 0x07。

用代码表示:

int a = 2020;

byte[] data = new byte[2];

data[0] = (byte)(a & 0xFF)

data[1] = (byte)(a & >>> 8)

解码就是反过来:

int[] data = new int[]{228, 7};

int i = (data[0] & 0xff) | ((data[1] & 0xff) << 8);

编码长度整数

int,根据数据值大小,动态的使用1、3、 4、9个字节保存。类似于UTF-8的编码方式。

如果值 < 251,就用1字节表示。

如果值 ≥ 251 且 < (2^16),就用0xfc + 2字节表示,共3字节。

如果值 ≥ (2^16) 且 < (2^24),就用0xfd + 3字节表示,共4字节。

如果值 ≥ (2^24)且 < (2^64),就用0xfe + 8字节表示,共9字节。

例如,值300,属于第二种情况,转成2字节为:00101100 00000001,前面加上0xfd,最后结果就是:0xfd 0x2C 0x01。

解码就是先取第一位,判断是否<251,如果如就是第一种情况,如果不是,根据第一位是0xfc 、0xfd 、0xfe 判断是那种情况,然后读取后面N位即可。

这种编码方式的好处是,在不能提前确定数据大小时,提供一种动态的编码方式,当实际数值较小时,可以不用传输大量的空值(占位的0),从而减少数据包大小,提高传输效率。

String

字节序列类型,分为5种类型

固定长度字符串

string,长度固定的字符串,跟固定长度的整数一样,但区别是字符串是按数据固有顺序编码的,不需要像整数一样,从右向左编码。

Null结尾的字符串

string,长度不固定,但是已一个空数据(0x00)结尾的字符串。类似于HTTP协议Head的结束标志\r\n\r\n,只要读到0x00就认为结束。

变量长度字符串

string,字符串的长度由另一个字段决定,或者在运行时计算。比如说消息体的长度,就是由消息头里的payload_length这个字段指定的。

编码长度字符串

string,用前缀整数指定长度的字符串,跟编码长度整数字符串一致。

包结尾字符串

string,放在包最后的字符串,因为在最后,所以只要用包长度 - 已读长度就是剩余字符串的长度了。

总结

所有的数据类型如下:

那么为什么要定义这些数据类型?因为在网络传输数据时,有两个问题:1,数据表示什么,2,数据边界在哪。

例如:客户端向服务器提交用户名密码,数据在网络上是一个个字节发送的,服务器怎么知道哪段是用户名,哪段是密码。最常见的解决办法是这样的:

{"username":"san", "password":"123"}

纯文本、便于阅读、结构清晰、没有特殊关键字、没有过多无用符号,比xml好多了。但是仍然不够,大括号、双引号、冒号,都是额外的开销,当数据量大到一定地步,都是巨大的资源浪费。这就是很多大厂开发RPC框架的原因,例如Dubbo、Protobuf(当然对于服务调用HTTP本身也很浪费资源)。

MySQL这种对性能有极致要求的数据库当然也不能这么做,同时,因为数据库通讯数据结构很固定,每次传输的字段基本没变化。所以可以这么做:

按提前规定好的顺序发送每个字段值,比如先发用户名,后发密码

特殊的标志位、常量直接规定长度,比如成功/失败,一个字节就够了

不确定的值就用各种方法描述,动态长度字符串

这样就可以把没用的数据去掉了,对于一个登陆请求,客户端完全可以传:3san3123。实际上Protobuf之所以快,就是用类似的方法做的。

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值