記一次基於LR的UDP和TCP效能測試
背景
最近專案要做效能測試,要出要一份效能報告,讓我出一個有關Tcp和Udp的功能模組的測試,流程大概是這樣,先走TCP協議協商一下會話,協商成功後走Udp收發資料。
有點簡單啊,自己寫個功能模組測一下,然後把結果展示出來就ok了。
然而想法很美好,現實有點殘酷。idea瞬間被pass掉,理由就是自己寫的測試模組木有說服力。
要用專業的測試工具來搞,才有說服力。作為一名開發,用測試工具是不可能的,就算餓死也不會用!!!
最後還是學了一下LoadRunner,在歷經一番坎坷摸索之後,出了個測試指令碼。不得不說,LR真的挺好用的。(PS:真香現場)
不說廢話了,在網上找了一下使用LR測試TCP和UDP的指令碼,資料有點難找,大多都是簡單概況一下。(讓我一個LR初手,搞不定啊),最後在自己一番摸索之下,把過程整理一下,要有啥不好的地方,還請多指教一下。
準備工作
- LoadRunner 環境,這個大家自行百度,教程太多我就不詳說了
- 資料包,客戶端進行TCP協商的資料包,使用udp傳送的資料包(用wireshark抓取)
- LR的測試指令碼
編寫測試指令碼
使用LR測試TCP和UDP要使用LR中Windows sockets協議,它可以模擬tcp/ip協議和伺服器進行資料互動,這樣便可以模擬終端來進行效能測試了。首先開啟LR Virtual User Generator選擇建立指令碼。
圖:建立指令碼
選擇建立windows sockets協議的指令碼。
圖:選擇socket協議
接著會出來一個錄製選項框,在應用型別裡有兩種選擇,一種是win32的應用,一種是瀏網路應用,選擇後可以開始錄製指令碼,會啟用對應的應用,根據操作錄製指令碼。
圖:初始化引數
我這邊使用網路應用,輸入要測試服務的URL,選擇對應的action,然後點選ok就可以開始錄製。
這裡可以選擇的活動對應有三種
- vuser_init:建立虛擬使用者初始化時做的事情, 比如要測試業務某個具體業務操作環節時,可以先把系統使用者登入的寫在init中。
- action: 使用者操作的事件,即需要測試業務操作點。
- vuser_end:虛擬使用者退出的時候做到操作,如關閉socket等。
不過錄制指令碼這個功能生成的測試指令碼有的時候不符合我們的預期,還是要自己修改,所以我這裡隨便錄製了一下,然後重寫指令碼。
圖:結束錄製
點選結束錄製,會生成指令碼,如下圖,然後我們就可以自己修改指令碼了。
最後就是最關鍵的地方了,根據具體業務流程來編寫測試指令碼,我這裡總體業務流程大致如下
編寫vuser_init
我這裡由於要協商會話,所以在初始化時需要傳送兩次請求和接受兩次請求,指令碼如下
vuser_init() { char*recvbuf; int recvlen=0; int rc=0; lrs_startup(257); //設定開始事務 lr_start_transaction("Trans_Session"); lr_start_transaction("Conn_TCP"); //建立socket rc=lrs_create_socket("socket0","TCP","LocalHost=0","RemoteHost=127.0.0.1:8888",LrsLastArg); //判斷套接字建立是否成功 if(rc!=0){ lr_end_transaction("Conn_TCP",LR_FAIL); lr_end_transaction("Trans_Session",LR_FAIL); return 0; } lr_end_transaction("Conn_TCP",LR_PASS); //判斷socket是否連結成功的事務,0表示建立成功 lrs_send("socket0","senCreateReqBuf",LrsLastArg); //傳送安全會話建立請求,senCreateReq為在data.ws中定義的傳送變數 lrs_receive("socket0","senCreateRspBuf",LrsLastArg); //接收訊息,存放在senCreateReq中,senCreateReq是在data.ws中定義的接收陣列,注意陣列長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket0",&recvbuf,&recvlen);//把Socket最後接收的位元組陣列,長度放在recvlen中,內容放在recvbuf中 if(recvlen<100) { lr_end_transaction("Trans_Session",LR_FAIL); } lrs_send("socket0","authReqBuf",LrsLastArg); //傳送authRsp,authRsp為在data.ws中定義的傳送變數 lrs_receive("socket0","authRspBuf",LrsLastArg); //接收訊息,存放在authRep中,authRep是在data.ws中定義的接收陣列,注意陣列長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket0",&recvbuf,&recvlen);//把Socket最後接收的位元組陣列,長度放在recvlen中,內容放在recvbuf中 if(recvlen>60) lr_end_transaction("Trans_Session",LR_PASS); else lr_end_transaction("Trans_Session",LR_FAIL); return 0; }
1. 首選建立相關測試的事務,在效能測試中這個可以作為測試用例通過的依據lr_start_transaction與lr_end_transaction 為使用最多的事物創造組合函式,lr_start_transaction為事物開始函式,lr_end_transaction為事物結束函式,並負責記錄事物的執行時間.
語法格式如下:
- int lr_start_transaction (const char * transaction_name);
- int lr_end_transaction (const char * transaction_name,int status);
transacton為事物名稱,status為事物的結束狀態,共有LR_PASS(通過)、LR_FAIL(失敗)、LR_AUTO(自動)、 LR_STOP(暫停),其中LR_PASS預設的是LR_PASS,可以在事物結束前通過lr_set_transaction_status進行修改。如果在lr_end_transaction中沒有指定結束事物狀態是LR_AUTO,而是明確制定為LR_PASS、LR_FAIL、 LR_STOP其中的其中,則事物將以最後制定狀態來結束。需要注意,事物開始沒有lr_end_transaction沒有結束的時候,不能用相同的事 物名稱,除非這個事物已經通過lr_end_transaction結束。
2. 接著建立socket,初始化套接字,使用的函式如下
- int lrs_create_socket("socket0","TCP","LocalHost=0","RemoteHost=127.0.0.1:8888",LrsLastArg);
引數分別是:socket名稱、協議型別(TCP或UDP)、連結型別(遠端連結:RemoteHost、本地:LocalHost、或者本地監聽)、LrsLastArg 引數結束標記,建立成功返回0。
3. 建立完套接字後,判斷時候成功,若是失敗將對應的事務狀態修改為LR_FAIL。
4.通過socket傳送資料,lrs_send("socket0","senCreateReqBuf",LrsLastArg); 這裡senCreateReqBuf為待發送的資料,資料存在data.ws檔案中。
send 填的是傳送資料buf的名稱,在後面跟上待發送資料的長度 傳送的資料在LR中我這邊是以16進位制傳送,按照LR的規則需要在16進制中加上\x,很明顯構造這個資料還是麻煩的很。不過這裡有一個比較方便的方式,
我們可以從wireshark中直接抓取對應格式的資料,選擇需要的資料,右鍵複製,選擇轉義字串,就可以了,然後將複製的資料放在data.ws中就可以了。
5.接收響應資料,判斷響應資料是否正確,我這裡根據長度來判斷。
編寫Action
在Action檔案中編寫需要測試的操作步驟,我這裡就是傳送udp請求,接受響應,判斷響應是否正確,程式碼如下
Action() { char*recvbuf; int recvlen=0; int rc=0; lr_start_transaction("Trans_UDP"); lr_start_transaction("Conn_UDP"); rc=lrs_create_socket("socket1","UDP","RemoteHost=127.0.0.1:8887",LrsLastArg); if (rc != 0) { lr_end_transaction("Conn_UDP",LR_FAIL); lr_end_transaction("Trans_UDP",LR_FAIL); return 0; } lr_output_message("Received:%d",rc); lr_end_transaction("Conn_UDP",LR_PASS); lrs_send("socket1","ReqBuf",LrsLastArg); //傳送ReqBuf,ReqBuf為在data.ws中定義的傳送變數 lrs_receive("socket1","RspBuf",LrsLastArg); //接收訊息,存放在RspBuf中,RspBuf是在data.ws中定義的接收陣列,注意陣列長度一定要大於等於實際接收長度 lrs_get_last_received_buffer("socket1",&recvbuf,&recvlen);//把Socket最後接收的位元組陣列,長度放在recvlen中,內容放在recvbuf中 if(recvlen>=128) { lr_end_transaction("Trans_UDP",LR_PASS); } else { lr_log_message("Error UDP Received length:%d",recvlen); lr_end_transaction("Trans_UDP",LR_FAIL); }
//--------------斷開socket-------------- lrs_disable_socket("socket1",DISABLE_SEND_RECV); //--------------關閉socket-------------- lrs_close_socket("socket1"); return 0; }
原理和上文提的基本一致,這裡就不再多說了
編寫vuser_init
編寫結束時的操作,這裡就是關閉init中的socket
vuser_end() { //--------------斷開socket-------------- lrs_disable_socket("socket0", DISABLE_SEND_RECV); //--------------關閉socket-------------- lrs_close_socket("socket0"); return 0; }
執行測試指令碼
點選start,執行指令碼,執行無誤,說明指令碼正確
至此測試指令碼編寫完畢,可以正式開始效能測試了
效能測試
- 始執行LR執行效能測試
- 這裡我們將剛剛編寫好的的測試指令碼新增進去
- 然後配置相關的測試引數,如併發數,測試時間等,開始測試
- 觀察測試結果
最後在執行結束後,我們可以根據分析報告診斷效能測試結果,還可以配合jvisualvm工具診斷熱點方法,提升程式效能
總結
我們可以LR可以配合jvisualvm工具診斷熱點方法,提升程式效能。如果有大神看出什麼端倪的話,歡迎批評斧正,個人感覺還有提升