[转帖]MySQL协议分析_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2157 | 回复: 0   主题: [转帖]MySQL协议分析        下一篇 
John
注册用户
等级:大元帅
经验:90444
发帖:136
精华:2
注册:2011-7-21
状态:离线
发送短消息息给John 加好友    发送短消息息给John 发消息
发表于: IP:您无权察看 2014-11-17 11:02:42 | [全部帖] [楼主帖] 楼主

    MySQL协议分析,主要参考MySQL Forge上的wiki和源码.协议的全图见这里,

View more presentations from ruoyi ruan
packet number


  在做proxy的时候在这里迷糊过,翻了几遍代码才搞明白,细节如下:

  客户端服务端的net->pkt_nr都从0开始.接受包时比较packet number 和net->pkt_nr是否相等,否则报packet number乱序,连接报错;相等则pkt_nr自增.发送包时把net->pkt_nr作为packet number发送,然后对net->pkt_nr进行自增保持和对端的同步.

  接收包

sql/net_serv.c:my_real_read
898 if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)


  发送包

sql/net_serv.c:my_net_write
392 int3store(buff,len);
393 buff[3]= (uchar) net->pkt_nr++;


  我们来几个具体场景的packet number, net->pkt_nr的变化

  连接

0 c ———-> s 0 connect
0 c <—-0——s 1 handshake
2 c —-1—->s 1 auth
2c <—-2——s 0 ok


  开始两方都为0,服务端发送handshake packet(pkt=0)之后自增为1,然后等待对端发送过来pkt=1的包

  查询

  每次查询,服务客户端都会对net->pkt_nr进行清零

include/mysql_com.h
388 #define net_new_transaction(net) ((net)->pkt_nr=0)
sql/sql_parse.cc:do_command
805 net_new_transaction(net);
sql/client.c:cli_advanced_command
800 net_clear(&mysql->net, (command != COM_QUIT));


  开始两方net->pkt_nr皆为0, 命令发送后客户端端为1,服务端开始发送分包,分包的pkt_nr的依次递增,客户端的net->pkt_nr也随之增加.

1 c ——0—-> s 0 query
1 c <—-1——s 2 resultset
2 c <—-2——s 3 resultset


  解包的细节

  my_net_read负责解包,首先读取4个字节,判断packet number是否等于net->pkt_nr然后再次读取packet_number长度的包体。

  伪代码如下:

remain=4
for(i = 0; i < 2; i++) {
      //数据是否读完
      while (remain>0) {
            length = read(fd, net->buff, remain)
            remain = remain - length
      }
      //第一次
      if (i=0) {
            remain = uint3korr(net->buff+net->where_b);
      }
}


  网络层优化

  从ppt里可以看到,一个resultset packet由多个包组成,如果每次读写包都导致系统调用那肯定是不合理,常规优化方法:写大包加预读

net->buff


  每个包发送到网络或者从网络读包都会先把数据包保存在net->buff里,待到net->buff满了或者一次命令结束才会通过socket发出给对端.net->buff有个初始大小(net->max_packet),会随读取数据的增多而扩展.

vio->read_buffer


  每次从网络读包,并不是按包的大小读取,而是会尽量读取2048个字节,这样一个resultset包的读取不会再引起多次的系统调用了.header packet读取完毕后, 接下来的field,eof, row apcket读取仅仅需要从vio-read_buffer拷贝指定字节的数据即可.

  MySQL api说明

  api和MySQL客户端都会使用sql/client.c这个文件,解包的过程都是使用sql/client.c:cli_read_query_result.

  mysql_store_result来解析row packet,并把数据存储到res->data里,此时所有数据都存内存里了.

  mysql_fetch_row仅仅是使用内部的游标,遍历result->data里的数据

3052 if (!res->data_cursor)
3053 {
      3054 DBUG_PRINT("info",("end of data"));
      3055 DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
3056 }
3057 tmp = res->data_cursor->data;
3058 res->data_cursor = res->data_cursor->next;
3059 DBUG_RETURN(res->current_row=tmp);


  mysql_free_result是把result->data指定的行数据释放掉.

--转自 北京联动北方科技有限公司




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论