Mysql Hunter
一、簡(jiǎn)介
自動(dòng)化實(shí)施的過程中,我們通常都面臨一個(gè)棘手的問題:數(shù)據(jù)的準(zhǔn)備和恢復(fù)。即在成功執(zhí)行一個(gè)自動(dòng)化用例時(shí),我們可能需要一定的數(shù)據(jù)前提,而為了使得整個(gè)前提不至于被其他的用例破壞,以至于我們有時(shí)不得不在自動(dòng)化用例編寫過程中手工的添加許多Insert、Update、Delete語句來保證數(shù)據(jù)被恢復(fù)到我們執(zhí)行用例前的狀態(tài)。?
使用phpunit等工具框架進(jìn)行php自動(dòng)化單元測(cè)試的過程中也同樣面臨數(shù)據(jù)準(zhǔn)備和恢復(fù)的問題。單元測(cè)試開發(fā)人員開發(fā)過程中不得不編碼中顯示編寫數(shù)據(jù)準(zhǔn)備,驗(yàn)證,恢復(fù)的代碼,這樣會(huì)帶來以下幾個(gè)缺點(diǎn):
1、用例閱讀性降低,難于辨別主要的測(cè)試邏輯?
2、用例可維護(hù)性降低,當(dāng)數(shù)據(jù)庫(kù)的表結(jié)構(gòu)略微有變化或者業(yè)務(wù)底層邏輯有變動(dòng),數(shù)據(jù)的準(zhǔn)備和恢復(fù)的代碼都將有可能面臨修改甚至重寫?
3、極大消耗開發(fā)人員開發(fā)成本,用例編寫過程中不得不額外花很多的時(shí)間去思考數(shù)據(jù)的準(zhǔn)備和恢復(fù)。
基于以上三點(diǎn),考慮設(shè)計(jì)實(shí)現(xiàn)一個(gè)mysql server及client的中間層,通過此中間層,可以將開發(fā)人員的數(shù)據(jù)恢復(fù)操作透明化,且在數(shù)據(jù)環(huán)境穩(wěn)定的前提下,適度的降低開發(fā)人員的數(shù)據(jù)準(zhǔn)備工作。?
基于Hunter擴(kuò)展,將來可能帶來:?
1、自定義Mysql樁(模擬、修改結(jié)果集)?
2、實(shí)時(shí)監(jiān)控Query(已經(jīng)實(shí)現(xiàn),目前可以監(jiān)控query性能)?
3、性能測(cè)試輔助,集成query性能瓶頸分析反饋
二、Amoeba和Hunter的角色
Amoeba for mysql位于Application與數(shù)據(jù)庫(kù)之間,為應(yīng)用提供透明的代理服務(wù)。Amoeba對(duì)外接口采用 mysql protocol,沒有定義自己的協(xié)議和接口,使得任何mysql的應(yīng)用都能方便的使用Amoeba,諸如php、java、c等等的cennector。Amoeba本身沒有Build 任何 SQL語句,而是直接接收client的SQL、命令等進(jìn)行代理轉(zhuǎn)發(fā),Amoeba采用 SQL、命令等 mysql protocol規(guī)范作為統(tǒng)一的接口,完備性得到了保證,能夠完成mysql的所有功能操作。
三、 安裝
Mysql Hunter不需要編譯,僅需要Java運(yùn)行環(huán)境(JRE1.5以上)。
先決條件 :
1、Java SE 1.5或以上Amoeba 框架是基于JDK1.5開發(fā)的,采用了JDK1.5的特性 支持Mysql協(xié)議版本10(mysql 4.1以后的版本)?
2、網(wǎng)絡(luò)環(huán)境至少運(yùn)行有一個(gè)mysql 4.1以上的服務(wù)?
操作步驟 :
1、 設(shè)置環(huán)境變量,在~/.bashrc中加入JAVA_HOME=/JRE的安裝路徑 /?
2、 將程序目錄解壓或拷貝出來,直接運(yùn)行mysql-hunter/bin/amoeba即可啟動(dòng)?
參考參數(shù)配置進(jìn)行配置后啟動(dòng)amoeba,此時(shí)proxy應(yīng)連接到Mysql Server,同時(shí)對(duì)于client而言,mysql servers對(duì)于client是透明的,client認(rèn)為proxy為mysql服務(wù)器直接連接proxy的ip和端口即可正常操作數(shù)據(jù)庫(kù)。
四、 功能介紹
4.1 Amoeba for mysql
Mysql-hunter是基于amoeba框架做的mysql代理擴(kuò)展如圖。
amoeba for mysql本身實(shí)現(xiàn)的功能包括:
讀寫/分離;
失敗重連 ;
負(fù)載均衡 ;
連接池 ;
身份認(rèn)證
4.2 Mysql hunter擴(kuò)展
Mysql-Hunter的功能則主要在于SQL/SQL Result的inject、rewrite以及reverse,如圖:?
從上圖可以看出,mysql hunter可以實(shí)現(xiàn)如下功能:
Client連接server的階段進(jìn)行自定義命令發(fā)送或返回?
Client發(fā)送query cmd至server的階段,進(jìn)行query截取,修改?
同理,Server返回給Client的結(jié)果集也能被hunter監(jiān)控,修改甚至重寫?
特點(diǎn):使用起來很簡(jiǎn)單,只需要設(shè)置start點(diǎn)和end點(diǎn),那么兩者之間所有執(zhí)行的sql query都可以被捕獲、并生成逆命令
?
4.3 基本擴(kuò)展BasicMysqlHunter
BasicMysqlHunter?是一個(gè)基本且實(shí)用的擴(kuò)展實(shí)現(xiàn),繼承自Hunter類,實(shí)現(xiàn)了Hunter的抽象方法 ,可以在client發(fā)送cmd至server前對(duì)query進(jìn)行截獲處理,也可以對(duì)server返回的結(jié)果集進(jìn)行修改。?
BasicMysqlHunter?下的basic handlers這里不再介紹,詳細(xì)請(qǐng)參考《Mysql Hunter總體設(shè)計(jì)》,BasicMysqlHunter目前定位于對(duì)DML query進(jìn)行如下操作:?
分析識(shí)別?
逆向語句及序列生成?
逆向語句的回放,即顯示命令恢復(fù)數(shù)據(jù)庫(kù)數(shù)據(jù)
舉例說明?
Client通過mysql hunter向server發(fā)送了一條query:?
INSERT INTO tblLemma SET title = ‘北京’, content = ‘我愛北京天安門’;?
此時(shí)tblLemma表的自增字段ID變?yōu)榱?00?
Mysql Hunter將分析識(shí)別這條語句,最終生成逆向的恢復(fù)語句序列:?
Stack = (
‘DELETE FROM tblLemma WHERE title = ‘北京’ AND content = ‘我愛北京天安門’ AND ID = 100;’,
‘ALTER TABLE tblLemma SET AUTO_INCREMENT = 99;’,
)
通過順序執(zhí)行stack中的語句,數(shù)據(jù)庫(kù)中的數(shù)據(jù)就將恢復(fù)到insert命令之前的狀態(tài)。
4.4 Sql檢查擴(kuò)展SqlCheckHunter
繼承自Hunter類,實(shí)現(xiàn)了Hunter的抽象方法,用來截獲SQL語句,并對(duì)sql語句進(jìn)行分析,最終給出分析報(bào)告。?
主要用于Sql query的性能分析,極大省去人力的比對(duì)分析,配置簡(jiǎn)單,對(duì)功能測(cè)試透明。?
支持SELECT、INSERT、UPDATE、DELETE語句的常規(guī)經(jīng)驗(yàn)性檢查。?
規(guī)則主要包含:?
mapIssueReason.put(SELECT_REASON_1, "使用的索引為Null,建議檢查SQL涉及表的索引字段是否合理");
mapIssueReason.put(SELECT_REASON_2, "Filesort,所使用的索引對(duì)排序支持不好,如果檢索排序結(jié)果集大建議增強(qiáng)索引");
mapIssueReason.put(SELECT_REASON_3, "查詢結(jié)果集可能對(duì)應(yīng)超過50條記錄,而SQL非翻頁(yè)查詢語句");
mapIssueReason.put(SELECT_REASON_4, "備選索引數(shù)大于1,可以考慮采用force index優(yōu)化");
mapIssueReason.put(INSERT_REASON_1, "連續(xù)采用單語句插入相同的表大于100次,建議考慮:1. 寫合并;2. 采用LOAD DATA INFILE;3. 調(diào)節(jié)bulk_insert_buffer_size變量");
mapIssueReason.put(INSERT_REASON_2, "INSERT...SELECT...語句,請(qǐng)查看該語句的SELECT性能是否可接受");
mapIssueReason.put(UPDATE_REASON_1, "UPDATE語句,未包含where條件字段,進(jìn)行全表更新操作效率低");
mapIssueReason.put(UPDATE_REASON_2, "UPDATE語句,WHERE字句不能使用索引找到被更新記錄或修改范圍過大");
mapIssueReason.put(UPDATE_REASON_3, "UPDATE語句連續(xù)更新相同表大于100次,建議考慮:1. 寫合并;2. 如果有索引,索引更新可能過于頻繁,適當(dāng)修改縮減索引");
mapIssueReason.put(DELETE_REASON_1, "DELETE語句刪除全表,建議使用truncate語句");
mapIssueReason.put(DELETE_REASON_2, "DELETE語句,WHERE字句不能使用索引找到被更新記錄或修改范圍過大");
mapIssueReason.put(DELETE_REASON_3, "DELETE語句連續(xù)更新相同表大于100次");
4.5 參數(shù)配置
下面介紹conf文件中所有的配置項(xiàng)。
amoeba.xml :
1. <server> //Amoeba 代理server,即proxy server的配置
/* port: 綁定端口
* ipAddress: 綁定ip
* readThreadPoolSize: 網(wǎng)絡(luò)IO最大線程數(shù)
* user: amoeba 對(duì)外驗(yàn)證所需用戶名
* password: amoeba 對(duì)外驗(yàn)證所需密碼
*/
2. <connectionManagerList> 所使用的連接管理類,通常不需要修改
3. <dbServerList> 后端所連接的數(shù)據(jù)庫(kù)服務(wù)器配置,包括主從所有的DB服務(wù)器
* <dbServer>
/* port: 真實(shí)mysql數(shù)據(jù)庫(kù)端口
* ipAddress: 真實(shí)mysql數(shù)據(jù)庫(kù)ip
* schema: 默認(rèn)的數(shù)據(jù)庫(kù)schema
* user: 連接該db所需的用戶名
* password: 連接該db所需的相應(yīng)用戶的密碼
*/
* <poolConfig>: 對(duì)象池,通常不需要修改
4. <dbServer name="multiPool" virtual="true"> 設(shè)定參與負(fù)載均衡的服務(wù)器
/* loadbalance: 負(fù)載均衡設(shè)定:1為輪詢 2為權(quán)重
* poolNames: 以逗號(hào)分隔如,server1,server2,server3…
*/
5. <queryRouter> 所用的query分發(fā)路由相關(guān)配置
/* writePool: 寫操作池包含的數(shù)據(jù)庫(kù)服務(wù)器
* readPool: 讀操作池包含的數(shù)據(jù)庫(kù)服務(wù)器
* needParse: 是否需要進(jìn)行query parse
*/
高亮的配置項(xiàng)是重新部署DB環(huán)境的時(shí)候通常需要關(guān)注的配置項(xiàng)。<br>
// 擴(kuò)展配置
<extension>
<hunter class="com.meidusa.amoeba.extend.BasicMySqlHunter"></hunter>
</extension>
設(shè)定使用的hunter擴(kuò)展是BasicMysqlHunter。
?
log4j.xml?
日志打印的配置,通常不需要修改。如果需要額外的增加日志格式,或者修改日志格式,級(jí)別可以參考log4j的文檔,或者參考本配置文件的其他配置方法。
BasicMysqlHunter?目前提供三條自定制命令:?
1 select start:開始啟用擴(kuò)展,擴(kuò)展將開始監(jiān)控select start執(zhí)行之后流經(jīng)Hunter的DML命令并求逆;Hunter直接返回Ok packet?
2 select print_stack:打印當(dāng)前Hunter上下文中的逆命令堆棧?
3 select end:結(jié)束擴(kuò)展監(jiān)控,并將Hunter上下文中的逆向命令棧依順序pop出棧并發(fā)送Server恢復(fù)DB數(shù)據(jù);Hunter直接返回Ok packet
$link = mysql_connect('127.0.0.1:3307', 'mysql_user', 'mysql_password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
// Case執(zhí)行前
$result = mysql_query("select start");
/*
* Case 執(zhí)行
* 執(zhí)行過程中可以自身或用其他客戶端發(fā)送select print_stack命令check當(dāng)前逆命令棧
*/
// Case執(zhí)行后
$result = mysql_query("select end");
// 此時(shí)Case執(zhí)行過程中的所有DML操作將被還原
五、使用注意
5.1 Mysql Hunter不支持的操作
Mysql Hunter(確切的說是BasicMysqlHunter)已經(jīng)支持了絕大部分常用的DML語句,目前已知的不支持的query類型包括:?
DML語句的多表操作,例如一個(gè)query中同時(shí)修改update表A和表B的字段,暫時(shí)沒有實(shí)現(xiàn)逆語句生成,僅能轉(zhuǎn)發(fā)?
未實(shí)現(xiàn)UPDATE語句中包含order by limit的語句的逆語句生成,僅能轉(zhuǎn)發(fā)?
暫不支持改變表結(jié)構(gòu)和用戶屬性權(quán)限的語句,ALTER TABLE、TRUNCATE TABLE、CREATE TABLE、DROP TABLE、GRANT、ALTER USER等,僅能轉(zhuǎn)發(fā)?
不支持非DML語句,僅能轉(zhuǎn)發(fā)?
內(nèi)置函數(shù)支持有限,根據(jù)實(shí)際應(yīng)用過程中的使用情況增加對(duì)內(nèi)置函數(shù)的擴(kuò)展并求逆(目前已支持now())
5.2 Mysql Hunter日志使用
Mysql Hunter運(yùn)行時(shí)日志記錄在:?
log/hunter.log 正常日志?
log/hunter.log.wf 錯(cuò)誤日志?
正常日志會(huì)打印所有流經(jīng)proxy層的query cmds,以及hunter的關(guān)鍵執(zhí)行步驟的log,通常不應(yīng)出現(xiàn)錯(cuò)誤日志,如果出現(xiàn)了錯(cuò)誤日志有兩種情況:?
hunter不支持的操作?
hunter自身的bug?
利用hunter.log有時(shí)可以輔助我們定位問題,甚至可以拋棄mysql的query.log
(作者:weichenxi)
?
【本文轉(zhuǎn)自百度測(cè)試技術(shù)空間】http://hi.baidu.com/baiduqa/blog/item/69fc0553d19d8f9b8c543004.html
【關(guān)注百度技術(shù)沙龍】本文轉(zhuǎn)自百度技術(shù)51CTO博客,原文鏈接:http://blog.51cto.com/baidutech/744475,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的Mysql Hunter的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS prototype作用
- 下一篇: PLSQL 之类型、变量和结构