原文地址:https://blog.fanscore.cn/a/53/
1. 前言
本文是與世界分享我剛編的轉發ntunnel_mysql.php的工具的后續,之前的實作有些拉胯,這次重構了下,需求背景是為了在本地macbook上通過開源的mysql可視化客戶端(dbeaver、Sequel Ace等)訪問我司測驗環境的mysql,整個測驗環境的如圖所示:

那么就有以下幾種方式:
- 客戶端直連mysql
#Pass# 測驗環境mysql只提供了內網ip,只允許測驗環境上的機器連接,因此不可行 - 通過ssh隧道連接
#Pass# 測驗環境機器倒是可以ssh上去,但是只能通過堡壘機接入,且堡壘機不允許ssh隧道,因此不可行 - navicat http隧道連接
#Pass# 測驗環境有機器提供了公網ip開放了http服務,因此技術上是可行的,但navicat非開源免費軟體,我司禁止使用,因此不可行 - 測驗環境選一臺機器建立mysql代理轉發請求
#Pass# 測驗環境機器只開放了80埠,且已被nginx占用,因此不可行 - 內網穿透
這個想法很好,下次不要再想了

既然上面的方式都不行,那怎么辦呢?因此我產生了一個大膽的想法
2. 一個大膽的想法
大概架構如下

首先,在本地pc上啟動一個sidecar行程,該行程監聽3306埠,實作mysql協議,將自己偽裝為一個mysql server,本地pc上的mysql客戶端連接到sidecar,發送請求資料包給sidecar,從sidecar讀取回應包,
然后在測驗環境某臺機器上啟動transport行程,該行程啟動http服務,由nginx代理轉發請求,相當于監聽在80埠,然后連接到測驗環境的mysql server,
sidecar會將來自客戶端的請求包通過http請求轉發給transport,transport將請求包轉發到測驗環境對應的mysql server,然后讀取mysql的回應資料包,然后將回應資料包回傳給sidecar,sidecar再將回應包回傳給mysql客戶端,
遵循上述的基本原理,我將其實作出來: https://github.com/Orlion/hersql,但是在描述hersql的實作細節之前我們有必要了解下mysql協議
3. mysql協議
mysql客戶端與服務端互動程序主要分為兩個階段:握手階段與命令階段,互動流程如下:

在最新版本中,握手程序比上面要復雜,會多幾次互動
3.1 握手階段
在握手階段,3次握手建立tcp連接后服務端會首先發送一個握手初始化包,包含了
- 協議版本號:指示所使用的協議版本,
- 服務器版本:指示MySQL服務器版本的字串,
- 連接ID:在當前連接中唯一標識客戶端的整數,
- 隨機資料:包含一個隨機字串,用于后續的身份驗證,
- 服務器支持的特性標志:指示服務器支持的客戶端功能的位掩碼,
- 字符集:指示服務器使用的默認字符集,
- 默認的身份驗證插件名(低版本沒有該資料)
隨后客戶端會發送一個登錄認證包,包含了:
- 協議版本號:指示所使用的協議版本,
- 用戶名:用于身份驗證的用戶名,
- 加密密碼:客戶端使用服務端回傳的亂數對密碼進行加密
- 資料庫名稱:連接后要使用的資料庫名稱,
- 客戶端標志:客戶端支持的功能的位掩碼,
- 最大資料包大小:客戶端希望接收的最大資料包大小,
- 字符集:客戶端希望使用的字符集,
- 插件名稱:客戶端希望使用的身份驗證插件的名稱,
服務端收到客戶端發來的登錄認證包驗證通過后會發送一個OK包,告知客戶端連接成功,可以轉入命令互動階段
在mysql 8.0默認的身份驗證插件為
caching_sha2_password,低版本為mysql_native_password,兩者的驗證互動流程有所不同個,caching_sha2_password在快取未命中的情況下還會多幾次互動,另外如果服務端與客戶端的驗證插件不同的話,也是會多幾次互動,
3.2 命令階段
在命令階段,客戶端會發送命令請求包到服務端,資料包的第一個位元組標識了當前請求的型別,常見的命令有:
- COM_QUERY命令,執行SQL查詢陳述句,
- COM_INIT_DB命令,連接到指定的資料庫,
- COM_QUIT命令,關閉MySQL連接,
- COM_FIELD_LIST命令,列出指定表的欄位串列,
- COM_PING命令,向MySQL服務器發送PING請求,
- COM_STMT_系列預處理陳述句命令
請求回應的模式是客戶端會發一個請求包,服務端會回復n(n>=0)個回應包
最后客戶端斷開連接時會主動發送一個COM_QUIT命令包通知服務端斷開連接
4. hersql資料流轉程序
在了解mysql協議之后我們就可以來看下hersql的資料流轉程序了,

transport連接mysql server時必須要知道目標資料庫的地址與埠號(mysql client連接的是sidecar),所以hersql要求mysql client需要在資料庫名中攜帶目標資料庫的地址與埠號,
transport發給mysql server的登錄請求包中需要包含用mysql server發來的亂數加密之后的密碼,但是mysql client給到sidecar的登錄請求包中的密碼是用sidecar給的亂數加密的,因此無法直接拿來使用,所以hersql要求mysql client需要在資料庫名中攜帶密碼原文,transport會用mysql server給的亂數進行加密, 這也是hersql的局限,
5. hersql使用
上面介紹了一堆原理性的東西,那么如何使用呢?
5.1 在一臺能夠請求目標mysql server的機器上部署hersql transport
首先你需要下載下來hersql的原始碼:https://github.com/Orlion/hersql,還需要安裝下golang,這些都完成后你就可以啟動hersql transport了,但是先別著急,我先解釋下transport的組態檔tranport.example.yaml:
server:
# transport http服務監聽的地址
addr: :8080
log:
# 標準輸出的日志的日志級別
stdout_level: debug
# 檔案日志的日志級別
level: error
# 檔案日志的檔案地址
filename: ./storage/transport.log
# 日志檔案的最大大小(以MB為單位), 默認為 100MB,日志檔案超過此大小會創建個新檔案繼續寫入
maxsize: 100
# maxage 是根據檔案名中編碼的時間戳保留舊日志檔案的最大天數,
maxage: 168
# maxbackups 是要保留的舊日志檔案的最大數量,默認是保留所有舊日志檔案,
maxbackups: 3
# 是否應使用 gzip 壓縮旋轉的日志檔案,默認是不執行壓縮,
compress: false
你可以根據你的需求修改配置,然后就可以啟動transport了
$ go run cmd/transport/main.go -conf=transport.example.yaml
一般情況下都是會先編譯為可執行檔案,由systemd之類的工具托管transport行程,保證transport存活,這里簡單期間直接用go run起來
5.2 在你本地機器部署啟動hersql sidecar
同樣的,你需要下載下來hersql的原始碼:https://github.com/Orlion/hersql,提前安裝好golang,修改下sidecar的組態檔sidecar.example.yaml:
server:
# sidecar 監聽的地址,之后mysql client會連接這個地址
addr: 127.0.0.1:3306
# transport http server的地址
transport_addr: http://x.x.x.x:xxxx
log:
# 與transport配置相同
就可以啟動sidecar了
$ go run cmd/sidecar/main.go -conf=sidecar.example.yaml
同樣的,一般情況下也都是會先編譯為可執行檔案,mac上是launchctl之類的工具托管sidecar行程,保證sidecar存活,這里簡單期間直接用go run起來
5.3 客戶端連接
上面的步驟都執行完成后,就可以打開mysql客戶端使用了,資料庫地址和埠號需要填寫sidecar組態檔中的addr地址,sidercar不會校驗用戶名和密碼,因此用戶名密碼可以隨意填寫
重點來了: 資料庫名必須要填寫,且必須要按照以下格式填寫
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
舉個例子:
root:123456@tcp(10.10.123.123:3306)/BlogDB
如圖所示:

5.4 舉個例子
目標mysql服務器
- 地址:10.10.123.123:3306
- 資料庫:BlogDB
- 用戶名:root
- 密碼:123456
可以直連目標mysql服務器的機器
- 地址:10.10.123.100
- 開放埠:8080
那么transport可以配置為
server:
addr: :8080
sidecar可以配置為
server:
addr: 127.0.0.1:3306
transport_addr: http://10.10.123.100:8080
客戶端連接配置
- 服務器地址:127.0.0.1
- 埠: 3306
- 資料庫名
root:123456@tcp(10.10.123.123:3306)/BlogDB
5.5 局限
hersql目前只支持mysql_native_password的認證方式,mysql8默認的認證方式是caching_sha2_password,所以如果要通過hersql連接mysql8需要注意登錄用戶的認證方式是否是mysql_native_password,如果是caching_sha2_password那暫時是無法使用的,
6. 參考資料
- MySQL協議分析
- MySQL: Client/Server Protocol
如果github.com/Orlion/hersql對你有幫助歡迎點個star
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/553357.html
標籤:MySQL
上一篇:01_MySQL基礎架構
下一篇:返回列表
