MySQL協議分析2

來源:互聯網
上載者:User

標籤:

MySQL協議分析

議程協議頭協議類型網路通訊協定相關函數NET緩衝VIO緩衝MySQL API

協議頭

● 資料變成在網路裡傳輸的資料,需要額外的在頭部添加4 個位元組的包頭. . packet length(3位元組), 包體的長度 . packet number(1位元組), 從0開始的遞增的● sql “select 1” 的網路通訊協定是?

 

協議頭

● packet length三個位元組意味著MySQL packet最大16M大於16M則被分包(net_write_command, my_net_write)● packet number分包從0開始,依次遞增.每一次執行sql, packet_number清零(sql/net_serv.c:net_clear)

 

協議類型

● handshake● auth● ok|error● resultset     ○ header     ○ field     ○ eof     ○ row● command packet

 

串連時的互動

協議說明

● 協議內欄位分三種形式     ○ 固定長度(include/my_global.h)         ■ uint*korr 解包         ■ int*store 封包     ○ length coded binary(sql-common/pack.c)         ■ net_field_length 解包         ■ net_store_length 封包     ○ null-terminated string● length coded binary     ○ 避免binary unsafe string, 字串的長度儲存在字串的前面         ■ length<251 1 byte         ■ length <256^2 3 byte(第一個byte是252)         ■ length<256^3 4byte(第一個byte是253)         ■ else 9byte(第一個byte是254)

 

handshake packet

● 該協議由服務端發送用戶端● 括弧內為位元組數,位元組數為n為是null-terminated string;位元組數為大寫的N表示length code binary.● salt就是scramble.分成兩個部分是為了相容4.1版本● sql_connect.cc:check_connection● sql_client.c:mysql_real_connect

 

auth packet

● 該協議是從用戶端對密碼使用scramble加密後發送到服務端● 其中databasename是可選的.salt就是加密後的密碼.● sql_client.c:mysql_real_connect● sql_connect.c:check_connection

 

ok packet

● ok包,命令和insert,update,delete的返回結果● 包體首位元組為0.● insert_id, affect_rows也是一併發過來.● src/protocol.cc:net_send_ok

 

error packet

● 錯誤的命令,非法的sql的返回包● 包體首位元組為255.● error code就是CR_***,include/errmsg.h● sqlstate marker是#● sqlstate是錯誤狀態,include/sql_state.h● message是錯誤的資訊● sql/protocol.cc:net_send_error_packet

 

resultset packet

● 結果集的資料包,由多個packet組合而成● 例如查詢一個結構集,順序如下:     ○ header     ○ field1....fieldN     ○ eof     ○ row1...rowN     ○ eof● sql/client.c:cli_read_query_result● 下面是一個sql "select * from d"查詢結果集的例子,結果 集是6行,3個欄位     ○ 公式:假設結果集有N行, M個欄位.則包的個數為,header(1) + field (M) + eof(1) + row(N) + eof(1)     ○ 所以這個例子的MySQL packet的個數是12個

 

resultset packet - header

● field packet number決定了接下來的field packet的個數.● 一個返回6行記錄,3個欄位的查詢語句

 

resultset packet - field

● 結果集中一個欄位一個field packet.● tables_alias是sql語句裡表的別名,org_table才是表的真 實名字.● sql/protocol.cc:Protocol::send_fields● sql/client.c:cli_read_query_result

 

resultset packet - eof

● eof包是用於分割field packet和row packet.● 包體首位元組為254● sql/protocol.cc:net_send_eof

 

resultset packet - row

● row packet裡才是真正的資料包.一行資料一個packet.● row裡的每個欄位都是length coded binary● 欄位的個數在header packet裡● sql/client.c:cli_read_rows

 

command packet

● 命令包,包括我們的sql語句還有一些常見的命令.● 包體首字母表示命令的類型(include/mysql_com.h),大 部分命令都是COM_QUERY.

 

網路通訊協定關鍵函數

● net_write_command(sql/net_serv.cc)所有的sql最終調用這個命令發送出去.● my_net_write(sql/net_serv.cc)串連階段的socket write操作調用這個函數.● my_net_read讀取包,會判斷包大小,是否是分包● my_real_read解析MySQL packet,第一次讀取4位元組,根據packet length再讀取餘下來的長度● cli_safe_read用戶端解包函數,包含了my_net_read

 

NET緩衝

● 每次socket操作都會先把資料寫,讀到net->buff,這是一 個緩衝區, 減少系統調用調用的次數.● 當寫入的資料和buff內的資料超過buff大小才會發出一次 write操作,然後再把要寫入的buff裡插入數, 寫入不會 導致buff區地區擴充.(sql/net_serv.cc: net_write_buff).● net->buff大小初始net->max_packet, 讀取會導致會導致 buff的realloc最大net->max_packet_size● 一次sql命令的結束都會調用net_flush,把buff裡的資料 都寫到socket裡.

 

VIO緩衝

● 從my_read_read可以看出每次packet讀取都是按需讀取, 為了減少系統調用,vio層面加了一個read_buffer.● 每次讀取前先判斷vio->read_buffer所需資料的長度是 否足夠.如果存在則直接copy. 如果不夠,則觸發一次 socket read 讀取2048個字(vio/viosocket.c: vio_read_buff)

 

MySQL API

● 資料從mysql_send_query處發送給服務端,實際調用的是 net_write_command.● cli_read_query_result解析header packet, field packet,獲 得field_count的個數● mysql_store_result解析了row packet,並儲存在result- >data裡● myql_fetch_row其實遍曆result->data

 

________________________________

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     if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)

 

發送包

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

 

我們來幾個具體情境的packet number, net->pkt_nr的變化

串連

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

 

開始兩方都為0,服務端發送handshake packet(pkt=0)之後自增為1,然後等待對端發送過來pkt=1的包

查詢

每次查詢,服務用戶端都會對net->pkt_nr進行清零

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

 

開始兩方net->pkt_nr皆為0, 命令發送後用戶端端為1,服務端開始發送分包,分包的pkt_nr的依次遞增,用戶端的net->pkt_nr也隨之增加.

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

 

解包的細節

my_net_read負責解包,首先讀取4個位元組,判斷packet number是否等於net->pkt_nr然後再次讀取packet_number長度的包體。

虛擬碼如下:

remain=4for(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裡的資料

     if (!res->data_cursor)     {       DBUG_PRINT("info",("end of data"));       DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);     }     tmp = res->data_cursor->data;     res->data_cursor = res->data_cursor->next;     DBUG_RETURN(res->current_row=tmp);

 

mysql_free_result是把result->data指定的行資料釋放掉.

MySQL協議分析2

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.