淺談MySQL壓縮協議細節--從原始碼層面
壓縮協議屬於mysql通訊協議的一部分,要啟用壓縮協議傳輸功能,前提條件客戶端和服務端都必須要支援zlib演算法,那麼,現在有個問題,假如服務端已經預設開啟壓縮功能,那原生客戶端在連線的時候要如何才可啟用該功能呢?答案很簡單隻需要加上-C(注意是大寫C)或者--compress=true選項即可,事情看似簡單,但是背後的設計卻值得大家深入挖掘,啟動後到底發生什麼事情了,對網路傳輸效能上的提升到底有什麼影響呢?
趁著風和日麗的今天,正適合在西湖邊上一邊泡著龍井、一邊聽著音樂、一邊晒著太陽來享受一下這裡面的真相,好,廢話不多說,咱們開始吧。
首先,當客戶端加上-C時,就會在Capabilities上新增CLIENT_COMPRESS壓縮標誌,原始碼參考sql-common/client.c的default_options變數、option_id變數以及mysql_read_default_options函式:
(PS:後面有出現原始碼的部分都是引用mysql 5.5.36版本,另外,核心介面部分的原始碼從5.1到5.6多個版本很少會變)
但這裡有個問題,這樣是否就成功開啟壓縮功能呢?不行的,還記得開始的時候提到的必須要客戶端和服務端都開啟壓縮功能才是成功的,那服務端又是什麼時候告訴客戶端支援壓縮呢?那就是在
如果在編譯原始碼時沒定義HAVE_COMPRESS變數時,那麼服務端就不支援壓縮,一般情況不會去掉該選項。
接下來,大夥得加快速度,跟上步伐,一起來認識下壓縮協議包組成部分,這主要由Compressed Packet header和payload組成,具體如下圖所述:
圖1 壓縮協議組成
從圖中可以看出比普通的協議多出
另外,可能細心的讀者又有疑問,為什麼訊息體是Compressed Payload或者Uncompressed Payload?這是因為mysql內部有一個約定,如果查詢語句payload小於50位元組時,對內容不壓縮而保持原貌的方式,而mysql此舉是為了減少CPU效能開銷,原始碼參考include/my_sys.h的MIN_COMPRESS_LENGTH和mysys/my_compress.c的my_compress函式:
同時,壓縮前的長度會設定為0。
如果訊息體為Compressed Payload時,客戶端或服務端互動前,可能會將一個或多個MySQL包文合併壓縮成一個數據包再發出去,目的顯然而見,為了提升網路傳輸效能,對於一些網路環境較差的使用者會有很大的幫助,剛才有提到過compressed sequence id的問題,如果不使用一個單獨的變數來標誌的話,那麼當一個壓縮包裡有多個MySQL報文時就不知道怎麼確定包序號了,這就是該變數的作用了。
那這裡面貌似還會產生一個問題,如果原始報文或拼揍後是32M的話,能否進行壓縮呢?答案是不行的,因為mysql一個包文最大長度限制為16M,從上面圖1的第3部分length of payload before compression就可以判斷出來,原始碼參考mysys/my_compress.c的my_uncompress函式:
以上就是今天要分享的小細節,希望對大家理解壓縮協議方面的相關細節有所幫助,祝玩得開心!