转载

MySQL 客户端代码引发的思考

一次偶然的机会debug代码瞅了一眼Mysql客户端的代码(Java版本),最引发我兴趣的是这一句:

MySQL 客户端代码引发的思考

execSQL 是一个非常重要的方法,所有SQL语句的最终都是交由这个代码来实现的;这个方法被一个 connectionMutex 锁(这个锁其实就是Connection对象自己,Mysql客户端通过使用了“反射”所以不能直接使用 this )包裹着这就意味着—— 在同一时刻一个Mysql连接只能执行一条SQL语句

MySQL客户端的“锁”

带着疑问我走读了这段代码,画一幅图

MySQL 客户端代码引发的思考 MysqlIO 是负责网络通讯的底层类,使用的是Java是BIO通讯属于“标准”的TCP客户端写法。它内部有三个重要的成员变量

  • mysqlConnection 是一个Socket类型

  • mysqlOutput 是一个BufferedOutputStream类型

  • InputStream 是一个InputStream类型(Mysql做了一点封装理解成BufferedInputStream也没什么问题)

这三个成员变量的初始化是在 MySqlIO 的构造函数完成的,当执行SQL语句的时相当于:

  • 锁住Socket,此时只有当前连接可以使用这个Socket对象(实际的锁范围更大)

  • mysqlOutput 写入数据包,发送Command(内部称客户端->服务器的请求为Command)

  • mysqlInput 读取数据包,解析返回结果

如果有多条SQL语句递交给一个 连接 因为Socket被“锁”所以会变成串行执行。

这不是bug,是特性

带着疑问我翻看了Mysql的通讯协议,客户端->服务器的标准格式如下:

MySQL 客户端代码引发的思考

  • 3字节表示后面“payload”的长度(所以mysql单数据包最大值是4M);

  • 1字节表示“sequence_id”;这个字段似乎没有什么用途

  • 最后一个是变长的“payload”(长度由第一部分决定)

服务器端->客户端(响应数据包)的标准格式是

MySQL 客户端代码引发的思考

  • 1字节表示“类型”

  • 根据不同的类型“payload”会有不同的变化,比如返回的错误信息、受影响的行数等

看到这里我明白原因了。

Mysql的数据包中没有办法区分出一个连接中“不同的数据包”。 A、B两条SQL语句,可以通过一个Socket发送到服务器端;服务器端也会返回两个执行结果。问题是——客户端如何区分出哪个是A的执行结果哪个是B的执行结果呢? 仔细观察上面的数据包唯一的方式是sequence_id,A分配一个id,B分配一个;服务器端在返回的时候把相应的sequence_id带回来表示这是某个SQL语句的执行结果。 遗憾的是——sequence_id根本没用到,服务器端不会返回sequence_id信息。(看Mysql的响应数据包)

正是因为这个原因导致了所有的Mysql客户端 Connection 对象都不是线程安全的。如果想要同时执行多条SQL语句就只能构造多个 Connection 有意思的是MongoDB的协议格式几乎和Mysql的一样,messageLength,requestID,opCode;但是响应数据包“修正”了这个bug,messageLength,responseID,opCode。 这就意味着mongodb的conneciton是不需要阻塞的而且根本不需要“线程池”。 (根据我观察 connectionsPerHost 似乎是没有用到,难道这个是为了给大家“安全感”?——我们带线程池,放心用吧)

更多思考

我想到了更多东西,HTTP 2.0的多路复用(Multiplexing)。在HTTP1.0中每个HTTP请求都是一个TCP请求,浏览器载入页面的时候会大量加载css、js、图片、html短时间内会发起大量的TCP请求。在HTTP2.0中同时向一台主机发起css、js、图片可以被承载在同一个TCP连接中。 AMQP中也有相似的设计,叫Channel;一个TCP连接可以被多个线程同时使用。比如用一个TCP连接可以同时实现“订阅”和“发布”消息。 微软RDP协议中也有相同的设计,区分图片、声音、鼠标、键盘操作(Citrix的ICA设计号称的32个通道就是这个意思)。 SSH协议中有一个叫 Channel Mechanism 的东西,它也是为了实现“多路复用”的(这意味着提高了ansible的效率)。

技术就是这么奇妙,很多东西都是你“借鉴我”,我“借鉴你”。相同的问题相同的解决办法,如果 用心其实可以汇编成一本书 ,比如我们上面讲的或许就可以叫——“多路复用的协议设计模式”吧。

欢迎关注公众账号了解更多信息“写程序的康德——思考、批判、理性”

MySQL 客户端代码引发的思考

原文  http://mp.weixin.qq.com/s?__biz=MzIxMjAzMDA1MQ==&mid=2648945752&idx=1&sn=9554004c911ad3ccc82e61df30384a17&chksm=8f5b5354b82cda42dcc114a974e470a217591c06fd1238dae8cde35b0be06ddd42eb3b547e92
正文到此结束
Loading...