浅析MySQL协议——从一个bug谈起

2023-11-23 05:48

本文主要是介绍浅析MySQL协议——从一个bug谈起,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

640?wx_fmt=png点击上方 “公众号” 可以订阅哦!

在经过一系列紧锣密鼓的筹备后,Sharding-Sphere 3.0.0.M2 终于在2018.8.8正式跟大家见面了。发版之前我们解决了几个棘手的问题,今天拓海与大家分享其中一个:MySQL协议相关的一个bug。在bug的定位过程中,小伙伴们会了解到一些MySQL协议的基本知识和调试方法。

Bug描述

关于bug的描述,这里使用了项目的issue模板,大家在提bug的时候也请一定遵循这个模板。在本文中使用中文描述,但大家提issue的时候记得用英文,毕竟老外也会来看的。

Which version of Sharding-Sphere do you using?

3.0.0.M2-SNAPSHOT

Which project do you using? Sharding-JDBC or Sharding-Proxy?

Sharding-Proxy

Expected behavior

持续正常的INSERT数据。

Actual behavior

循环插入200万数据,当插入到100万左右的时候,客户端无响应。

Reason analyze

客户端无响应可能是Proxy阻塞引起的,也可能是Proxy导致客户端阻塞引起的。

Steps to reproduce the behavior

持续插入数据到100万条以上即可复现。

Bug初步定位

经过初步分析,Proxy日志正常,MySQL里也能查到用户插入的最后一条数据。那么,问题应该就出在最后一条数据插入成功之后。可能有两种情况:1. 插入数据成功后,MySQL返回的消息被Proxy错误解码,导致Proxy异常;2. Proxy返回给客户端的消息编码错误,导致客户端异常。

第一种情况,如果Proxy解码错误,Netty会抛异常,TCP连接断开,Proxy会把异常打印到日志,所以这种情况可能性不大。第二种情况可能性较大,需要分析Proxy和客户端之间的消息交互,进一步定位。

MySQL协议

准确的说应该是MySQL Client/Server协议,另一个叫X Protocol的暂不涉及。任何MySQL客户端(CLI、GUI、MySQL驱动)与MySQL服务器通信,都需要使用这个协议。这个协议包含一系列的命令消息(COM)和响应消息(Response)、编解码方式和交互流程。


640?wx_fmt=png

上图展示了绝大多数协议消息的交互过程:对于DQL,服务器会返回FIELD_COUNT(列数)、FIELD(列的描述信息,如类型等)、ROW(每一行数据的值)、EOF(结束标志);而对于DML,只需要返回OK或者ERR,通知客户端命令执行成功或失败。

经过之前的分析,我们可以把范围缩小到OK_Packet这条响应消息上,这条消息由服务器发送给客户端,表示一条命令的成功执行。也就是说,在插入数据成功后,MySQL服务器会发送OK_Packet给Proxy,后者又会把这条消息发送给客户端。消息格式如下:

640?wx_fmt=png

这个表格看起来有点抽象,我们可以先用Wireshark抓个真实包看看,解析出来会直观一些:

640?wx_fmt=png

做协议开发永远离不开Wireshark,后面拓海会手把手教你使用Wireshark进行网络抓包。真实的数据看起来就简单明了一些了,有包长度、包序号、影响行数、最后插入id、服务器状态等信息。我们找一个字段,来说明其编解码方式。例如last_insert_id,它的类型是int<lenenc>,值为1083。

MySQL协议里存储数据的方式是小端字节序,这是什么意思呢?比如一个值0x1234,采用大端字节序的存储方式就是0x1234,而小端方式则是0x3412。MySQL采用这样的字节序很不友好,对于一个通信协议,应该使用网络字节序传输数据,而不是机器字节序。

640?wx_fmt=jpeg

回到协议,int<lenenc>是变长编码的整数类型,不同范围的数值使用不同的长度来编码:

640?wx_fmt=png

由上可知,1083这个值应该是0xfc 加上2个字节来表示:

640?wx_fmt=png

1083 = 0x043b,小端字节序就是0x3b04。有了这些基础,我们就可以通过抓包来分析产生bug的根本原因了。

Bug最终定位

以下就是当时抓到的包,看起来非常的“正常”,插入一条数据,返回一条成功的响应,Wireshark也没有解析出错。看现象就是客户端停止了插入数据。

640?wx_fmt=png

经过多次试验,最后一条INSERT总是卡在t_order_item这个表上,它与t_order表有什么本质区别呢?了解Sharding-Sphere-Example的同学对这两个表应该很熟悉,t_order使用的是雪花算法生成的分布式主键,值很大,而t_order_item使用的是MySQL自增主键。为什么主键值小的表会卡住?

又经过一系列调查,发现t_order_item表也不是每次都卡住,这个表有两个分片,在其中一个分片上永远没问题,而另一个分片上只要插入数据就会卡。这两个表又有什么区别呢?其实,由于分片的不均匀,一个表的数据量多,另一个数据量少,除此之外没什么不同。数据量多的表大概6万多条数据。

在拓海百思不得其解的时候,亮神和赵帅看出了些端倪:

640?wx_fmt=png

最后一条OK_Packet的Last INSERT ID值太大了,一个表不可能有这么多数据。通过观察发现,表的数据量已经大于65535,应该使用3个字节存储

640?wx_fmt=png

然而程序里却使用了四个字节。四个字节的编码在协议里是不存在的,这必然导致客户端jdbc解析出错。至于为什么wireshark没有解析出错,那一定是因为它的解析逻辑错了。

使用Wireshark分析MySQL协议

Wireshark可以理解为是一个带图形界面的tcpdump,同时集成了非常多的协议解析插件,可以帮助我们方便的抓取和分析MySQL协议。需要注意的是,Wireshark只能抓网络协议包,但MySQL协议还有其他通信方式,如Shared memory,Named pipes,这些是抓不到的,最好不要开这些参数。

Linux命令行环境下:可以先用tcpdump抓包,然后将包发送到本地,使用Wireshark解析。命令如下:

tcpdump -i any port 3307 -w test.pcap

any: 表示所有网络接口。

port: tcp端口,Proxy的默认端口是3307,如果你关心MySQL的包,就改为3306。

pcap: 一种通用的数据流格式,Wireshark可以直接打开。

用Wireshark打开test.pcap,你会发现除了MySQL协议,还显示很多TCP协议的ACK消息:

640?wx_fmt=png

在过滤器中输入mysql,进行过滤即可:

640?wx_fmt=png

Windows环境下:直接使用Wireshark抓包,一边抓包一边解析。本地的测试环境往往会同时运行客户端、Proxy和MySQL服务器,它们的通信在同一台机器上是不走网卡的,然而windows系统又没有提供本地回环网络的接口,所以这种情况下是什么也抓不到的。

为了解决这个问题,我们需要把Wireshark在Windows系统上默认的抓包工具WinPcap替换为Npcap,在这里下载:https://nmap.org/npcap/#download

安装前先在Wireshark的安装目录下卸载WinPcap。安装时勾选如下选项:


640?wx_fmt=png

安装完成再次启动Wireshark时,就会看到在网络接口列表中,多了一项Npcap Loopback adapter,这个就是来抓本地回环包的网络接口了:

640?wx_fmt=png

小结

Sharding-Sphere自2016开源以来,不断精进、不断发展,被越来越多的企业和个人认可:在Github上收获5000+的star,1900+forks,60+的各大公司企业使用它,为Sharding-Sphere提供了重要的成功案例。此外,越来越多的企业伙伴和个人也加入到Sharding-Sphere的开源项目中,为它的成长和发展贡献了巨大力量。

我们从未停息过脚步,聆听社区伙伴的需求和建议,不断开发新的强大功能,不断使其健壮可靠!开源不易, 我们却愿向着最终的目标,步履不停!那么,正在阅读的你,是否可以助我们一臂之力呢?分享、转发、使用、交流,以及加入我们,都是对我们最大的鼓励!

640?wx_fmt=png

Sharding-Sphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这3款相互独立的产品组成。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。
亦步亦趋,开源不易,您对我们最大支持,就是在github上留下一个star。

项目地址:
https://github.com/sharding-sphere/sharding-sphere/
https://gitee.com/sharding-sphere/sharding-sphere/
更多信息请浏览官网:
http://shardingsphere.io/
或加入Sharding-Sphere官方讨论群

640?wx_fmt=png 640?wx_fmt=png 640?wx_fmt=jpeg


这篇关于浅析MySQL协议——从一个bug谈起的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/415791

相关文章

mysql索引四(组合索引)

单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引;组合索引,即一个索引包含多个列。 因为有事,下面内容全部转自:https://www.cnblogs.com/farmer-cabbage/p/5793589.html 为了形象地对比单列索引和组合索引,为表添加多个字段:    CREATE TABLE mytable( ID INT NOT NULL, use

mysql索引三(全文索引)

前面分别介绍了mysql索引一(普通索引)、mysql索引二(唯一索引)。 本文学习mysql全文索引。 全文索引(也称全文检索)是目前搜索引擎使用的一种关键技术。它能够利用【分词技术】等多种算法智能分析出文本文字中关键词的频率和重要性,然后按照一定的算法规则智能地筛选出我们想要的搜索结果。 在MySql中,创建全文索引相对比较简单。例如:我们有一个文章表(article),其中有主键ID(

mysql索引二(唯一索引)

前文中介绍了MySQL中普通索引用法,和没有索引的区别。mysql索引一(普通索引) 下面学习一下唯一索引。 创建唯一索引的目的不是为了提高访问速度,而只是为了避免数据出现重复。唯一索引可以有多个但索引列的值必须唯一,索引列的值允许有空值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该使用关键字UNIQUE,把它定义为一个唯一索引。 添加数据库唯一索引的几种

mysql索引一(普通索引)

mysql的索引分为两大类,聚簇索引、非聚簇索引。聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引则不同。聚簇索引能够提高多行检索的速度、非聚簇索引则对单行检索的速度很快。         在这两大类的索引类型下,还可以降索引分为4个小类型:         1,普通索引:最基本的索引,没有任何限制,是我们经常使用到的索引。         2,唯一索引:与普通索引

【服务器运维】MySQL数据存储至数据盘

查看磁盘及分区 [root@MySQL tmp]# fdisk -lDisk /dev/sda: 21.5 GB, 21474836480 bytes255 heads, 63 sectors/track, 2610 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesSector size (logical/physical)

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

SQL Server中,查询数据库中有多少个表,以及数据库其余类型数据统计查询

sqlserver查询数据库中有多少个表 sql server 数表:select count(1) from sysobjects where xtype='U'数视图:select count(1) from sysobjects where xtype='V'数存储过程select count(1) from sysobjects where xtype='P' SE

SQL Server中,always on服务器的相关操作

在SQL Server中,建立了always on服务,可用于数据库的同步备份,当数据库出现问题后,always on服务会自动切换主从服务器。 例如192.168.1.10为主服务器,12为从服务器,当主服务器出现问题后,always on自动将主服务器切换为12,保证数据库正常访问。 对于always on服务器有如下操作: 1、切换主从服务器:假如需要手动切换主从服务器时(如果两个服务

SQL Server中,isnull()函数以及null的用法

SQL Serve中的isnull()函数:          isnull(value1,value2)         1、value1与value2的数据类型必须一致。         2、如果value1的值不为null,结果返回value1。         3、如果value1为null,结果返回vaule2的值。vaule2是你设定的值。        如

SQL Server中,添加数据库到AlwaysOn高可用性组条件

1、将数据添加到AlwaysOn高可用性组,需要满足以下条件: 2、更多具体AlwaysOn设置,参考:https://msdn.microsoft.com/zh-cn/library/windows/apps/ff878487(v=sql.120).aspx 注:上述资源来自MSDN。