中間件mysql-proxy的一些細節

2021-02-25 JDTech
mysql的中間件有mysql-proxy\Atlas等。mysql-proxy是官方提供的mysql中間件產品可以實現負載平衡,讀寫分離,failover等,但其不支持大數據量的分庫分表且性能較差。Atlas(是由 Qihoo 360, Web平臺部基礎架構團隊開發維護的一個基於MySQL協議的數據中間層項目。)

今天推薦一篇文章,深度分享mysql-proxy的細節。

原文轉自公眾號:架構師之路

=======================================

一、mysql-proxy簡介

mysql-proxy是mysql官方提供的mysql中間件服務,上遊可接入若干個mysql-client,後端可連接若干個mysql-server,它使用mysql協議,任何連接mysql的上遊無需任何更改即可遷移至mysql-proxy上。

mysql-proxy最基本的用法,就是作為一個請求攔截,請求中轉的中間層:

進一步的,mysql-proxy可以分析與修改請求。攔截查詢和修改結果,需要通過編寫Lua腳本來完成。mysql-proxy允許用戶指定Lua腳本對請求進行攔截,對請求進行分析與修改,它還允許用戶指定Lua腳本對伺服器的返回結果進行修改,加入一些結果集或者去除一些結果集均可。

【SK畫外音:sql攔截與修改,性能分析與監控,讀寫分離,請求路由等各種功能都是通過編寫Lua腳本來完成的,mysql-proxy是個框架,具備很好的擴展性。這個框架提供了6個hook點,能夠讓用戶能夠動態的介入到client與server中的通訊中去。】

二、mysql-proxy命令參數

版本顯示

使用--version參數即可:

./mysql-proxy --version

從輸出可以看到mysql-proxy的版本,以及依賴的glib,libevent,lua的版本

1 mysql-proxy0.8.3

2 chassis: mysql-proxy 0.8.3

3 glib2: 2.16.6

4 libevent: 1.4.13-stable

5 LUA: Lua 5.1.4

8 -- modules

9 proxy: 0.8.3

簡單啟動

mysql-proxy啟動至少需要指定一個後端mysql的ip和埠號,此時帶上--proxy-backend-addresses參數即可:

./mysql-proxy --proxy-backend-addresses=127.0.0.1:3306

指定配置文件啟動

mysql-proxy亦可以指定配置文件啟動,此時帶上--defaults-file來指定配置文件即可:

./mysql-proxy --defaults-file=./mysql-proxy.cnf

mysql-proxy.cnf的格式如下:

1[mysql-proxy]

2proxy-backend-addresses = 127.0.0.1:3306

需要注意,在命令行中參數前需要加入「--」,而在配置文件中則不需要。

尋求幫助

可以使用--help,或者--help-all

./mysql-proxy --help

./mysql-proxy --help-all

Proxy常用選項

選項

說明

proxy-backend-addresses=$host:$port

後端mysql的ip和port,多個以逗號分隔

proxy-read-only-backend-addresses=$host:$port

後端只讀mysql的ip和port,多個以逗號分隔

proxy-skip-profiling=$bool

是否禁用查詢性能剖析

proxy-lua-script=$file_name

lua文件



注意:

如果設置了多個後端mysql,負載均衡策略為round-robin。例如設了A和B兩臺後端,第一個請求轉發到A,第二個請求轉發到B,第三個請求轉發到A,以此類推。

Proxy服務常用選項

選項

說明

proxy-address=$host:$port

mysql-proxy的ip和port,默認port是4040

daemon=$bool

是否使用daemon模式啟動

event-threads=$count

event-handing線程數,默認值是1

keep-alive=$bool

proxy服務崩潰後自動重啟

log-file=$file_name

日誌文件

log-level=$level

日誌級別:error|warning|info|message|debug

log-use-syslog=$bool

日誌使用syslog

max-open-files=$count

最大文件句柄數

pid-file=$file_name

pid文件



典型配置文件示例

1[mysql-proxy]

2

3proxy-address = 127.0.0.1:4040

4 daemon =true

5event-threads = 2

6 keep-alive= true

7 log-file =./mysql-proxy.log

8 log-level= debug

9max-open-files = 1024

10 pid-file =./mysql-proxy.pid

11

12 proxy-lua-script= ./ro-balance.lua

13proxy-backend-addresses = 127.0.0.1:3306

14proxy-skip-profiling = false

啟動過程中提示:

2013-12-28 15:15:49: (critical)mysql-proxy-cli.c:326: loading config from './mysql-proxy.cnf' failed:permissions of ./mysql-proxy.cnf aren't secure (0660 or stricter required)

由於安全要求,必須將配置文件權限設為660(創建人可讀寫,同組人可讀),否則不允許啟動。

三、mysql-proxy腳本編程

如「簡介」中所述,mysql-proxy向用戶提供了6個hook點,讓用戶實現Lua腳本來完成各種功能,這些hook點是以函數的形式提供的,用戶可以實現這些函數,在不同事件、不同操作發生時,做我們期望的事情。

connect_server()

mysql-client向proxy發起連接時,proxy會調用這個函數。用戶可以實現該函數,來做一些負載均衡的事情,例如選擇將要連向那個mysql-server。假設有多個mysql-server後端,而用戶又沒有實現這個函數,proxy默認採用輪詢(round-robin)策略。

read_handshake()

mysql-server向proxy返回「初始握手信息」時,proxy會調用這個函數。用戶可以實現這個函數,來做更多的權限驗證工作。

read_auth()

mysql-client向proxy發送認證報文(user_name, password,database)時,proxy會調用這個函數。

read_auth_result()

mysql-server向proxy返回認證結果時,proxy會調用這個函數。

read_query()

認證完成後,mysql-client每次經過proxy向mysql-server發送query報文時,proxy會調用這個函數。用戶如果要攔截請求,就可以模擬mysql-server直接返回了,當然用戶亦可以實現各種策略,修改請求,路由請求等各種不同的業務邏輯。

read_query_result()

認證完成後,mysql-server每次經過proxy向mysql-client返回query結果時,proxy會調用這個函數。需要注意,如果用戶沒有顯示實現read_query()函數,則read_query_result()函數是不會被調用的。用戶可以在此處實現各種合併策略,或者對結果集進行修改。

【SK畫外音:下圖是一個各hook函數的觸發圖(請注意請求方向)】

【SK繼續畫外音:可以發現,最重要的兩個函數其實是read_query()和read_query_result(),各種sql的改寫與結果集的改寫邏輯,都是在這兩個函數中實現的,更細節的query過程如下圖】

案例一: sql時間統計分析

不妨設mysql-client提交的原sql為:SELECT * FROM City;

proxy可以在read_query()裡將其改寫為:SELECT NOW(); SELECT *FROM City; SELECT NOW();

這樣在返回結果集時,就可以在應用層對sql時間進行記錄,以方便統計分析。

案例二:sql性能統計分析

不妨設mysql-client提交的原sql為:SELECT * FROM City;

proxy可以在read_query()裡將其改寫為: SELECT * FROM City; EXPLAIN SELECT * FROMCity;

這樣在返回結果集時,就可以在應用層對sql性能進行記錄,以方便統計分析。

需要強調的是,這兩個案例,由於proxy在read_query()時對sql進行了改寫,故在read_query_result()時,mysql-server其實返回了比原請求更多的信息,proxy一定要將多餘的信息去掉,再返回mysql-client。多說一句,可以加入一個唯一ID,來對請求sql和返回結果進行配對。

demo

需求:在業務層統計sql日誌

實現:tutorial-basic.lua

1 -- 如果是COM_QUERY,就將內容列印出來

2 functionread_query( packet )

3 if string.byte(packet) == proxy.COM_QUERYthen

4 print("we got a normal query:" .. string.sub(packet, 2))

5 end

6 end

修改配置並重啟proxy:

proxy-lua-script = tutorial-basic.lua

客戶端使用黑黑的窗口連接4040埠的proxy,並進行一系列sql操作,操作序列如下:

mysql -h127.0.0.1 -uroot -P4040

show databases;

use im;

show tables;

select * from user;

quit

通過tutorial-basic.lua,會將上述操作都記錄到日誌中,日誌序列如下:

we got a normal query: select @@version_comment limit1

we got a normal query: show databases

we got a normal query: SELECT DATABASE()

we got a normal query: show tables

we got a normal query: select * from user

【SK畫外音:咦,通過這個日誌我才知道,連上資料庫會默認發一個select @@version_comment limit 1的請求呢。use im;這個請求,為啥變成SELECT DATABASE()了呢?】

四、FAQ

(1)如何實現最簡單的讀寫分離?

shell> mysql-proxy \

--proxy-backend-addresses=10.0.1.2:3306 \

--proxy-read-only-backend-addresses=10.0.1.3:3306

(2)mysql proxy支持所有版本的mysql麼?

只支持mysql5.0+的mysql協議。

(3)如果開啟負載均衡,那事務怎麼辦?所有的query會發往同一臺mysql麼?

如果用戶不專門定製Lua腳本,會發往同一臺mysql,以保證其完整性。

(4)系統上下文切換代價大麼?Lua腳本引入的額外開銷有多大?

Lua很快,對於大部分應用來說,額外開銷很小,原始包(raw packet)開銷大概在400微秒左右。

【SK畫外音:這,,,我不太相信】

(5)Lua腳本可以動態加載麼?

升級了Lua腳本,連接建立後才會讀取新的喲。

(6)如果proxy和mysql部署在一臺機器上,有什麼需要建議的呢?

proxy單獨部署也可以,和mysql部署在同一臺機器上也可以。相比mysql而言,proxy不怎麼佔CPU和內存,其性能損耗可以忽略不計。

【SK畫外音:這,,,性能損耗可以忽略,這我也不信】

(7)Lua腳本是預讀到內存裡的吧?還是說每次都要到文件系統裡讀?

客戶端連接過來時,或者腳本更新時會讀取,其他的時候都讀內存喲。

(8)加入客戶端連上來,出發了connect_server()函數,Lua腳本能連接多個mysql麼?

可以,使用指引裡有樣例代碼喲。

(9)proxy可以處理SSL連接麼?

不可以,作為中間人,不能處理加密信息。

(10)proxy不會獲取和保存我的明文密碼吧?

不會,也獲取不到。mysql協議不允許密碼以明文傳輸,傳輸的都是加密後的密文。

(11)有隔離問題,調試問題的工具麼?如果請求出錯了,我怎麼知道錯誤發生在mysql客戶端,還是mysql服務端,還是proxy呢?

你可以自己在proxy裡設置debug腳本進行調試,例如設置斷點什麼的。

(12)瞧你官網吹的,有哪個大網站用了mysql-proxy麼?請求量是什麼級別?

這問題問的,作為官網我,,,蓋亞在線(http://www.gaiaonline.com/) 就是用的mysql-proxy喲,qps可以到2400。

【SK畫外音:這是個外國的遊戲網站,頁面好醜啊。】

(13)如果我在Lua腳本用使用LuaSocket可以麼?

大哥,這可能引起阻塞的,強烈不建議這樣。

相關焦點

  • MySQL-ProxySQL中間件(一)
    ProxySQLProxySQL作為一款強大的中間件為MySQL的架構提供了有力的支持。目前可以很好的支持 Master Slave\ MGR \ PXC等,並提供連接池、讀寫分離、日誌記錄等功能,當然還有很多其他實用功能,這裡不一一列舉了。
  • ToughProxy V1.0.0.1 發布,面向運營的代理伺服器軟體
    DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;GRANT ALL ON toughproxy.* TO proxyuser@'127.0.0.1' IDENTIFIED BY 'proxypwd' WITH GRANT OPTION;FLUSH PRIVILEGES;創建資料庫表
  • 詳解MySQL|MySQL中間件DBLE-第五章 後端資料庫相關特性-愛可生
    後端資料庫的相關特性主要從讀寫分離、連接管理、上下文同步以及高可用故障切換四個方面拆分講解;讀寫分離與高可用故障切換是社區同學反饋中需求最大的部分,本節內容十分詳盡的講解了大家關注的關鍵技術點及相關處理細節,有助於增進對分布式應用的相關理解。
  • PHP資料庫編程之MySQL優化策略概述
    雖然我們對資料庫的讀取寫入速度上卻是無能為力,但在一些資料庫類擴展像memcache、mongodb、redis這樣的數據存儲伺服器的幫助下,PHP也能達到更快的存取速度,所以了解學習這些擴展也是非常必要,這一篇先說一下MySQL常見的優化策略。
  • SpringBoot + MyBatis + MySQL讀寫分離實踐!
    引言讀寫分離要做的事情就是對於一條SQL該選擇哪個資料庫去執行,至於誰來做選擇資料庫這件事兒,無非兩個,要麼中間件幫我們做,要麼程序自己做。因此,一般來講,讀寫分離有兩種實現方式。第一種是依靠中間件(比如:MyCat),也就是說應用程式連接到中間件,中間件幫我們做SQL分離;第二種是應用程式自己去做分離。
  • 你不知道的 Proxy
    下面阿寶哥將簡單介紹 Reflect 對象所支持的一些靜態方法。3.2 Reflect 對象支持的靜態方法Reflect 的所有屬性和方法都是靜態的,該對象提供了與 Proxy handler 對象相關的 13 個方法。
  • Proxy使用詳解
    2、代理實例中沒有指定的handler,實際就是操作原對象target:實例:打開控制臺查看:http://jsrun.net/3RLKp/editlet target = function(){return 'ddd'}let proxy = new Proxy(target, {});proxy.prototype.age
  • Linux下MySQL的一些基本使用方法
    資料庫安裝好後,我們應該為mysql資料庫創建一個管理帳號。2]如何進入mysql資料庫?如果自己想學的弟兄,也不是什麼難事;在windows中操作過mysql的,其實在這裡也是一樣的,mysql是跨平臺的資料庫,用法都是相同的。在mysql資料庫中,每操作一個命令,都是;號結尾的,可能有的新手弟兄,忘記輸入了;號結尾,結果退不出來。:):)1]查看mysql中都有哪些資料庫?
  • SpringBoot+MyBatis+MySQL讀寫分離(實例)
    引言讀寫分離要做的事情就是對於一條SQL該選擇哪個資料庫去執行,至於誰來做選擇資料庫這件事兒,無非兩個,要麼中間件幫我們做,要麼程序自己做。因此,一般來講,讀寫分離有兩種實現方式。第一種是依靠中間件(比如:MyCat),也就是說應用程式連接到中間件,中間件幫我們做SQL分離;第二種是應用程式自己去做分離。
  • .NET Core中間件的註冊和管道的構建(2)---- 用UseMiddleware擴展方法註冊中間件類
    在上面這個中間件類中Invoke就是這個方法。為了能夠調用下一個中間件,當前中間件還需要保存下一個中間件的引用。這個引用是通過構造函數傳進來的,如果當前中間件不需要調用後面中間件的話,這個引用完全可以不保存。如果要註冊這個中間件,我們可以這樣做:
  • Mysql--show命令
    * 顯示所有的資料庫名稱mysql root@localhost:sakila> show
  • mysql分表的3種方法
    例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等有人會問mysql集群,和分表有什麼關係嗎?雖然它不是實際意義上的分表,但是它起到了分表的作用。做集群的意義是什麼呢?為一個資料庫減輕負擔,說白了就是減少sql排隊隊列中的sql的數量。
  • Dynamic-proxy
    Dynamic-proxy<dependency>    <groupId>net.neoremind</groupId>    <artifactId>dynamicproxy
  • MySQL InnoDB Cluster環境搭建和簡單測試
    你要說還有一些方案補充,比如MySQL Cluster,MySQL Proxy,這些的使用率個人感覺還是不高,也就是經受的考驗還不夠,原因有很多,就不贅述了。   不久,我和一個MySQL DBA有了下面的一個基本對話。    我: MySQL GR GA之後,裡面的自動切換功能確實很贊,能夠做到讀寫分離,原本MHA的方案現在MGR也可以做了。
  • 架構秘笈:移花接木,使用MySQL模擬Redis
    一個mysql協議的後面,可能是tidb;一個linux機器後面,可能是一個精簡的docker;你覺得xjjdog是個女的,但可能ta自己也不太清楚;而當你大呼php萬歲的時候,可能是研發人員和你開個玩笑,重寫了後綴,而後端用的卻是java。
  • 前端如何正確使用中間件?
    阿里妹導讀:中間件可以算是一種前端中常用的」設計模式「了,有的時候甚至可以說,整個應用的架構都是使用中間件為基礎搭建的。那麼中間件有哪些利弊?什麼才是中間件正確的使用姿勢?本文將分享作者在實際使用中的一些想法,歡迎同學們共同討論。文末福利:下載《大促背後的前端核心業務實踐》電子書。
  • 終於學會了 MySQL 主從配置和讀寫分離
    mysql -h 192.168.0.101 -uroot -p這就需要資料庫中間件來幫忙了,現在比較流行的中間件有Atlas、Cobar、Mycat、Sharding-Sphere,具體選擇哪個或者自研,要看各個公司的標準了。Sharding-Sphere 包括 ShardingSphere-JDBC 和 ShardingSphere-Proxy。