loadrunner教程 如何保存api服务器返回的内容

扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
Loadrunner脚本的录制与调试
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口1465人阅读
最近对服务器的性能感兴趣,于是开始研究了一阵子loadrunner如何做采用TCP协议交互的服务器的性能测试,对loadrunner不是很熟悉,所以一开始也走了一些弯路,现将学习的过程记录下来,为以后做参考吧。
TCP协议的服务器的性能测试,我想大家都会选择loadrunner的winsocket协议进行测试,我也是采用此种方式。下面将逐一记录如何使用此协议做性能测试。
1.采用DLL文件方式进行测试
由于与服务器连接的客户端的DLL文件我手头有,同时其对应的头文件也有,所以一开始试想的是采用loadrunner调用DLL文件的方式来实现性能测试。因为这种方式简单,不需了解很多loadrunner的winsocket的相关函数,容易上手。下面的代码即是采用DLL文件初步编写的代码:
vuser_init.c
vuser_init()
lrs_startup(257);
lr_load_dll(&InnoVSSBASClient.dll&);
lr_load_dll(&ole32.dll&);
#include &lrs.h&
#include &def.h&
NET_CLIENT_INFO
NET_CROSS_INFO crossI
NET_VEHCILE_PASS_INFO lrPassInfo = {0};
NET_VEHCILE_ALARM_INFO lrAlarmInfo = {0};
handle = InnoVSSBASClient_Init(NULL,NULL);
strcpy(info.clientId,guid_gen());
strcpy(info.serverIP,&127.0.0.1&);
info.serverPort = 9300;
strcpy(info.username,&admin&);
strcpy(info.password,&admin&);
lr_start_transaction(&tran_login_start&);
isLogin = InnoVSSBASClient_CreateConn(handle,&info);
if(isLogin==1){
lr_end_transaction(&tran_login_start&, LR_AUTO);
lr_output_message(info.clientId);
lr_output_message(&登陆成功&);
//InnoVSSBASClient_SetCallbackFunc(handle,InnoVSSBASClientCallback,1L);
lr_start_transaction(&tran_addcross_start&);
strcpy(crossInfo.crossId,lr_eval_string(&{crossId}&));
InnoVSSBASClient_AddCrossInfo(handle,&crossInfo);
lr_end_transaction(&tran_addcross_start&, LR_AUTO);
lr_end_transaction(&tran_login_start&, LR_FAIL);
lr_output_message(info.clientId);
lr_output_message(&登陆失败&);
sleep(100);
}vuser_init中加载了程序所需要的DLL文件,InnoVSSBASClient.dll为与服务器连接的客户端的DLL文件,而ole32.dll为程序中的字符串函数(比如strcpy等)需要加载的DLL文件。
action中则是性能测试的主体代码。本代码一共对两个操作:登录和添加路口信息做了事务监控。
采用DLL文件的方式针对测试简单的顺序的操作很适用,但是本客户端还有个功能是需要处理服务器实时传输的过车等信息的功能,即在测试服务器端功能的时候,还需要模拟出客户端的回调函数的功能,但是在loadrunner中没有找到定义回调函数的方式,于是不得不放弃这种简单的性能测试的方式。在此想向loadrunner的大牛问一下,如何在loadrunner中第一回调函数呢?
上面的方式不能真实的模拟客户端的情况,于是下面会记录采用loadrunner本身的winsocket函数进行测试。
2.采用loadrunner的winsocket函数做测试
我先上源码,然后逐一讲解:
def.h //本文件是外部文件,在此用于定义自定义函数
char* guid_gen(){
//生成GUID方法
typedef struct _GUID
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
char buf[50];
char pNameStr[50];
CoCreateGuid(&m_guid);
// 定义输出格式
//sprintf (buf, &{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}&, // 大写
//sprintf (buf, &{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}&,// 小写
sprintf (buf, &%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x&,// 小写%08lx-%04x%04x-%02x%02x%02x%02x-%02x%02x%02x%02x
m_guid.Data1, m_guid.Data2, m_guid.Data3,
m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],
m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);
//lr_save_string(buf, paramName);
//sprintf(pNameStr,&{%s}&,paramName);
return lr_eval_string(buf);
char* join(char *s1, char *s2)
char *result = (char*)malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
//in real code you would check for errors in malloc here
if (result == NULL) exit (1);
strcpy(result, s1);
strcat(result, s2);
// 字符串替换函数.
// 能替换所有的要替换的字符串,被替换的字符串和替换的字符串不一定一样长.
// pInput - 输入字符串.
// pOutput - 输出字符串, 要保证足够的空间可以存储替换后的字符串.
// pSrc - 要被替换的子字符串, 比如%user%
// pDst - 要替换成的字符串, 比如user1
// 注意:以上的字符串均要以'\0'结尾.
void Substitute(char *pInput, char *pOutput, char *pSrc, char *pDst)
*pi, *po, *p;
nSrcLen, nDstLen, nL
// 指向输入字符串的游动指针.
// 指向输出字符串的游动指针.
// 计算被替换串和替换串的长度.
nSrcLen = strlen(pSrc);
nDstLen = strlen(pDst);
// 查找pi指向字符串中第一次出现替换串的位置,并返回指针(找不到则返回null).
p = (char*)strstr(pi, pSrc);
// 计算被替换串前边字符串的长度.
nLen = (int)(p - pi);
// 复制到输出字符串.
memcpy(po, pi, nLen);
memcpy(po + nLen, pDst, nDstLen);
// 跳过被替换串.
pi = p + nSrcL
// 调整指向输出串的指针位置.
po = po + nLen + nDstL
// 继续查找.
p = (char*)strstr(pi, pSrc);
// 复制剩余字符串.
strcpy(po, pi);
// 没有找到则原样复制.
strcpy(po, pi);
/* @param char* dest 目标串,也就是替换后的新串
* @param const char* src 源字符串,被替换的字符串
* @param const char* oldstr 旧的子串,将被替换的子串
* @param const char* newstr 新的子串
* @param int len 将要被替换的前len个字符*/
char *strreplace(char *dest, char *src, const char *oldstr, const char *newstr, size_t len)
//子串位置指针
//临时内存区
//如果串相等,则直接返回
lr_output_message(&newStr:%s&,newstr);
if(strcmp(oldstr, newstr)==0)
//把源串地址赋给指针dest,即让dest和src都指向src的内存区域
//如果找到子串, 并且子串位置在前len个子串范围内, 则进行替换, 否则直接返回
while((needle = (char *) strstr(dest, oldstr)) && (needle -dest &= len))
//分配新的空间: +1 是为了添加串尾的'\0'结束符
tmp=(char*)malloc(strlen(dest)+(strlen(newstr)-strlen(oldstr))+1);
//把src内的前needle-dest个内存空间的数据,拷贝到arr
strncpy(tmp, dest, needle-dest);
//标识串结束
tmp[needle-dest]='\0';
//连接arr和newstr, 即把newstr附在arr尾部, 从而组成新串(或说字符数组)arr
strcat(tmp, newstr);
//把src中 从oldstr子串位置后的部分和arr连接在一起,组成新串arr
strcat(tmp, needle+strlen(oldstr));
//把用malloc分配的内存,复制给指针retv
dest = (char *)strdup(tmp);
//释放malloc分配的内存空间
free(tmp);
本文件包含了两种功能的函数:一个是如何生成guid,一个是如何替换字符串中的子串。
/*********************************************************************
* Created by Mercury Interactive Windows Sockets Recorder
* Created on: Tue Dec 30 16:04:06
*********************************************************************/
#include &lrs.h&
#include &def.h&
int sendLoginCount=0,sendCrossCount=0;
int loginIndex,loginIndex2;
char* clientId = guid_gen();
char clientId2[100];
char* clientId3;
int clientI
char* loginSrc = &&?xml version=\&1.0\& encoding=\&UTF-8\& ?&\n&Parament&\n&
&ClientId&$ClientId&/ClientId&\n&
&ServerIP&$IP&/ServerIP&\n&
&ServerPort&$Port&/ServerPort&\n&
&Username&&/Username&\n&
&Password&&/Password&\n&
&&/Parament&&;
char* loginS
int loginStrL
char* loginStrLenH
char loginStrLenStr[5];
char send_loginHeader[100]=&\\x12$Len\\x00\\x010&;
char* send_loginH
char send_loginStr[1500]=&&;
//添加路口相关字符串
char* crossSrc= &&?xml version=\&1.0\& encoding=\&UTF-8\& ?&\n&Parament&\n&
&ClientId&$ClientId&/ClientId&\n&
&CrossId&$CrossId&/CrossId&\n&
&&/Parament&&;
char* send_addCrossHeader = &\\x12$Len\\x00\\x02&;
char* crossId = lr_eval_string(&&db_crossId&&);
char* crossS
char send_crossStr[1700];
char crossStrLenStr[5];
int crossStrL
char* send_addCrossH
int crossAddIndex,crossAddIndex2;
strcpy(clientId2,lr_eval_string(clientId));
clientId3 = clientId;
//登陆数据
loginStr = strreplace(loginStr,loginSrc,&$ClientId&,clientId,strlen(loginSrc));
loginStr = strreplace(loginStr,loginStr,&$IP&,&127.0.0.1&,strlen(loginStr));
loginStr = strreplace(loginStr,loginStr,&$Port&,&9300&,strlen(loginStr));
lr_output_message(&loginStr:%s&,loginStr);
loginStrLen = strlen(loginStr)+1;
//lr_output_message(&loginStrLen:%d&,loginStrLen);
//itoa(loginStrLen,loginStrLenStr,16);
sprintf(loginStrLenStr, &%X&, loginStrLen);
//lr_output_message(&loginStrLenStr:%s&,loginStrLenStr);
if(strlen(loginStrLenStr)==2)
char tmpH[5];
strcpy(tmpH,loginStrLenStr);
strcpy(loginStrLenStr,&\\x00\\x00\\x00\\x&);
strcat(loginStrLenStr,tmpH);
char tmpH[5];
char tmpD[5];
strcpy(tmpH,loginStrLenStr);
strcpy(tmpH+1,&\0&);
strcpy(tmpD,loginStrLenStr+strlen(loginStrLenStr)-2);
strcpy(loginStrLenStr,&\\x00\\x00\\x0&);
strcat(loginStrLenStr,tmpH);
strcat(loginStrLenStr,&\\x&);
strcat(loginStrLenStr,tmpD);
//lr_output_message(&tmpH:%s&,tmpH);
//lr_output_message(&tmpD:%s&,tmpD);
//lr_output_message(&loginStrLenStr:%s&,loginStrLenStr);
send_loginHeaderf = strreplace(send_loginHeaderf,send_loginHeader,&$Len&,loginStrLenStr,strlen(send_loginHeader));
//lr_output_message(&send_loginHeader:%s&,send_loginHeaderf);
strcpy(send_loginStr,send_loginHeaderf);
//lr_output_message(&send_loginStr:%s&,send_loginStr);
for(loginIndex=0,loginIndex2=strlen(send_loginStr);loginIndex&strlen(loginStr);loginIndex++,loginIndex2++)
char loginHex[5];
sprintf(loginHex,&\\x%.2X&,loginStr[loginIndex]);
//strcat(send_loginBody,loginHex);
strcat(send_loginStr+loginIndex2,loginHex);
strcat(send_loginStr+loginIndex2,&\\x0A&);
lr_output_message(&send_loginStr:%s&,send_loginStr);
//创建TCP连接
lr_start_transaction(&login&);
lrs_create_socket(&socket0&, &TCP&, &LocalHost=0&, &RemoteHost=127.0.0.1:1234&,LrsLastArg);
for(sendLoginCount = 0;sendLoginCount & 10;sendLoginCount++)
//lr_output_message(&send_loginStr:%s&,send_loginStr);
lr_output_message(&sendLoginCount:%d&,sendLoginCount);
lrs_set_send_buffer(&socket0&,send_loginStr,strlen(send_loginStr));
lrs_send(&socket0&,&buf0&,LrsLastArg);
lrs_receive(&socket0&, &buf1&, LrsLastArg);
char* login_
int login_
lrs_get_last_received_buffer(&socket0&,&login_recv,&login_recvlen);
if(login_recvlen!=0)
lr_end_transaction(&login&, LR_AUTO);
lr_output_message(&%s&,login_recv+15);
//添加路口
lr_output_message(&clientId3:%s&,lr_eval_string(clientId2));
crossStr = strreplace(crossStr,crossSrc,&$ClientId&,clientId3,strlen(crossSrc));
crossStr = strreplace(crossStr,crossStr,&$CrossId&,crossId,strlen(crossStr));
lr_output_message(&crossStr:%s&,crossStr);
crossStrLen = strlen(crossStr)+1;
sprintf(crossStrLenStr,&%X&,crossStrLen);
if(strlen(crossStrLenStr)==2)
char tmpH[5];
strcpy(tmpH,crossStrLenStr);
strcpy(crossStrLenStr,&\\x00\\x00\\x00\\x&);
strcat(crossStrLenStr,tmpH);
char tmpH[5];
char tmpD[5];
strcpy(tmpH,crossStrLenStr);
strcpy(tmpH+1,&\0&);
strcpy(tmpD,crossStrLenStr+strlen(crossStrLenStr)-2);
strcpy(crossStrLenStr,&\\x00\\x00\\x0&);
strcat(crossStrLenStr,tmpH);
strcat(crossStrLenStr,&\\x&);
strcat(crossStrLenStr,tmpD);
//lr_output_message(&cross_tmpH:%s&,tmpH);
//lr_output_message(&cross_tmpD:%s&,tmpD);
//lr_output_message(&crossStrLenStr:%s&,crossStrLenStr);
send_addCrossHeaderf = strreplace(send_addCrossHeaderf,send_addCrossHeader,&$Len&,crossStrLenStr,strlen(send_addCrossHeader));
//lr_output_message(&send_addCrossHeaderf:%s&,send_addCrossHeaderf);
strcpy(send_crossStr,send_addCrossHeaderf);
//lr_output_message(&send_crossStr:%s&,send_crossStr);
for(crossAddIndex=0,crossAddIndex2=strlen(send_crossStr);crossAddIndex&strlen(crossStr);crossAddIndex++,crossAddIndex2++)
char crossHex[5];
sprintf(crossHex,&\\x%.2X&,crossStr[crossAddIndex]);
//strcat(send_loginBody,loginHex);
strcat(send_crossStr+crossAddIndex2,crossHex);
strcat(send_crossStr+crossAddIndex2,&\\x0A&);
lr_output_message(&send_crossStr:%s&,send_crossStr);
//lr_output_message(&send_loginStr:%s&,send_loginStr);
lr_start_transaction(&addCross&);
for(sendCrossCount=0;sendCrossCount&10;sendCrossCount++)
lr_output_message(&send_crossStr:%s&,send_crossStr);
lr_output_message(&sendCrossCount:%d&,sendCrossCount);
lrs_set_send_buffer(&socket0&,send_crossStr,strlen(send_crossStr));
lrs_send(&socket0&,&buf0&,LrsLastArg);
lrs_receive(&socket0&,&buf1&,LrsLastArg);
char* cross_
int cross_
lrs_get_last_received_buffer(&socket0&,&cross_recv,&cross_recvlen);
if(cross_recvlen!=0)
lr_end_transaction(&addCross&, LR_AUTO);
lr_output_message(&cross_recv:%s&,cross_recv+15);
//lr_end_transaction(&addCross&, LR_FAIL);
if(sendCrossCount&10)
lr_end_transaction(&addCross&, LR_FAIL);
//lr_end_transaction(&login&, LR_FAIL);
if(sendLoginCount&10)
lr_end_transaction(&login&, LR_FAIL);
lrs_receive(&socket0&,&buf3&,LrsLastArg);
lrs_get_last_received_buffer(&socket0&,&recv,&recvlen);
if(recvlen!=0)
lr_output_message(&recv:%s&,recv+15);
lrs_close_socket(&socket0&);
上面代码的具体业务就不介绍了,在此我介绍一下在该片代码中应该注意的地方:
1)本代码模拟了客户端所发的16进制的数据,在此提一下字符、字符串如何转换成loadrunner中的16进制的字符串。
在loadrunner中16进行的字符采用前面加’\x'的方式表示,如16进制0xAB,则在loadrunner中需要表示为'\xAB‘;
整形转为16进制字符串:sprintf(loginStrLenStr, &%X&, loginStrLen);
16进制字符串转换为loadrunner中认可的16进制串:
for(loginIndex=0,loginIndex2=strlen(send_loginStr);loginIndex&strlen(loginStr);loginIndex++,loginIndex2++)
char loginHex[5];
sprintf(loginHex,&\\x%.2X&,loginStr[loginIndex]);
//strcat(send_loginBody,loginHex);
strcat(send_loginStr+loginIndex2,loginHex);
}本部分使用的是本方法,即将字符串“abcd&的的每个字符逐一转换成loadrunner认可的16进制串(如:字符”a&转换成&\x61“)
该方法是个笨方法,不知在loadrunner中有没有自带的函数做字符串的16进制转换呢?
2)loadrunner做winsocket测试的基本步骤:
/*********************************************************************
* Created by Mercury Interactive Windows Sockets Recorder
* Created on: Mon Dec 29 09:01:03
*********************************************************************/
#include &lrs.h&
char *//定义字符指针
int numberOfB//定义int型变量保存长度
//这是第一步initializes a socket
lrs_create_socket(&socket0&, &TCP&, &LocalHost=0&, &RemoteHost=127.0.0.1:1234&,LrsLastArg);
lr_start_transaction(&send&);
//这里是第二步,通过建立的socket1将buf1中的数据发送给远端MM-7QL3Z0JYUJN6用户,端口2425
lrs_send(&socket0&, &buf1&,
LrsLastArg);
//输出缓冲区数据大小
lrs_send(&socket0&, buffer,
LrsLastArg);
//从buf2中接收返回的数据
lrs_receive(&socket0&, &buf2&, LrsLastArg);
//取得缓冲区数据
lrs_get_buffer_by_name(&buf2&, &buffer, &numberOfBytes);
//输出缓冲区数据大小
lr_output_message(&The buffer's size is: %d/n&, numberOfBytes);
lr_output_message(buffer);
lr_end_transaction(&send&, LR_AUTO);
//第三步关闭释放socket连接
lrs_close_socket(&socket0&);
}上面的代码的注释很明确了,不过需要注意一点的是,loadrunner中lrs_send中的缓存的buf需要在data.ws中定义,不能是程序中定义的字符串。
;WSRData 2 1
recv buf1 101
recv buf2 210
recv buf3 300
3)对winsocket编程的一些函数的解释
①lrs_set_send_buffer(&socket0&,send_loginStr,strlen(send_loginStr));
lrs_set_send_buffer将程序中定义的字符串放入data.ws第一个定义的send bufx中,如上面的data.ws中定义的为buf0,则是将其方式buf0中,不管调用多少次,都是放入到buf0中。
②lrs_receive(&socket0&, &buf1&, LrsLastArg);
lrs_get_last_received_buffer(&socket0&,&login_recv,&login_recvlen);
buf1定义的长度与实际接收的长度不一致没关系,loadrunner只会在输出中输出一个警告信息,但是不会影响实际接收的数据。警告信息为:&Mismatch in buffer's length (expected 101 bytes, 222 bytes actually received, difference in 121 bytes)
该loadrunner测试代码在这里可以。
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:163319次
积分:2634
积分:2634
排名:第6843名
原创:98篇
转载:36篇
评论:51条
文章:23篇
阅读:18408利用LoadRunner判断HTTP服务器的返回状态
利用LoadRunner判断HTTP服务器的返回状态
第一种方法:是利用LR的内置函数web_get_int_property。
#include "web_api.h"
int HttpRetC
web_url("网易",
"TargetFrame=_TOP",
HttpRetCode = web_get_int_property(HTTP_INFO_RETURN_CODE);
if (HttpRetCode == 200)
lr_log_message("The Vuser successfully accessed the 网易
lr_log_message("The Vuser failed to access the 网易 page ");
&&& return
第二种方法:另外一种就是最原始的办法,自己取HTTP服务器的数据,然后利用关联函数分析啊.
其实所有的东西都可以通过关联函数从服务器的返回数据中取,然后自己动手解析,呵呵. 举个不太恰当的例子:
你需要一套家具,可以去家具市场挑,当然也可以自己买木材原料和工具,动手加工. 那才是最合乎自己需要的.
关于动态参数化的问题分析;
其实第一次看到这个问题,我没有马上反应过来,后来仔细想想, 明白了. 就是需要参数化的数据不是静态的,是动态的.
比如从中选出来的.
针对这个问题,应该提前从数据源(比如数据库)把数据选取出来,然后在执行的时候直接进行参数化的选取.
反之,如果在程序执行期间,进行数据的选取,将可能带来数据库服务器的强大压力,因为参加并发执行的每个虚拟用户都去数据库搜刮一下,对数据库将是多么严峻的考验啊.
朋友或者同事之间的探讨是加深对问题理解和增加知识面,扩展视野最直接的途径和方法,加强沟通,keep in touch.
参考文章地址://case-one-of-loadrunner/
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。loadrunner使用-提高篇 转 - yunmenzhe的个人空间 - 51Testing软件测试网 51Testing软件测试网-中国软件测试人的精神家园
loadrunner使用-提高篇 转
& 18:53:19
/ 个人分类:
1. 概述在山东BOSS性能压力过程中,发现脚本对于整个压力测试过程的重要性,一个压力测试脚本录制和编辑修改得怎么样直接影响后面压力测试的执行。通常情况下,脚本应尽可能的精简,就像写代码一样。针对BOSS系统的特点, 个人 认为把单一业务录制成一个Action,并在脚本中添加Transaction,Find检查(可以采用URL-based scrīpt 方式录制并事先设定),Rendezvous,参数化等基本元素,然而有时我们会发现光有这些基本元素还不能满足我们的要求。比如在Controller 中运行我们的脚本时,一旦压力过大或某种原因导致某一业务失败,而此时我们很想尽快地找出错误的原因。当然此时我们第一想到的是,查找
,但是有时发现查找日志很不方便,因此我们希望寻求一种更快捷的方式,希望能直接从Controller的Errors错误中找到出错的服务号码、在第几次Iteration的哪个Transaction出错。实现的方式,当然是通过简单的编程来调用错误日志里的信息,另外本文中还简单介绍了关于 工具使用的一些常用注意事项、脚本处理技巧和一些常用性能参数的分析及
中机器瓶颈的定义和查看机器瓶颈的相关命令。&下面再具体的一一介绍。&2.性能测试脚本说明一个规范的性能测试脚本就像一段规范的程序代码一样,需要基本的说明信息:&在下面要介绍的脚本中,我把这些信息以注释的形式放在vuser_init最前面:&/*&@corporation:Copyright By *** Technologies CO.,LTD. All Rights Reserved.&@Athour:XuLinLin&@Date:&@Name:异地缴费压力测试脚本&@Parameter:BOSSURL,LogName,PhoneNum,iteration,FanHui&@Data:BOSSURL:BOSSURL. //由于BOSS压力测试前台展现环境多,故将地址也参数化。&LogName:LogName. //登录用操作员,选择具备异地缴费权限的操作员,这里选择的是德州操作员300个。&PhoneNum:PhoneNum. //用于异地缴费的服务号码,这里选择的是烟台的正常在用的标准全球通号码3000个。&iteration:iteration. //用于压力测试出错时,打印出错所在的循环次数。&@Descrīption:此脚本用于测试异地缴费的性能及稳定性,选用德州的操作员对烟台的标准全球通号码进行异地缴费,目标是&通过vuser模仿真实操作员进行异地缴费,达到验证或测试系统性能和稳定性的目的。&@Notes:脚本的录制使用的是LoadRunner8.0的VU,采用的是URL-based scrīpt方式,需要特别注意的是Recording Options(按Ctrl+F7)&的Advanced 选项里的Surport Charset一般情况默认为不选,除非字符集合采用的是国际标准才选中UTF-8选项,否则会出现汉字乱码现象。&*/&3.登陆成功与否判断通常情况下,任何业务必须在登陆成功后才能做,所以有必要对登陆成功与否进行判断:&下面我从脚本中取出相关部分进行简单介绍:&vuser_init()&{& //定义变量用于判断登陆是否成功&web_reg_find("Text="山东移动BOSS"",&LAST);&…….&…….&web_submit_data("reguserAction.do", //登陆提交数据Action。&"Action="http://{BOSSURL}/boss/reguserAction.do"",&"Method="POST"",&"RecContentType="text/html"",&"Referer="http://{BOSSURL}/boss/index.jsp"",&"Snapshot="t12.inf"",&"Mode="HTTP"",&ITEMDATA,&"Name="logname"", "Value="{LogName}"", ENDITEM,&"Name="password"", "Value=", ENDITEM,&LAST);&status = web_submit_data("reguserAction.do", // 取成功与否标志&"Action="http://{BOSSURL}/boss/reguserAction.do"",&"Method="POST"",&"RecContentType="text/html"",&"Referer="http://{BOSSURL}/boss/index.jsp"",&"Snapshot="t12.inf"",&"Mode="HTTP"",&ITEMDATA,&"Name="logname"", "Value="{LogName}"", ENDITEM,&"Name="password"", "Value=", ENDITEM,&LAST);&if (status ="=" LR_FAIL) //一旦登陆失败,脚本给出提示报错信息。&{&lr_error_message("错误信息: %s", "不能正常登陆!");&return -1;&}&}&4.定义事务事务的定义,很简单,也很有必要,尽量是每个定义的事物符合逻辑和小。&在下面的脚本中,在异地缴费这一业务中定义了两个Transaction:准备异地缴费数据和提交异地缴费,见如下脚本代码:&lr_start_transaction("准备异地缴费数据");&web_set_max_html_param_len("4096");&……….&web_submit_data("chargeacc.do",&"Action="http://{BOSSURL}/boss/charge/commonbusiness/acccharge/chargeacc.do?act=queryaccount"",&"Method="POST"",&"RecContentType="text/html"",&"Referer="http://{BOSSURL}/boss/charge/commonbusiness/acccharge/acccharge.jsp?act=first"",&"Snapshot="t74.inf"",&"Mode="HTTP"",&ITEMDATA,&"Name="isconfirm"", "Value="no"", ENDITEM,&"Name="chargetype"", "Value="telnumber"", ENDITEM,&"Name="telnumber"", "Value="{PhoneNum}"", ENDITEM,&"Name="nowfee"", "Value="0.0"", ENDITEM,&"Name="factfee"", "Value=", ENDITEM,&"Name="totalfee"", "Value="0.0"", ENDITEM,&LAST);&lr_end_transaction("准备异地缴费数据", LR_AUTO);&5.增强脚本,脚本编程增强脚本,对脚本进行简单的编程,为性能或压力测试提供方便,这也是写&本文的宗旨,下面对此做简单的介绍:&5.1定义成功与否的判断标志或字符串。&在此,我把判断成功与否的标志定义在异地缴费Action 最前面,具体定义如下:char fanhuiflag[30]="操作业务数据成功!";&但是大家可能会问,字符串"操作业务数据成功!"从何处而来,可以肯定的不能凭空想象,成功标志可从两三种方式来取得:&第一种:也是最简单的一种,直接从脚本中取得,具体操作是以View Tree 方式找到相关的界面,然后从Server Response的Snapshot的Body里去取。见下面的 图片 :&注:Snapshot在录制前要将Recording Options&Advanced里的Save snapshot resources locally 选项选中。&第二种方式,从脚本代码中去取,即取find函数中相关字符串,具体做法是,找到在提交事件前的web_reg_find函数,然后从中取相关字符串。&web_reg_find("Text="---------操作业务数据成功!--------"",&LAST);&值得注意的是要有web_reg_find函数,可以在录制前选中Recording Options&Advanced里的Generate web_reg_find functions for page titles 选项。&第三种方式,从本地的snapshot里去取,具体操作,首先找到提交数据事件相关脚本,找到snapshot文件的名称,然后从本地的data文件里去找这个snapshot文件,然后丛中找到我们需要的字符串。&web_reg_find("Text="---------操作业务数据成功!--------"",&LAST);&…….&web_submit_data("chargeacc.do_3",&"Action="http://{BOSSURL}/boss/charge/commonbusiness/acccharge/chargeacc.do?act=submit&atype=commitdata"",&"Method="POST"",&"RecContentType="text/html"",&"Referer="http://{BOSSURL}/boss/charge/commonbusiness/acccharge/chargeacc.do?act=querycustomer"",&"Snapshot="t129.inf"",&"Mode="HTTP"",&ITEMDATA,&"Name="isconfirm"", "Value="no"", ENDITEM,&"Name="chargetype"", "Value="telnumber"", ENDITEM,&"Name="telnumber"", "Value=", ENDITEM,&"Name="nowfee"", "Value="8.8"", ENDITEM,&"Name="factfee"", "Value="0.00"", ENDITEM,&"Name="totalfee"", "Value="8.8"", ENDITEM,&"Name="accountno"", "Value="{WCSParam_Diff1}"", ENDITEM,&"Name="factpay"", "Value="8.8"", ENDITEM,&"Name="grantpercent"", "Value=", ENDITEM,&"Name="grantfee"", "Value="0"", ENDITEM,&"Name="takecash"", "Value="8.8"", ENDITEM,&"Name="zero"", "Value="0"", ENDITEM,&"Name="paytype"", "Value="Cash"", ENDITEM,&"Name="remark"", "Value=", ENDITEM,&"Name="invoice"", "Value="joininvoice"", ENDITEM,&LAST);&5.2设置和保存判断成功与否的参数&有一点大家都很清楚,业务成功返回的字符串和失败返回的字符串是不同的,我们所要做的是将返回的字符串做为参数保存下来,然后拿这个参数和我们事先定义好的成功的标志做比较,有两种方式可以设置和保存这一参数,下面简单介绍:&第一种方式也是最准确的方式,是以View Tree 方式找到相关的界面,然后从Server Response的Snapshot的Body里的成功的返回标志,然后对其进行Create Parameter,这样LoadRunner会自动在脚本中添加web_reg_save_param函数,具体如下:&// [WCSPARAM WCSParam_Text2 24 操作业务数据成功!_Text2] Parameter {WCSParam_Text2} created by Correlation Studio&web_reg_save_param("WCSParam_Text2",&"LB="---------"",&"RB="-"",&"Ord="1"",&"RelFrameId="1"",&"Search="Body"",&LAST);&第二种方式是在提交事件前添加web_reg_save_param函数,具体操作是在提交事件前右击鼠标选择Insert Before 选项,然后在弹出的对话框中选择Services里的web_reg_save_param选项,单击OK按纽,然后在弹出的对话框中输入相关的数据。&5.3 编写相关判断代码段&在已经定义好判断字符串和设置和保存好成功与否的标志字符串参数后,编写相关判断代码段,这也是最关键的地方,具体代码段如下:&if (strcmp(fanhuiflag,lr_eval_string("{WCSParam_Text2}"))!="0)&{&lr_error_message("消息: %s,在第 %s 次循环时出错,出错号码:%s", "提交异地缴费数据失败!", lr_eval_string("{iteration}"), lr_eval_string("{PhoneNum}"));&}&简单解释如下:&fanhuiflag:前面已经定义好的成功标志字符串的数组名,当然前面也可以用指针来实现,这里不做介绍。&WCSParam_Text2:为实现设置和保存好的成功与否返回的字符串的参数;&PhoneNum:服务号码的参数化,具体为电话号码。关于参数化,这里不做分析和解释部分。&Iteration:为了定位具体的循环而设置的参数。&Strcmp函数:LoadRunner自带的字符串比较函数,相等时返回0&lr_eval_string函数:LoadRunner自带求字符串函数,函数格式为&char * lr_eval_string (const char * instring );&(另一种判断方式:先事先定义好int rc="1;" char *fanhuiflag="操作业务数据成功!";然后在定义事务的结尾进行判断: rc="strcmp(str_tip,lr_eval_string(""{re_str_tip}"));&if(rc="=0)"&{&lr_end_transaction("异地缴费_提交", LR_PASS);&}&else&{&lr_error_message("异地缴费_提交失败,号码为:%s",lr_eval_string("{msisdn}"));&lr_end_transaction("异地缴费_提交", LR_FAIL);&}&//lr_end_transaction("异地缴费_提交",LR_AUTO);)&5.4 验证需求是否实现&下面简单介绍,整个验证过程,在确保脚本正确和测试环境正常的情况下,我们先在VU里验证下是否真正实现了我们想要的功能,为了方便,我特地将判断条件该为="=而不是!=,通过查看日志来检查。&首先,选中菜单栏里的Run-time Settings子菜单,设置里面的Log选项,选中Enable Logging 和Always send messages 和Extended log 及Parameter substitution。&设置Run Logic 里的Number of Iterations 为2,然后运行,并查看日志。可以得到如下的日志(只取了关键部分的):&第一次循环关键部分:&YiDiJiaoFei.c(598): Notify: Transaction "提交异地缴费数据" ended with "Fail" status (Duration: 4.8459 Wasted Time: 0.0060).&YiDiJiaoFei.c(605): Notify: Parameter Substitution: parameter "WCSParam_Text2" = "操作业务数据成功!"&YiDiJiaoFei.c(607): Notify: Next row for parameter iteration = 1 [table = iteration].&YiDiJiaoFei.c(607): Notify: Parameter Substitution: parameter "iteration" = "1"&YiDiJiaoFei.c(607): Notify: Parameter Substitution: parameter "PhoneNum" = ""&YiDiJiaoFei.c(607): Error: 消息: 提交异地缴费数据失败!,在第 1 次循环时出错,出错号码:&第二次循环关键部分:&YiDiJiaoFei.c(598): Notify: Transaction "提交异地缴费数据" ended with "Fail" status (Duration: 4.2347 Wasted Time: 0.0064).&YiDiJiaoFei.c(605): Notify: Parameter Substitution: parameter "WCSParam_Text2" = "操作业务数据成功!"&YiDiJiaoFei.c(607): Notify: Next row for parameter iteration = 2 [table = iteration].&YiDiJiaoFei.c(607): Notify: Parameter Substitution: parameter "iteration" = "2"&YiDiJiaoFei.c(607): Notify: Parameter Substitution: parameter "PhoneNum" = ""&YiDiJiaoFei.c(607): Error: 消息: 提交异地缴费数据失败!,在第 2 次循环时出错,出错号码:&下面验证执行时,能正确找到出错的号码信息,将脚本加入到场景后,同样设置好Run-time Settings。&设置结果保存路径等相关信息,按Start Scenario 执行场景,等出错是单击右上角的Errors,然后选中错误信息再按Details按纽查看错误信息。&6.多机均匀对被测系统施压怎么样使多台产生vuser的测试机均匀地对被测试的系统施加压力?&在测试的过程中,为了尽可能减少或者避免本身的测试机成为测试过程中的瓶颈,需要使用多台测试机产生vuser对被测试系统施加压力,下面对操作步骤做简单介绍:&在默认模式下使用controller添加多台Generators机器时,不管你怎么加,最终能真正起作用的只有一台(10.19.180.2/3/4或localhost):&为了让10.19.180.2/3/4机器同时能真正被添加进去,我们需要做以下几步:&改变场景模式,将组模式()改变为百分比模式(percentage mode),具体做法是,选择Scenario菜单下的Convert Scenario to the Percentage Mode;&然后,在已经添加好的Load Generators机器列表中同时选择你想选择的机器;&最后,点OK按钮就可以得到我们所要的结果了。&当然,如有必要我们还可以把场景模式改为Vuser Group Mode,具体做法如下:&选择Scenario菜单下的Convert Scenario to the Vuser Group Mode;&然后在弹出的对话框中,单击Yes按钮可以得到如下结果,&到此为止,添加多台Load Generators测试机整个过程就完成了,其实很简单,关键是你发现了没有。&7. 怎么样在关联时取列表的最后一个值在压力测试脚本的关联过程中,我们有时可能需要关联最新的值(如最新的流水号,通常情况下,最新的流水号放在列表的最下方),所以找最新的流水号就是最列表最下方,如果保存在数组里,那就是找index值最大的那个元素。下面以重打发票(注:具体流程为先缴费,然后查询缴费历史,然后从缴费历史里找到最新的流水号,然后使用此流水号进行重打发票)为例对整个过程做详细的介绍:&首先,在缴费历史里找到需要关联的流水号并关联之,具体做法如下,&7.1以Tree View方式打开脚本并在对应事件的Page View里找到最新的流水号&找到我们需要关联的流水号(这里为536dxwf0000)后,需要把它给关联,(因为返回的值是事后才知道的,且对于不同的电话号码,对应的返回值不同,所以对于这样的值是需要关联的。)具体做法是打开Server Response 页面并在Body里找到需要关联的流水号,然后选中此流水号并在右键弹出的菜单中使用Create Parameter关联之。&7.2单击是(Y)按钮,对应的脚本中会增加如下内容。&单击View scrīpt 图标以scrīpt模式查看关联情况。&7.3到此为止脚本中多出如下代码段,下面对它做一定的分析:&web_reg_find("Text="缴费历史查询"",&LAST);&// [WCSPARAM WCSParam_Text1 23 536dxwf0000] Parameter {WCSParam_Text1} created by Correlation Studio&web_reg_save_param("WCSParam_Text1",&"LB="formnum="",&"RB=\"",&"Ord=8",&"RelFrameId=1",&"Search=Body",&LAST);&//后面的内容为注释部分,说明流水号536dxwf0000已经关联并保存到WCSParam_Text1参数中。&web_reg_save_param()为LoadRunner的保存参数所用的函数,其作用是将返回流水号保存到WCSParam_Text1参数中,以便使用不同的号码进行缴费历史查询出来的流水号能随着时间的变化流水号也跟着变化,而不是录制脚本时的 536dxwf0000,这样可以避免在重打发票时不会报诸如此流水号不存在等类似错误信息。然而现在的问题是怎么将此流水号对应到重打发票对应的地方。另一个问题是,不是所有的号码缴费后查询到的流水号数量都和录制脚本时查询到的流水号相同,事实上每做一笔除查询类的操作都会有一个流水号。而我们关注的是怎么取到最新的缴费的流水号,下面详细介绍相关步骤。&5.1 修改web_reg_save_param()函数相关部分,很简单,把"Ord="8"",改为"Ord=ALL",目的是找最TOP的那个参数值。&5.2 光保存和取参数还不够,我们需要把参数能正确传递到重打发票对应的地方,为此我采取的做法如下:&在缴费历史事件脚本最前面定义两个变量,目的是为了将流水号以字符串的形式保存在变量里(因为LoadRunner不支持在web_submit_data()函数里直接使用变量):具体做法是:&char WCSParam_Text1Pram[50]; //保存取到的流水号&char WCSParam_Text1PramVal[50]; //保存以"Value="流水号""取到的流水号。&将关联好的流水号存到变量里,在此的做法是在对应的web_submit_data()函数后添加如下代码段:&lr_message("WCSParam_text1:%s",lr_eval_string("{WCSParam_Text1}"));&//打印出关联的参数WCSParam_Text1的值。&sprintf(WCSParam_Text1Pram,"{WCSParam_Text1_%s}",lr_eval_string("{WCSParam_Text1_count}"));&//把取到流水号保存到WCSParam_Text1Pram里,具体形式为&sprintf(WCSParam_Text1PramVal,"Value="%s"",lr_eval_string(WCSParam_Text1Pram));&//组合流水号和”Value=”并保存到WCSParam_Text1PramVal变量中。&lr_message("The value argument is : %s", WCSParam_Text1PramVal);&//打印出字符串变量WCSParam_Text1PramVal的值。&5.3 找到重打发票中响应的流水号,并把其中的"Value="536dxwf0000""替换成WCSParam_Text1PramVal,在这里总共有两处。&到此为止,流水号的关联已经基本上处理完毕,下面我们执行脚本,来验证我们想要的是不是真的有效。(注,参数化的问题在本文中不做具体介绍)为了看到明显的效果,我们需要将日志的处理做简单设置。&然后执行脚本,查看相关执行日志,可以得到类似下面得消息。&8.使用LoadRunner一些常用的注意事项Note1:VuGen仅能录制 平台上的会话,但是,录制的Vuser脚本既可以在Windows 平台上运行,也可以在 UNIX 平台上运行。&通用 Vuser 函数和特定于协议的函数,它们共同构成了 LoadRunner API,并使Vuser能够直接与服务器通信。&Note2:用于运行Vuser脚本的C解释器仅支持ANSI C语言。它不支持 Microsoft对ANSI C的任何扩展。&通常情况下,可以将登录到服务器的活动录制到vuser_init部分中、将客户端活动录制到Actions部分中,并将注销过程录制到vuser_end部分中。&Note3:只能向Action部分(而不是init或end 部分)添加集合。&Note:不要从事务内部发送消息,因为这可能使事务执行时间变长,并扭曲事务结果。&Note4:如果使用日志运行时设置修改脚本的调试级别,则 lr_message、lr_output_message 和 lr_log_message 函数的行为将不会更改,它们将继续发送消息。&Note5:录制 Java Vuser 脚本时, Vuser 脚本中将不生成 lr_think_time 语句。&Note6:VuGen 新建参数,但不会自动替换任何在脚本中选定的字符串。&Note7:不要将参数命名为 unique,因为该名已被 VuGen 使用。&Note8:如果在常规运行时设置文件夹中将“错误处理”设置为“出现错误时仍继续”,则错误消息仍将被发送到输出窗口。&Note9:因为生成的服务器消息很长,而且日志记录会降低系统的运行速度,所以请仅为脚本中特定的代码块激活服务器消息日志记录功能。&Note10:启用“出现错误时仍继续”功能时,将覆盖 0 严重级别;即使发生错误,也将继续执行脚本。然而,如果禁用了“出现错误时仍继续”功能,但将严重级别指定为 1,则当发生数据库错误时仍将继续执行脚本。&Note11:下列协议不是线程安全协议:Sybase-Ctlib、Sybase-Dblib、Informix、Tuxedo 和 PeopleSoft-Tuxedo。&Note12:对于支持树视图的协议(如“视图”菜单所示),在树视图中运行 Vuser脚本时, VuGen 将从 Vuser 脚本中的第一个图标开始运行该脚本。&Note13:要显示运行时查看器,必须安装 Microsoft Internet Explorer 4.0 或更高版本。&Note:Vuser 生成“结果摘要”报告时,事务时间可能会增加。Vuser 可以仅在从 VuGen 运行时才生成“结果摘要”报告。使用 Controller 运行
Vuser 脚本时, Vuser 不能生成报告。&Note14:当使用 Javascrīpt 和 VBscrīpt Vuser 时,在脚本中用到的 COM 对象必须完全的兼容。这使下列情况成为了可能:一个应用程序操纵另一个应用程序中的对象,或者公开对象以便操纵它们。&9.性能参数解析WEB资源参数&每秒点击次数:中Vuser每秒向Web服务器提交的HTTP请求数,依据点击次数来评估Vuser产生的负载量。&吞吐量:案运行过程中服务器上每秒的吞吐量。吞吐量的度量单位是字节,表示Vuser在任何给定的某一秒上从服务器获得的数据量,依据服务器吞吐量来评估Vuser产生的负载量。&每秒HTTP响应数:中每秒从Web服务器返回的HTTP状态代码号(表示HTTP请求的状态,例如“the request was successful”、“the page was not found”)&每秒下载页面数:每秒钟从服务器下载的网页数,依据下载的页面数来评估Vuser产生的负载量。&每秒重试次数:中每秒钟内服务器尝试的连接次数,在下列情况下将重试服务器连接:初始连接未经授权、要求代理服务器身份验证、服务器关闭了初始连接、初始连接无法连接到服务器或者服务器最初无法解析负载生成者的IP地址。&连接数:每个时间点上打开的TCP/IP连接数。&每秒SSL连接数:每秒打开的新的以及重新使用的SSL连接数。当对安全服务器打开TCP/IP连接后,浏览器将打开SSL连接,因为新建SSL连接需要消耗大量的资源,所以应该尽量少地打开新的SSL连接。网页细分图&注意:由于要从客户端测定服务器时间,因此,如果发送初始HTTP请求到发送第一次缓冲这一段时间内网络性能发生变化,则网络时间可能会影响此测定。因此,所显示的服务器时间是一个估计值,可能不太精确。&DNS解析:显示使用最近的DNS服务器将DNS名称解析为IP地址所需的时间。“DNS 查找”度量是指示DNS解析问题或DNS服务器问题的一个很好的指示器。&连接:显示与包含指定URL的Web服务器建立初始连接所需的时间。连接度量是一个很好的网络问题指示器。此外,它还可表明服务器是否对请求作出响应。&第一次缓冲:显示从初始HTTP请求(通常为 GET)到成功收回来自Web服务器的第一次缓冲时为止所经过的时间。第一次缓冲度量是很好的Web服务器延迟和网络滞后指示器。注意:由于缓冲区大小最大为 8K,因此第一次缓冲时间可能也就是完成元素下载所需的时间。&SSL握手:显示建立SSL连接(包括客户端 hello、服务器hello、客户端公用密钥传输、服务器证书传输和其他部分可选阶段)所用的时间,自此点之后,客户端与服务器之间的所有通信都将被加密。SSL握手度量仅适用于HTTPS通信。&接收:显示从服务器收到最后一个字节并完成下载之前经过的时间。“接收”度量是很好的网络质量指示器(查看用来计算接收速率的时间/ 大小比率)。&FTP验证:显示验证客户端所用的时间。如果使用FTP,则服务器在开始处理客户端命令之前,必须验证该客户端。“FTP 验证”度量仅适用于 FTP 协议通信。&客户端时间:显示因浏览器思考时间或其他与客户端有关的延迟而使客户机上的请求发生延迟时,所经过的平均时间。&错误时间:显示从发出HTTP请求到返回错误消息(仅限于HTTP错误)这期间经过的平均时间。系统资源(UNIX资源参数)&CPU utilization :CPU的使用时间百分比&Disk rate :磁盘传输速率&Paging rate :每秒钟读入物理内存或写入页面文件中的页数&Page-in rate :每秒钟读入到物理内存中的页数&Page-out rate :每秒钟写入页面文件和从物理内存中删除的页数&Collision rate :每秒钟在以太网上检测到的冲突数&Context switches rate :每秒钟在进程或线程之间的切换次数&Average load :上一分钟同时处于“就绪”状态的平均进程数&Swap-in rate :正在交换的进程数&System mode CPU utilization :在系统模式下使用CPU的时间百分比&User mode CPU utilization :在用户模式下使用CPU的时间百分比网络监视参数&网络延迟时间:源计算机与目标计算机(例如,数据库服务器和Vuser负载生成器)之间的整个路径的延迟。&网络子路径时间:从源计算机到路径上每个节点的延迟。注意:从源计算机到每个节点的延迟是同时而又独立地度量的。因此,从源计算机到其中一个节点的延迟可能大于源计算机与目标计算机之间的整个路径上的延迟。&网络段延:路径上每个段的延迟。&验证网络是否是瓶颈:可以合并各种图来确定网络是否是瓶颈。例如,通过使用网络延迟时间图和运行Vuser图,可以确定Vuser的数量如何影响网络延迟。网络延迟时间图指示在方案运行期间的网络延迟。数据库服务器&User Calls :在每次登录、解析或执行时,
会分配资源(Call State 对象)以记录相关的用户调用数据结构。在确定活动时,用户调用与RPI调用的比指明了,因用户发往Oracle的请求类型而生成的内部工作量&Total file opens :由实例执行的文件打开总数。每个进程需要许多文件(控制文件、日志文件、数据库文件)以便针对数据库进行工作&Opened cursors current :当前打开的光标总数&DB block changes :由于与一致更改的关系非常密切,此统计计算对SGA中所有块执行的、作为更新或删除操作一部分的更改总数。这些更改将生成重做日志项,如果事务被提交,将是对数据库的永久性更改。此统计是一个全部数据库作业的粗略指示,并且指出(可能在每事务级上)弄脏缓冲区的速率。&10.AIX操作系统机器性能瓶颈定义&瓶颈定义&CPU bound : vmstat : when %user+%sys greater than 80%;&Disk I/O bound : vmstat : when %iowait greater than 40%(AIX4.3.3 or later);&Application disk bound :vmstat : when %tm_act greater than 70%;&Paging space low : lsps -a : when used paging space greater than 70% active;&Paging bound : iostat vmstat : paging logical volumes %tm_act greater than 30% of the I/O(iostat) and paging activity greater than 10* the number of CPUs(vmstat);&Thrashing : vmstat sar :rising page outs, CPU wait and run queue;&11.系统性能分析命令cpu : vmstat,iostat,topas,nmon,ps,sar,time,timex,netpmon,trace,&内存:vmstat,topas,nmon,ps,svmon,lsps,filemon,trace,&磁盘:iostat,topas,nmon,lvmstat,iostat -d, lvmstat, lsps,filemon,lsattr,&网络:netstat,topas,nmon,entstat,nfsstat,ifconfig,iptrace,ipreport,trace,&监视CPU使用情况:vmstat 2 ; iostat -t 2 6;sar -P ALL 2 3;&监视内存使用情况: vmstat 2 10;svmon -G;svmon -Pau 10;&监视I/O使用情况: iostat 5;sar -d 3 3;&监视网络使用情况: netstat -netstat -m;netstat -v;}

我要回帖

更多关于 loadrunner下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信