发布新日志

  • loadrunner学习系列---脚本编写(2)

    zibeike 发布于 2007-12-12 20:58:53

       今天接着翻译http://www.wilsonmar.com/1lrscrīpt.htm上面关于LR脚本编写部分.

    VUser_Init部分

    这里是Vuser_init部分的一些例子:

    操作系统的User ID

    下面显示了使用advapi32.dll的GetUserNameA函数获得的操作系统的用户ID

    	char	sUserID[1024]; // Maximum possible UserID length.
    	long	lUserIDSize = sizeof(sUserID)-1;
    	int 	rc;
    
    	rc=lr_load_dll("advapi32.dll");
    	if( rc != 0 ){
    		lr_error_message("lr_load_dll of advapi32.dll failed. Aborted for rc=%d",rc);
    		lr_abort(); 
    	}else{
    		GetUserNameA(sUserID, &lUserIDSize);
    		lr_message("UserID='%s'", sUserID);
    	}
    所有的变量声明需要一块放到最上方。在vuser_init 部分创建的本地C变量(如 int或char)对其他部分的脚本是不可见的。所以使用lr_save_string函数来创建对所有脚本可用的全局参数。例子:
       
    char *itoa ( int value, char *str, int radix ); 
    vuser_init(){ 
    	int x = 10;
    	char buffer[10]; 
    	lr_save_string( itoa( x, buffer, 10) , "pX" ); 
    	lr_message ( "int x = %s", lr_eval_string("{pX}" )); 
    return 0;
    } 
     
     
    运行时设置的附加属性(Additional Attribute)
      8.0版本引进了一个非常有价值的特性:在运行时设置中指定属性,这个属性可以对不同的虚拟用户组设置不同的值。
     
     下面的代码是从运行时设置的附加属性中读取名为“usertype”的参数。然后使用参数值来对应的设置全局的"thinktime1"变量。
       
    int thinktime1=0;
    vuser_init()
    {
      LPCSTR strUsertype; // Define *str.
      strUsertype = lr_get_attrib_string("usertype");
      if (strUsertype==NULL){
        lr_output_message("### Run-time Settings Additional Attribute usertype not specified. Cannot continue.");
        lr_abort();
      }else{
        lr_message("### Run-time Settings Additional Attribute usertype=\"%s\"", strUsertype );
        if( strcmp( strUsertype,"advanced") == 0 ){ thinktime1=2; }
        else
        if( strcmp( strUsertype,"intermediate") == 0 ){ thinktime1=4; }
        else
        if( strcmp( strUsertype,"basic") == 0 ){ thinktime1=8; }
        else{
          lr_error_message("### ERROR: Value not recognized. Aborting run." );
          lr_abort();
        }
        }
        return 0;
      }
       
      Time Structure Fix(不知道怎么翻译,呵呵,“时间结构的解决“?)
      根据知识库34195的文章,默认当前时间戳的毫秒部分不被更新,除非ftime使用的时间结构被重新定义:
      typedef long time_t; 
      struct _timeb { 
         time_t time; 
         unsigned short millitm;
         short timezone; 
         short dstflag; 
      }; 
      struct _timeb t; 
      _tzset(); \\ 使用ftime设置变量 
      _ftime( &t ); 
      lr_message( "Plus milliseconds: %u", t.millitm ); 
      
      控制信息的显示:
      在运行时,当脚本的事务失败后继续,你怎么知道哪个用户失败了?
       Idea在每个失败的事务之后,发出一个能够唯一确定该用户的信息。
      Loadrunner提供了一些函数来在运行时显示信息:
         
    • // 往输出日志上发送消息,这个消息前边会带有action 的名称和行数
      lr_output_message("an output message");

      例子:

      • Actions.c (4): an output message

    • // 往输出日志和虚拟用户日志上发消息:
    • lr_message("*** a message"
        +"\r"+"A new line."
          );
    • Idea把");"放到另一行,这样可以容易的在命令上添加或者删除代码项。

      UNIX/Linux机器上,使用 "\n"来添加一个换行。

      Windows 机器上,使用"\r"来添加一个换行。

      // 往输出日志上发送不带action名称和行数的信息
      lr_log_message("number\t"+ numvar +"\t");

       

      // 只给控制器上的虚拟用户状态区域发送信息(当在VuGen中运行时,只是简单的显示):
      lr_vuser_status_message("a vuser status message");

       

      // 给LoadRunner控制器或者Tuning模块的控制台输出窗口显示一个红色高亮度显示的-17999 信息。
      lr_error_message("an error message");

       

      Idea 使用lr_error_message将会使日志信息堆栈在每个新的action开始时被自动清空。如果选择了"当错误发生时才发送消息", 这些信息仍然被创建在"日志信息堆栈"里, 但是被压缩了(没有显示),直到监测到一个错误。

       

       

         
         
         
         
         
      • 查看端口号是否被占用

        含笑 发布于 2011-07-26 15:10:43

        查看占用指定端口号的进程:

        C:\>netstat -aon|findstr "80"

        TCP 127.0.0.1:80 0.0.0.0:0 LISTENING 2168

        端口被进程号为2448的进程占用

        C:\>tasklist|findstr "2168"

        QQ.exe 2168 Console 0 40,720 K

        QQ占用了你的端口

      • 性能测试中如何定位性能瓶颈

        yzylion 发布于 2011-03-21 09:29:00

        以下摘录性能测试定位瓶颈的经验分享:

        --------------------------------------

        性能测试的概念是什么,基本目的是什么,我想大家都基本清楚,不作详述,总之,性能测试只是测试过程中的一种方式,帮助我们的功能更好的运行,如果功能测试是可用,易用,满足需求、用户使用为目的,性能测试无非就是让这些目的更流畅。没有什么专业的概念,无非实现两个字:好用!
            所以,性能测试这种测试方式在发生过程中,其中一个过渡性的工作,就是对执行过程中的问题,进行定位,对功能的定位,对负载的定位,最重要的,当然就是问题中说的“瓶颈”,接触性能测试不深,更非专家,自己的理解,瓶颈产生在以下几方面:
        1,网络瓶颈,如带宽,流量等形成的网络环境
        2,应用服务瓶颈,如中间件的基本配置,CACHE等
        3,系统瓶颈,这个比较常用:应用服务器,数据库服务器以及客户机的CPU,内存,硬盘等配置
        4,数据库瓶颈,以ORACLE为例,SYS中默认的一些参数设置
        5,应用程序本身瓶颈,
        以上几方面分别唠叨几句
              针对网络瓶颈,现在冒似很少,不过也不是没有,首先想一下如果有网络的阻塞,断网,带宽被其他资源占用,限速等情况,应用程序或系统会是什么情况,针对WEB,无非是超时,HTTP400,500之类的错,针对一些客户端程序,可能也是超时,掉线,服务器下发的,需要服务器返回的信息获取不到还有一种更明显的情况,应该就是事务提交慢,如果封装事务的代码再不完善,一般造成的错误,无非就是数据提交不完整,或者因为网终原因+代码缺陷造成重复性提交。如此综合下来,肯定是考虑网络有瓶颈,然后考虑网络有问题时,怎样去优化,是需要优化交互的一些代码,还是接口之类的。
              应用服务的瓶颈的定位,比较复杂,学习中,不过网上有很多资料可以参考的。一般像tomcat,weblogic之类的,有默认的设置,也有经过架构和维护人员进行试验调试的一些值,这些值一般可以满足程序发布的需要,不必进行太多的设置,可能我们认识的最基本的就是JAVA_OPTS的设置,maxThreads,time_out之类的参数我们做借助LR,Jemeter或webload之类的工具,执行性能测试,尤其是对应用服务造成了压力,如果应用服务有瓶颈,一般我们设置的log4j.properties,日志都会记录下来。然后根据日志,去进一步确定应用服务的问题
              系统瓶颈,这个定位虽说比较复杂,但是有很多前辈的经验值参考,不作说明,相信用LR的同行,也可以从性能记数器中得出一些指标值,加上nagios,cacti,可以很明显的看出系统哪些资源够用,哪些资源明显不够用。不过,一般系统瓶颈的造成,是因为应用程序本身造成的。关于这点儿的分析和定位,就需要归入应用程序本身瓶颈分析和定位了。
              现在基本所有的东东,都离不开数据库这个后台,数据库的瓶颈实在是不知道是什么概念,数据库管理员的工作,数据库管理员日常做的工作,可能就是有瓶颈定位的工作,比如:查询一下V$sys_event,V$sysstat,v$syssql之类的表,比对一下日常正常情况下的监控数据,看一下有没有异常等。其他方面,我也不是太了解。
              应用程序瓶颈,这个是测试过程中最需要去关注的,需要测试人员和开发人员配合执行,然后定位,我这儿做的大都是执行性的,比如会有脚本去运行,开发人员会结合jprofiler之类的工具,去看一下堆遍历,线程剖析的情况确定哪儿有问题。大致是这样,没有实际操作过
        ------------------------------------

        逐步细化分析,先可以监控一些常见衡量CPU,内存,磁盘的性能指标,进行综合分析,然后根据所测系统具体情况,进行初步问题定位,然后确定更详细的监控指标来分析。

        怀疑内存不足时:
        方法1:
        【监控指标】:Memory Available MBytes ,Memory的Pages/sec, page read/sec, Page Faults/sec
        【参考值】:
        如果 Page Reads/Sec 比率持续保持为 5,表示可能内存不足。
        Page/sec 推荐00-20(如果服务器没有足够的内存处理其工作负荷,此数值将一直很高。如果大于80,表示有问题)。

        方法2:根据Physical Disk 值分析性能瓶颈
        【监控指标】:Memory Available MBytes ,Pages read/sec,%Disk Time 和 Avg.Disk Queue Length
        【参考值】:%Disk Time建议阈值90%
                当内存不足时,有点进程会转移到硬盘上去运行,造成性能急剧下降,而且一个缺少内存的系统常常表现出很高的CPU利用率,因为它需要不断的扫描内存,将内存中的页面移到硬盘上。

        怀疑内存泄漏时
           【监控指标】:Memory Available MBytes ,Process\Private Bytes和Process\Working Set,PhysicalDisk/%Disk Time
        【说明】:
        Windows资源监控中,如果Process\Private Bytes计数器和Process\Working Set计数器的值在长时间内持续升高,同时Memory\Available bytes计数器的值持续降低,则很可能存在内存泄漏。内存泄漏应该通过一个长时间的,用来研究分析当所有内存都耗尽时,应用程序反应情况的测试来检验。


        CPU分析
        【监控指标】:
        System %Processor Time CPU,Processor %Processor Time CPU
        Processor%user time 和Processor%Privileged Time
        system\Processor Queue Length
        Context Switches/sec 和%Privileged Time
        【参考值】:
        System\%Total processor time不持续超过90%,如果服务器专用于SQL Server,可接受的最大上限是80-85% ,合理使用的范围在60%至70%。
        Processor %Processor Time小于75%
        system\Processor Queue Length值,小于CPU数量的总数+1

        CPU瓶颈问题
        1:System\%Total processor time如果该值持续超过90%,且伴随处理器阻塞,则说明整个系统面临着处理器方面的瓶颈.
        注: 在某些多CPU系统中,该数据虽然本身并不大,但CPU之间的负载状况极不均衡,此时也应该视作系统产生了处理器方面的瓶颈.
        2:排除内存因素,如果Processor %Processor Time计数器的值比较大,而同时网卡和硬盘的值比较低,那么可以确定CPU 瓶颈。(内存不足时,有点进程会转移到硬盘上去运行,造成性能急剧下降,而且一个缺少内存的系统常常表现出很高的CPU利用率,因为它需要不断的扫描内存,将内存中的页面移到硬盘上。)

        造成高CPU使用率的原因:
        频繁执行程序,复杂运算操作,消耗CPU严重
        数据库查询语句复杂,大量的 where 子句,order by, group by 排序等,CPU容易出现瓶颈
        内存不足,IO磁盘问题使得CPU的开销增加


        磁盘I/O分析
        【监控指标】:PhysicalDisk/%Disk time,PhysicalDisk/%Idle Time,Physical Disk\ Avg.Disk Queue Length, Disk sec/Transfer
        【参考值】:%Disk Time建议阈值90%


        Windows资源监控中,如果% Disk Time和Avg.Disk Queue Length的值很高,而Page Reads/sec页面读取操作速率很低,则可能存在磁盘瓶径。

        Processor%Privileged Time该参数值一直很高,且如果在 Physical Disk 计数器中,只有%Disk time 比较大,其他值都比较适中,硬盘可能会是瓶颈。若几个值都比较大, 那么硬盘不是瓶颈。若数值持续超过80%,则可能是内存泄露。如果 Physical Disk 计数器的值很高时该计数器的值(Processor%Privileged Time)也一直很高, 则考虑使用速度更快或效率更高的磁盘子系统。

        Disk sec/Transfer 一般来说,该数值小于15ms为最好,介于15-30ms之间为良好,30-60ms之间为可以接受,超过60ms则需要考虑更换硬盘或是硬盘的RAID方式了.

        ---------------------------------------------

        Average Transaciton Response Time(事务平均响应时间)随着测试时间的变化,系统处理事务的速度开始逐渐变慢,这说明应用系统随着投产时间的变化,整体性能将会有下降的趋势
        Transactions per Second(每秒通过事务数/TPS)当压力加大时,点击率/TPS曲线如果变化缓慢或者有平坦的趋势,很有可能是服务器开始出现瓶颈
        Hits per Second(每秒点击次数)通过对查看“每秒点击次数”,可以判断系统是否稳定。系统点击率下降通常表明服务器的响应速度在变慢,需进一步分析,发现系统瓶颈所在。
        Throughput(吞吐率)可以依据服务器的吞吐量来评估虚拟用户产生的负载量,以及看出服务器在流量方面的处理能力以及是否存在瓶颈。
        Connections(连接数)当连接数到达稳定状态而事务响应时间迅速增大时,添加连接可以使性能得到极大提高(事务响应时间将降低)
        Time to First Buffer Breakdown(Over Time)(第一次缓冲时间细分(随时间变化))可以使用该图确定场景或会话步骤运行期间服务器或网络出现问题的时间。
        ----------------------------------------------
        碰到过的性能问题:
        1.在高并发的情况下,产生的处理失败(比如:数据库连接池过低,服务器连接数超过上限,数据库锁控制考虑不足等)
        2.内存泄露(比如:在长时间运行下,内存没有正常释放,发生宕机等)
        3.CPU使用偏离(比如:高并发导致CPU使用率过高)
        4.日志打印过多,服务器无硬盘空间

        如何定位这些性能问题:
        1.查看系统日志,日志是定位问题的不二法宝,如果日志记录的全面,很容易通过日志发现问题。
          比如,系统宕机时,系统日志打印了某方法执行时抛出out of memory的错误,我们就可以顺藤摸瓜,很快定位到导致内存溢出的问题在哪里。
        2.利用性能监控工具,比如:JAVA开发B/S结构的项目,可以通过JDK自带的Jconsole,或者JProfiler,来监控服务器性能,Jconsole可以远程监控服务器的CPU,内存,线程等状态,并绘制变化曲线图。
        利用Spotlight可以监控数据库使用情况。
        我们需要关注的性能点有:CPU负载,内存使用率,网络I/O等
        3.工具和日志只是手段,除此之外,还需要设计合理的性能测试场景
        具体场景有:性能测试,负载测试,压力测试,稳定性测试,浪涌测试等
        好的测试场景,能更加快速的发现瓶颈,定位瓶颈
        4.了解系统参数配置,可以进行后期的性能调优

        除此以外,还想说个题外话,就是关于性能测试工具的使用问题
        在刚开始用Loadrunner和JMeter的时候,做高并发测试时,都出现过没有把服务器压垮,这两个程序自己先倒下的情况
        如果遇到这个问题,可以通过远程调用多个客户端的服务,分散性能测试工具客户端的压力来解决
        说这个的目的是想说,做性能测试的时候,我们一定要确保瓶颈不要发生在我们自己的测试脚本和测试工具上

        ------------------------------------------------------

              

      • linux性能优化 vmstat命令详解

        yzylion 发布于 2010-10-14 17:32:22

         vmstat 命令报告虚拟内存统计信息和CPU负荷:页面调度,交换,任务交换,CPU利用率。命令的语法是:
               vmstat [-cisS] [d1 d2 d3 d4] [interval [count]]
               当不用选项时,vmstat显示一条曲线表示自从系统启动后活动的信息。如果指定interval(时间间隔),接下来的线是重复显示最后的interval期间活动的情况,直到用户中断命令执行。当同时提供计数器时,统计信息按时间计数来显示。
               如果指定了一个磁盘名(如d1,d2,等等。),这些磁盘得到优先显示。通常,系统上的前4个磁盘设备是显示的,因为只有四个设备能在一线条上显 示,这个选项允许性能分析员修改缺省显示选项。(*磁盘名通常随id,sd,xd,或xy (取决于类型和I/0界面)加一个数字,如id0,sd2,xd1等等命名而定。),vmstat 命令显示若干字段信息:
              
        procs        报表下面三种状态的进程数:
                    r--在运行队列中等候运行
                    b--被资源阻塞(I/0,页面调度,等等.)
                    w--可运行但是被换出的
        memory 报告虚拟内存和实存信息:
                    swap--以千字节为单位的当前可用交换空间的数量
                    free--以千字节为单位的页自由表大小
        page   报告每秒页面调度活动数量的信息:
                    re-从自由表回收页
                    mf--次要的错误;地址空间或硬件地址转换错误
                    pi--页入的千字节数
                    po -页出的千字节数
                    fr- 释放的千字节数
                    de--以千字节为单位的可接受的短期内存不足数
                    sr--页由时钟算法扫描
        disk             可以为四个磁盘报告每秒磁盘I/O的数量

        faults        报告每秒系统软件中断和硬件中断的速率
                    in-设备中断,不包括系统时钟中断
                    sy-系统调用
                    cs-CPU任务(上下文)交换
        cpu--        CPU故障时间的百分比,在多处理器系统上,这是全部处理器的平均值:
                             us-   用户时间
                    sy-- 系统时间
                    id-- 闲置时间

        vmstat命令有四个可选标志可供使用。如果机器有虚拟地址缓存-c标志就改变输出报告缓存刷新统计数据。报告包括自从系统启动后每种缓存刷新全部总量。六个缓存类型是用户,上下文,区域,段,页,部分页。
        -i标志 使输出变为报告中断的数量。如果给出设备名,如d1,d2等,监控将在设备级*执行,(*注,参阅第十二章有关打开设备级监控的信息。)并报告每个给定设备的统计信息。

           修改"普通"报告来显示交换而非页面调度活动的信息。这选项改变显示的两个字段:si(换入)和so(换出)替代了re和mf字段。

        值得注意是,interval 和count选项对-i或-s选项是非法的。


        vmstat 参数详解

        procs:

        r-->在运行队列中等待的进程数
        b-->在等待io的进程数
        w-->可以进入运行队列但被替换的进程

        memoy

        swap-->现时可用的交换内存(k表示)
        free-->空闲的内存(k表示)


        pages

        re--》回收的页面
        mf--》非严重错误的页面
        pi--》进入页面数(k表示)
        po--》出页面数(k表示)
        fr--》空余的页面数(k表示)
        de--》提前读入的页面中的未命中数
        sr--》通过时钟算法扫描的页面

        disk 显示每秒的磁盘操作。 s表示scsi盘,0表示盘号

        fault 显示每秒的中断数
        in--》设备中断
        sy--》系统中断
        cy--》cpu交换

        cpu 表示cpu的使用状态

        cs--》用户进程使用的时间
        sy--》系统进程使用的时间
        id--》cpu空闲的时间


        FIELD DESCRIPTIONS
        Procs
           r: The number of processes waiting for run time.
           b: The number of processes in uninterruptable sleep.
           w: The number of processes swapped out but otherwise runnable.  

        Thisfield is calculated, but Linux never desperation swaps.
          
        Memory
           swpd: the amount of virtual memory used (kB).
           free: the amount of idle memory (kB).
           buff: the amount of memory used as buffers (kB).
          
        Swap
           si: Amount of memory swapped in from disk (kB/s). 虚拟内存的页导入(从SWAP DISK导入RAM)
           so: Amount of memory swapped to disk (kB/s). 虚拟内存的页导出.
        (从RAM到SWAP DISK)
          
        IO
           bi: Blocks sent to a block device (blocks/s).写入
           bo: Blocks received from a block device (blocks/s).写出
          
        System
           in: The number of interrupts per second, including the clock.
           cs: The number of context switches per second.
        : CPU
           These are percentages of total CPU time.
           us: user time
           sy: system time
           id: idle time


        如果 r经常大于 4 ,且id经常少于40,表示cpu的负荷很重。
        如果pi,po 长期不等于0,表示内存不足。
        如果disk 经常不等于0, 且在 b中的队列 大于3, 表示 io性能不好。


        由vmstat看服务器


        说明:由于STATSPACK并不能获取全面分析性能问题所需要的所有信息,所以需要扩展其收集服务器的统计信息。
          
        VMSTAT介绍

        通过STATSPACK收集服务器信息,主要通过收集VMSTAT的信息来展现服务器状况。VMSTAT工具是最常见的UNIX监控工具,可以展现给定时间间隔的服务器的状态值。

        一般VMSTAT工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数。如:
        [oracle@brucelau oracle]$ vmstat 1 2
        procs                   memory swap       io   system         CPU
        r   b   w swpd free buff   cache    si   so bi bo in cs   us   sy   id
        1   0   0    0 271844 186052 255852 0 0     2     6   102 10 0 0 100
        0   0   0    0 271844 186052 255852 0 0     0     0   104 11 0 0 100
          
        (注:目前系统几乎空闲,并且不同操作系统VMSTAT输出内容有所不同)
          
        目前说来,对于服务器监控有用处的度量主要有:

        r(运行队列)
        pi(页导入)
        us(用户CPU)
        sy(系统CPU)
        id(空闲)
          
        通过VMSTAT识别CPU瓶颈

        r(运行队列)展示了正在执行和等待CPU资源的任务个数。当这个值超过了CPU数目,就会出现CPU瓶颈了。
        获得CPU个数的命令(LINUX环境):
        cat /proc/cpuinfo|grep processor|wc –l
        当r值超过了CPU个数,就会出现CPU瓶颈,解决办法大体几种:
        1. 最简单的就是增加CPU个数
        2. 通过调整任务执行时间,如大任务放到系统不繁忙的情况下进行执行,进尔平衡系统任务
        3.   调整已有任务的优先级  

        通过VMSTAT识别CPU满负荷

        首先需要声明一点的是,vmstat中CPU的度量是百分比的。当us+sy的值接近100的时候,表示CPU正在接近满负荷工作。但要注意的是,CPU 满负荷工作并不能说明什么,UNIX总是试图要CPU尽可能的繁忙,使得任务的吞吐量最大化。唯一能够确定CPU瓶颈的还是r(运行队列)的值。
          
        通过VMSTAT识别RAM瓶颈

        数据库服务器都只有有限的RAM,出现内存争用现象是Oracle的常见问题。
        首先察看RAM的数量,命令如下(LINUX环境):
        [root@brucelau root]#free
                  total       used       free        shared    buffers     cached
        Mem:    1027348     873312     154036     185736     187496     293964
        -/+ buffers/cache:    391852    635496
        Swap:    2096440       0    2096440
          
        当然可以使用top等其他命令来显示RAM。

        当内存的需求大于RAM的数量,服务器启动了虚拟内存机制,通过虚拟内存,可以将RAM段移到SWAP DISK的特殊磁盘段上,这样会出现虚拟内存的页导出和页导入现象,页导出并不能说明RAM瓶颈,虚拟内存系统经常会对内存段进行页导出,但页导入操作就 表明了服务器需要更多的内存了,页导入需要从SWAP DISK上将内存段复制回RAM,导致服务器速度变慢。
          
        解决的办法有几种:
        1.    最简单的,加大RAM
        2.    改小SGA,使得对RAM需求减少
        3.    减少RAM的需求(如:减少PGA)
          
        我们基本的了解了VMSTAT工作,下面是STATSPACK通过vmstat统计收集服务器性能数据。
          
        STATSPACK通过vmstat收集服务器信息
        首先在perfstat用户下建一个存储服务器信息的表:如
        建表:
        create table stats$vmstat
        (
        start_date date,   --系统时间
        duration date,   --时间间隔
        server_name varchar2(20), --服务器名称
        runque_waits number, --运行队列数据
        page_in   number, --页导入数据
        page_out number, --页导出数据
        user_cpu number, --用户cpu数据
        system_cpu number, --系统cpu数据
        idle_cpu number, --空闲cpu数据
        wait_cpu number –等待cpu数据(只是aix存在)
        )
        tablespace perfstat;
        然后,通过UNIX/LINUX的shell变成,利用vmstat的结果来获取相应的服务器信息,并且存放到表中。

         

        转载:http://hi.baidu.com/leukoli/blog/item/004e2f8b13ae8edafc1f100a.html

      • Android自动化测试初探

        sunny508 发布于 2011-06-23 20:12:34

        Android自动化测试初探

          入职两月有余,从之前的android app开发到现在的测试框架开发,工作中遇到很多问题,趁这次机会分享一下。

          Android自动化测试目前可借鉴的经验不多,现在采取的方式就是通过java代码对Activity和View进行操作,目前已知的入口是Instrumentation类。

          Instrumentation与Activity均位于android.app包下,这个包内还有诸如ActivityManagerNative这种不对App层开放的类,通过查看Android源码发现Activity类中诸如startActivity(Intent intent)这样重要的方法都是通过Instrumentation实现,Instrumentation中也提供了一系列对Activity生命周期控制的方法。以Instrumentation为基础,Android SDK在Junit基础上进行了扩展,提供了AndroidTestCase类及系列子类,其中最重要的一个类是ActivityInstrumentationTestCase2。

          基于Instrumentation的测试框架的工作原理SDK中的这张图说明的很清楚了:

          研究Android源码发现框架层中有很多对测试有帮助的类、方法都被加上了@hide注解或是声明为private的,无法从app层访问。自然而然我们想到了java的反射机制, java反射允许我们访问这样的类和方法。

          在上面的基础上,国外有人开发出了Robotium工具,可以在有app源码或apk的情况下进行自动化黑盒测试

          但是Robotium目前的缺点也很明显,无法对WebView进行操作,这对大量使用WebView的淘宝Android客户端来说无疑是很大的限制。

          而且Robotium提供的API是面向过程的,测试代码的可扩展性差。

          我们需要一个面向对象的,可对WebView进行操作的自动化测试框架,这就催生了TMTS(Taobao Mobile Test Studio)框架。

          TMTS立项时还试图着重解决另一个问题,就是Instrumentation框架下testapp和app运行在一个进程中 ,app crash会导致testapp一并crash。当时和士敦一起研究了Instrumentation、Activity的启动流程,甚至想去研究一下dalvik是如何解析Manifest文件的,最后也没有想到好的方法,收获就是了解了android更底层一些的细节,这个问题现在先搁置了起来。

        从测试代码方面来看, Robotium中采用的是actionMethod(View, arg)的方式,TMTS中采用getView(id).actionMethod(arg)的方式,更加符合java的编程习惯。TMTS测试代码的编写也就是分三步,找到View,调用View的相应的action方法,断言。

          TMTS框架主要思想就是通过反射机制调用Android框架层API拿到当前Activity的所有View,在此基础上返回需要获得的View对象,对获得的View通过Instrumentation封装一些此View常用的操作,最后返回,这就是TmtsView及其子类。

          这种方式缺点也很明显,对每个从android.View继承来的子类,如果其中有特殊的操作,就需要封装出一个对应的TmtsView子类。

          还有一个缺点就是目前是通过View在布局文件中声明的id去寻找,这样测试人员在编写代码时需要对app的源码非常熟悉,了解当前操作的view的id是多少,在传递id参数时还有可能写错。之后我们对这个方式进行了一些改进,使用SDK自带的hierarchyviewer工具获得view的id;对每个布局文件进行解析生成java类,这个类中会提供方法返回布局文件中的所有带id的view,经过讨论,最后按view子类型来对一个布局中的view进行归类。

          现在测试代码从getView(id).actionMethod(arg)演变成了Layout(layout.class).ViewType().view().actionMethod(arg)的方式,代码虽然变长了,但是出错的可能性大大降低了。

          Bug的定位离不开日志,因而日志系统也是一个测试框架重要的组成部分,Android的Log类中提供了一系列的静态方法可以在IDE中打印日志。在TMTS中,提供TmtsLog类,除日志打印外可将日志内容实时保存至SD卡指定目录,在框架代码中的关键部位都加上了这样的日志用来保存异常时的调用栈信息,用户的测试代码中也可以加上对TmtsLog的调用跟踪测试代码执行进度,TmtsLog将为每个测试类保存一份这样的日志文件,同时包含用户的过程日志和框架异常日志,文件名以精确到毫秒的日期加以区分。

          项目做到这里远远没有结束,套用屈原的一句话就是路漫漫其修远兮。

          后面计划解决的问题有:

          1.跨进程测试,让testapp和app运行在两个不同的进程中,这是一个大坑。

          2.稳定性问题,目前框架中有很多地方硬编码Thread.sleep()去等待一个View加载完成,避免对空的View进行操作,或者是对一个view进行set操作后,也需要等待一段时间让操作生效。希望能找到一种回调机制优雅的解决。

          3.设法捕获Toast消息

          后面可能会研究的方向,是通过非java的方式来实现android自动化测试。Android目前已经通过ASE(Android Scripting Environment)支持了多种脚本语言,如phyton,lua,perl等,限于目前的人力还没有时间来研究这一块,相信ASE会给Android自动化开辟一片新天地。

          最后谈一点点感悟,老子曾经曰过:“持而盈之,不如其已;揣而锐之,不可长保。金玉满堂,莫之能守;富贵而骄,自遗其咎。”和“重为轻根,静为躁君。”第一句话说有缺陷才是真正的完美,没有一个方案是真正完美的。第二句话说有时候看起来完美的方案,过段时间之后又不适用了,而且不适用的地方很可能就是当初觉得完美的地方,对于软件项目解决方案也是如此。

          分享到此结束,敬请期待士敦下次关于WebView方面的分享。

      • LoadRunner性能测试指标

        超越自我 发布于 2008-11-14 15:51:32

        LoadRunner性能测试指标

        Object

        Counters

        Descrīption

        Reference value

        Memory

        Available Mbytes

        可用物理内存数.如果Available Mbytes的值很小(4 MB或更小),则说明计算机上总的内存可能不足,或某程序没有释放内存。

        4 MB或更小,至少要有10%的物理内存值

        Page/sec

        (Input/Out)

        为了解析硬页错误,从磁盘取出或写入的页数。一般如果Page/sec持续高于几百,那么您应该进一步研究页交换活动。有可能需要增加内存,以减少换页的需求(你可以把这个数字乘以4k就得到由此引起的硬盘数据流量)。Pages/sec的值很大不一定表明内存有问题,而可能是运行使用内存映射文件的程序所致。

        推荐00-20

        如果服务器没有足够的内存处理其工作负荷,此数值将一直很高。如果大于80,表示有问题(太多的读写数据操作要访问磁盘,可考虑增加内存或优化读写数据的算法)

        该系列计数器的值比较低说明响应请求比较快, 否则可能是服务器系统内存短缺引起(也可能是缓存太大, 导致系统内存太少)。

         

         

        >5越低越好

        Page Fault

        处理器每秒处理的错误页(包括软/硬错误)。

        当处理器向内存指定的位置请求一页(可能是数据或代码)出现错误时,这就构成一个Page Fault。如果该页在内存的其他位置,该错误被称为软错误(用Transition Fault/sec记数器衡量);如果该页必须从硬盘上重新读取时,被称为硬错误。许多处理器可以在有大量软错误的情况下继续操作。但是,硬错误可以导致明显的拖延。

        Page Input/sec

        为了解决硬错误页,从磁盘上读取的页数。

        Page Output/sec

         

        Page reads/sec

        为了解决硬错误页,从磁盘上读取的次数。解析对内存的引用,必须读取页文件的次数。阈值为>5.越低越好。大数值表示磁盘读而不是缓存读。

        Cache Bytes

        文件系统缓存,默认情况下为50%的可用物理内存。如IIS5.0运行内存不够时,它会自动整理缓存。需要关注该计数器的趋势变化

         

        内存泄露

        如果您怀疑有内存泄露,请监视Memory\\ Available BytesMemory\\ Committed Bytes,以观察内存行为,并监视您认为可能在泄露内存的进程的Process\\Private BytesProcess\\Working SetProcess\\Handle Count。如果您怀疑是内核模式进程导致了泄露,则还应该监视Memory\\Pool Nonpaged BytesMemory\\ Pool Nonpaged AllocsProcess(process_name)\\ Pool Nonpaged Bytes

         

        Process

        Page Faults/sec

        将进程产生的页故障与系统产生的相比较,以判断这个进程对系统页故障产生的影响。

         

        Private Bytes

        此进程所分配的无法与其它进程共享的当前字节数量。如果系统性能随着时间而降低,则此计数器可以是内存泄漏的最佳指示器。

         

        Work set

        处理线程最近使用的内存页,反映了每一个进程使用的内存页的数量。如果服务器有足够的空闲内存,页就会被留在工作集中,当自由内存少于一个特定的阈值时,页就会被清除出工作集。

         

        Processor

        % Processor Time

        被消耗的处理器时间数量.如果服务器专用于sqlserver可接受的最大上限是80% -85%.也就是常见的CPU使用率.

         

        ProcessorQueue Length

        判断CPU瓶颈,如果processor queue length显示的队列长度保持不变(>=2)并且处理器的利用率%Processor time超过90%,那么很可能存在处理器瓶颈.如果发现processor queue length显示的队列长度超过2,而处理器的利用率却一直很低,或许更应该去解决处理器阻塞问题,这里处理器一般不是瓶颈.

         

        Physical

        Disk

        %DiskTime

        指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。

        正常值<10,此值过大表示耗费太多时间来访问磁盘,可考虑增加内存、更换更快的硬盘、优化读写数据的算法。若数值持续超过80 (此时处理器及网络连接并没有饱和),则可能是内存泄漏。

         

        CurrentDiskQueueLength

        读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。(磁盘数1.5-2)

         

        Avg.Disk Queue

        Length

        Avg.Disk Read

        QueueLength

        Avg.Disk Write

        QueueLength

        Disk Read/sec

        Disk Write/sec

        读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。

        磁盘瓶颈判断公式:

        每磁盘的I/O=(读次数+4*写次数))/磁盘个数。

        如果计算出来的每磁盘的I/O数大于磁盘的处理能力,那么磁盘存在瓶颈。

        Avg.DiskQueue Length正常值<0.5,此值过大表示磁盘IO太慢,要更换更快的硬盘。

         

         

        附:

        1、SQL数据库:
        1. User 0 Connections (用户连接数,也就是
        数据库的连接数量);
        2. Number of deadlocks/Sec/-Total (数据库死锁)
        3. Memory\ Availalle Mbyte 内存监控 (可用内存)
        4. Physicsdisk \disk time \-Total(磁盘读写总时间)(出现瓶颈时检查读磁盘的时间长还是写磁盘的时间长)
        5. Butter Caile hit(数据库缓存的选取命中率)
        6. 数据库的命中率不能低于92%
        2、Web Server:
        1. Processor \ Processon time \ Tatol cpu时间
        2. Memory \ Availalle MbyteAvai 应用服务器的内存
        3. Requst Quened 进入HTTP队列的时间;队列/每秒
        4. Total request 总请求数时间
        5. Avg Rps 平均每秒钟响应次数= 总请求时间 / 秒数
        6. Avg time to last byte per terstion (mstes)平均每秒迭代次数 ; 上一个页面到下一个页面的时间是你录入角本的一个过程的执行
        7. Http Error 无效请求次数
        8. Send 发送请求次数字节数
        Webload的压力参数:
        l Load Size(压力规模大小)
        l Round Time(请求时间)
        l Rounds (请求数)
        l Successful Rounds(成功的请求)
        l Failed Rounds (失败的请求)
        l Rounds Per Second (每秒请求次数)(是指你录入角本的任务在一秒中执行的次数,类似Avg time to last byte per terstion (mstes))
        l Successful Rounds Per Second(每秒成功的请求次数)
        l Failed Rounds Per Second(每秒失败的请求次数)
        l Page Time 页面响应时间
        l Pages (页面数)
        l Pages Per Second (每秒页面响应数)
        l H it Time(点击时间)
        l Hits(点击次数,也可以是请求次数,不过有一些不一样)
        l Successful Hits (成功的点击次数)
        l Failed Hits (失败的点击次数)
        l Hits Per Second (每秒点击数)
        l Successful Hits Per Second (每秒成功的点击次数)
        l Failed Hits Per Second (每秒失败的点击次数)
        l Attempted Connections (尝试链接数)
        l Successful Connections(成功的连接数)
        l Failed Connections(失败的连接数)
        l Connect Time(连接时间)
        l Process Time(系统执行时间,一般用来显示CPU的运算量,服务器端与客户端都要记录)
        l Receive Time(接受时间)
        l Send Time(请求时间)
        l Time To First Byte ()
        l Throughput (Bytes Per Second)()
        l Response Time(回应时间)
        l Response Data Size()
        l Responses()
         
         
         
        Transactions per second(每秒处理事务数) http连接Get or Post方法的事务数
        Rounds per second(每秒完成数) 每秒完全执行Agenda〔代理〕的数量
        Throughput(吞吐量)(bytes per second〔每秒字节数〕) 测试服务器每秒传送的字节数
        Round Time 完成一次事务所用的必要时间,单位是秒
        Transaction Time是完成一次事务的必须时间。事务:包括连接时间,发送、响应和处理时间。
        Connect Time 客户端到测试服务器的一个连接完成的时间,单位秒(包括建立和收到的TCP/IP时间)
        Send Time 是将事务写入测试服务器的缓冲必要时间 ,单位秒
        Response Time 是客户端请求接受测试服务器响应的必要时间,单位秒
        Process Time 处理数据的必要时间
        Load Size 负载测试时开启的虚拟客户数量〕
        Rounds 在测试会话期间执行议程脚本的时间数
        Attempted Connections 尝试连接测试服务器的数量
        HTTP Response Status 每一个http响应被结束的时间数量
        Response Data Size 由测试服务器发送的响应大小,单位字节。

      • 【转】Linux 下使用 NMON 分析系统性能

        pconline_qa 发布于 2010-01-25 15:31:39

        下载相应 CPU 类型的版本:
        http://nmon.sourceforge.net/pmwiki.php?n=Site.Download

        wget http://sourceforge.net/projects/nmon/files/download/nmon_x86_12a.zip/download
        unzip nmon_x86_12a.zip
        Archive:  nmon_x86_12a.zip
          inflating: nmon_x86_rhel45
          inflating: nmon_x86_rhel52
          inflating: nmon_x86_sles9
          inflating: nmon_x86_sles10
          inflating: nmon_x86_ubuntu810
          inflating: nmon_x86_fedora10
          inflating: nmon_x86_opensuse10

        使用对应的操作系统文件:
        chmod +x nmon_x86_ubuntu810
        mv nmon_x86_ubuntu810 /usr/local/bin/nmon

        对于 Debian 还要做以下操作(不做也同样能运行):
        apt-get install lsb-release
        lsb_release -d | sed 's/Description:\t//' > /etc/debian_release

        然后直接运行 nmon 即可。

        采集数据并生成报表:
        采集数据:
        nmon -s10 -c60 -f -m /home/

        参数解释:
        -s10 每 10 秒采集一次数据。
        -c60 采集 60 次,即为采集十分钟的数据。
        -f 生成的数据文件名中包含文件创建的时间。
        -m 生成的数据文件的存放目录。

        这样就会生成一个 nmon 文件,并每十秒更新一次,直到十分钟后。
        生成的文件名如: hostname_090824_1306.nmon ,"hostname" 是这台主机的主机名。

        生成报表:
        下载 nmon analyser (生成性能报告的免费工具):
        http://www.ibm.com/developerworks/wikis/display/Wikiptype/nmonanalyser

        把之前生成的 nmon 数据文件传到 Windows 机器上,用 Excel 打开分析工具 nmon analyser v33C.xls 。点击 Excel 文件中的 "Analyze nmon data" 按钮,选择 nmon 数据文件,这样就会生成一个分析后的结果文件: hostname_090824_1306.nmon.xls ,用 Excel 打开生成的文件就可以看到结果了。

        如果宏不能运行,需要做以下操作:
        工具 -> 宏 -> 安全性 -> 中,然后再打开文件并允许运行宏。

        自动按天采集数据:
        在 crontab 中增加一条记录:
        0 0 * * * root nmon -s300 -c288 -f -m /home/ > /dev/null 2>&1

        300*288=86400 秒,正好是一天的数据。

        参考资料:
        nmon for Linux:
        http://nmon.sourceforge.net/pmwiki.php

        nmon 性能:分析 AIX 和 Linux 性能的免费工具:
        http://www.ibm.com/developerworks/cn/aix/library/analyze_aix/index.html

        nmon analyser —— 生成 AIX 性能报告的免费工具:
        http://www.ibm.com/developerworks/cn/aix/library/nmon_analyser/index.html

      • 利用JProfiler对应用服务器内存泄漏问题诊断一例(转)

        超越自我 发布于 2008-11-15 16:42:48

        在中间件应用服务器的整体调优中,有关于等待队列、执行线程,EJB池以及数据库连接池和Statement Cache方面的调优,这些都属于系统参数方面的调优,本文主要从另外一个角度,也就是从应用的角度来解决中间件应用服务器的内存泄露问题,从这个角度来提高系统的稳定性和性能。

        项目背景

        问题描述

        某个大型项目(Use Case用例超过300个),在项目上线后,其Web应用服务器经常宕机。表现为:

        1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

        2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

        3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。

        Web应用服务器的物理部署

              一台Unix服务器(4CPU,8G Memory)来部署本Web应用程序;Web应用程序部署在中间件应用服务器上;部署了一个节点(Node),只配置一个应用服务器实例(Instance),没有做Cluster部署。

        Web应用服务器启动脚本中的内存参数

        MEM_ARGS="-XX:MaxPermSize=128m -XX:MaxNewSize=512m -Xms3096m
        -Xmx3096m -XX:+Printetails -Xloggc:./inwebapp1/gc.$$"

        可以看出目前生产系统中Web应用服务器的内存分配为3G Memory。

        Web应用服务器的重要部署参数

        参数名称 参数值 参数解释
        kernel.default(Thread Count) 120 执行线程数目,是并发处理能力的重要参数
        Session Timeout 240分钟(4小时) HttpSession会话超时

         

        分析

        分析方法

        内存长期占用并导致系统不稳定一般有两种可能:

        1. 对象被大量创建而且被缓存,在旧的对象释放前又有大量新的对象被创建使得内存长期高位占用。

        • 表现为:内存不断被消耗、在高位时也很难回归到低位,有大量的对象在不断的创建,经过很长时间后又被回收。例如:在HttpSession中保存了大量的分页查询数据,而HttpSession的会话超时时间设置过长(例如:1天),那么在旧的对象释放前又有大量新的对象在第二天产生。
        • 解决办法:对共享的对象可以采用池机制进行缓存,避免各自创建;缓存的临时对象应该及时释放;另一种办法是扩大系统的内存容量。

        2. 另一种情况就是内存泄漏问题

        • 表现为:内存回收低位点不断升高(以每次内存回收的最低点连成一条直线,那么它是一条上升线);内存回收的频率也越来越高,内存占用也越来越高,最终出现"Out of Memory Exception"的系统异常。
        • 解决办法:定位那些有内存泄漏的类或对象并修改完善这些类以避免内存泄漏。方法是:经过一段时间的测试、监控,如果某个类的对象数目屡创新高,即使在JVM Full GC后仍然数目降不下来,这些对象基本上是属于内存泄漏的对象了。

        问题定位

        这里请看5月份 Web应用服务器的内存回收图形:

        《注意:5月18日早上10点重新启动了Web服务器,5月20日早上又重新启动了Web服务器。》

        • 在Web应用重要部署参数中,我们知道:Session的超时时间为4个小时,我们在监控平台也观测到:在18日晚上10点左右所有的会话都过期了,从图形一中也能看出18日晚上确实系统的内存有回收到40%(就象股票的高位跳水);
        • 从图形一(5月18日)中我们也能看到Full GC回收后的内存占用率走势(红色曲线),上午基本平滑上升到20%(内存占用率),中午开始上升到30%,下午上升到40%
        • 从图形二(5月19日)中我们也能看到Full GC回收后的内存占用率走势(红色曲线),上午又上升到了60%,到下午上升到了70%。
        • 从黄色曲线(GC花费的时间,以秒为单位),Full GC的频率也在增快,时间耗费也越来越长,在图形一中基本高位在20秒左右,到19日基本都是30-40秒之间了。

         图形一 5月18日
        图形一 5月18日

        图二
        图二

        通过上述分析,我们基本定位到了Web应用服务器的内存在高位长期占用的原因了:是内存泄露!并且正是由于这个原因导致系统不稳定、响应客户请求越来越慢的。

        解决方法

        方法如下:

        • 我们从图形二中发现,在8.95(将近9点钟)到9.66(将近9点40)期间有几次Full GC,但是有内存泄漏,从占用率40%上升到50%左右,泄漏了大约10%的内存,约300M;
        • 我们在自己搭建的Web应用服务器平台(应用软件版本和生产版本一致)做这一阶段相同的查询交易;表明对同一个黑盒(Web应用)施加同样的刺激(相同的操作过程和查询交易)以期重现现象;
        • 我们使用Jprofiler工具对Web应用服务器的内存进行实时监控;
        • 做完这些交易后,用户退出系统,并等待Web应用服务器的HttpSession超时(我们这里设置为15分钟);
        • 我们对Web应用服务器做了两次强制性的内存回收操作。

        发现如下:


        图三
        图三

        如图三所示,内存经过HttpSession超时后,并强制gc后,仍然有大量的对象没有释放。例如:gov.gdlt.taxcore.comm.security.MenuNode,仍然有807个实例没有释放。

        我们继续追溯发现,这些MenuNode首先存放在一个ArrayList对象中,然后发现这个ArrayList对象又是存放在WHsessionAttrVO对象的Map中,WHsessionAttrVO 对象又是存放在ExternalSessionManager的staic Map中(名称为sessionMap),如图四所示。


        图四
        图四

        我们发现gov.gdlt.taxcore.taxevent.xtgl.comm.WHsessionAttrVO中保存了EJBSessionId信息(登录用户的唯一标志,由用户id+登录时间戳组成,每天都不同)和一个HashMap,这个HashMap中的内容有:

        • ArrayList: 内有MenuTreeNodes(菜单树节点)
        • HashMap: 内有操作人员代码信息
        • CurrentVersion:当前版本号
        • CurrentTime:当前系统时间

        WHsessionAttrVO这个对象的最终存放在ExternalSessionManager的static Map sessionMap中,由于ExternalSessionManager是一个全局的单实例,不会释放,所以它的成员变量sessionMap中的数据也不会释放,而Map中的Key值为EJBSessionId,每天登录的用户EJBSessionId都不同,就造成了每天的登录信息(包括菜单信息)都保存在sessionMap中不会被释放,最终造成了内存的泄漏。


        图五
        图五

        如上图所示:WHsessionAttrsVO对象中除了有一个String对象(内容是EJBSessionId),还有一个HashMap对象。


        图六
        图六

        如上图所示,这个HashMap中的内容主要有menuTreeNodes为key,value为ArrayList的对象和以czrydminfo为key,value为HashMap对象的数据。


        图七
        图七

        如上图所示:menuTreeNodes为key,value为ArrayList对象中包含的对象有许多的MenuNode对象,封装的都是用户的菜单节点。


        图八
        图八

        如上图所示,最顶层(Root)的初始对象为一个ExternalSessionManager对象,其中的一个成员变量为static (静态的),名称为:sessionMap,这个对象是singleton方式的,全局只有一个。

        初步估量

        我们从图形一和图形二中可以看出,每天应用服务器损失大约40%的内存,大约1G左右。

        从图形四可以看出,当前用户(Id=24400001129)有807个菜单项(每个菜单项为一个MenuNode 对象实例,图形四中的这个实例的size为592 Byte),这些菜单数据和用户基本登录信息(czrydmInfo HashMap)也都存放在WHsessionAttrVO对象中,当前这个WHsessionAttrVO对象的size为457K。

        我们做如下估算:

        假设平均每天有4千人(估计值,这个数值仅仅是5月19日峰值的1/2左右)登录系统(有重复登录的现象,例如:上午登录一次,中午退出系统,下午登录一次),以平均每人占用200K(估计值,是用户id=24400001129 的Size的1/2左右)来计算,一天泄漏的内存约800M,比较符合目前内存泄漏的情况。当然,这种估计仍然需要经过实践的检验,方法是:当这次发现的内存泄漏问题解决后看系统是否还有其它内存泄漏问题。


        方案

        ExternalSessionManager类是当初某某软件商设计的用来解决Web服务器负载均衡的模块,这个类主要用来保存客户的基本登录信息(包括会话的EJBSessionId),以维护多个Web服务器之间的会话信息一致。

        改进方案有两种:

        • 从架构设计方面改进

          实现Web层的负载均衡有很多标准的实现方式。例如:采用负载均衡设备(硬件或软件)来实现。

          如果采用新的Web层的负载均衡方式,那么就可以去掉ExternalSessionManager这个类了。

        • 从应用实现方面改进

          保留当前的Web层的负载均衡设计机制,仅仅从应用实现方面解决内存泄漏问题,首先菜单信息不应该保存在ExternalSessionManager中。其次,增加对ExternalSessionManager类中用户会话登录信息的清除,有几种方式可以选择:

          • 被动方式,当HttpSession会话超时(或过期)被Web应用服务器回收时清除相应的ExternalSessionManager中的过期会话登录信息。
          • 主动方式,可以采用任务定时清理每天的过期会话登录信息或线程轮询清理。
          • 采用新的会话登录信息存储方式,ExternalSessionManager的sessionMap中的key值不再以EJBSessionId作为键值,而是以用户id(EJBSessionId的前11位)代替。由于用户id每天都是一样的,所以不会造成内存泄漏。保存得登录信息也不再包含菜单节点信息,而只是登录基本信息。最多也只是保存整个系统所有的用户id及其基本登录信息(大约每个用户的登录信息只有1.5K左右,而目前这个系统的营业网点用户为1万左右,所以大约只占用Web服务器15M内存)。


        实施情况

        采用的方案:某某软件商采用了新的会话登录信息存贮方案,即:ExternalSessionManager的成员变量sessionMap中不再保存用户菜单信息,只保存基本的登录信息;存储方式采用用户id(11位)作为键值(key)来保留用户基本登录信息。

        基本分析:由于基本登录信息只有1K左右,而目前内网登录的用户总数也只有8887个,所以只保存了大约10M-15M的信息在内存,占用量很小,并且不会有内存泄漏。用户菜单信息保存在session中,如果用户退出时点击logout页面,那么应用服务器可以很快地释放这部分内存;如果用户直接关闭窗口,那么保存在session中的菜单信息只有等会话超时后才会由系统清除并回收内存。

        监控状况:


        图九
        图九

        如图九所示,ExternalSessionManager中只保留了简单的登录信息(Map中保存了WHsessionAttrVO对象),包括:当前版本(currentversion),操作人员代码基本信息(czrydmInfo),当前时间(currenttime)。


        图十
        图十

        如图十所示,这个登录用户的基本信息只有1368 bytes,大约1.3K


        图十一
        图十一

        如图十一所示,一共有两个用户(相同的用户id)登录系统,当一个用户使用logout页面退出时,保留在session中的菜单信息(MenuNode)立刻释放了,所以Difference一栏减少了806个菜单项。


        图十二
        图十二

        如图十二所示,当另外一个会话超时后,应用服务器回收了整个会话的菜单信息(MenuNode),图上已经没有MenuNode对象了。并且由于是同一个用户登录,所以保留在ExternalSessionManager成员变量sessionMap中的对象WHsessionAttrVO只有一个(id=24400001129),而没有产生多个,没有因为多次登录而产生多个对象的后果,避免了内存泄漏问题的出现,解决了前期定位的内存泄漏问题。


        图十三
        图十三

        如图十三所示,经过gc内存回收后,发现内存回收比较稳定,基本都回收到了最低点,也证明了内存没有泄露。

        结论与建议:从测试情况看,解决了前期定位的内存泄漏问题。

        生产系统实施后的监控与分析

        经过调优后,我们发现:在2005年6月2日晚9点40左右重新部署、启动了Web应用服务器(采用了新的调优方案)。经过几天的监控运行,发现Web应用服务器目前运行基本稳定,目前没有出现新的内存泄漏问题,下列图示说明了这一点


        图十四 2005年6月2日
        图十四 2005年6月2日

        如图十四所示,6月2日晚21.7(21点42分)重新启动应用服务器,内存占用很少,大约为15%(请看红色曲线),每次GC消耗的时间也很短,大约在5秒以内(请看黄色曲线)。


        图十五 2005年6月3日周五
        图十五 2005年6月3日周五

        如图十五所示,在6月3日周五的整个工作日内,内存的回收基本到位,回收位置控制在20%-30%之间,也就是在600M-900M之间(请看红色曲线的最低点),始终可以回收2G的内存供应用程序使用,每次GC的时间最高不超过20秒,Full GC平均在10秒左右,时间消耗比较短(请看黄色曲线)。


        图十六2005年6月5日周日
        图十六2005年6月5日周日

        如图十六所示,在周日休息日期间,Web应用服务器全天只做了大约4次Full GC(黄色曲线中的小山峰),时间都在10秒以内;大的Full GC后,内存只占用10%,内存回收很彻底。


        图十七 2005年6月6日周一
        图十七 2005年6月6日周一

        如图十七所示,在周一工作日期间,内存回收还是不错的,基本可以回收到30%(见红色曲线的最低点),即:占用900M内存空间,剩余2G的内存空间;Full GC的时间大部分控制在20秒以内,平均15秒(见黄色曲线)。


        图十八 2005年6月7日周二
        图十八 2005年6月7日周二

        如图十八所示,在6月7日周二早上,大约8:30左右,Web应用服务器作了一次Full GC,用了10秒的时间,把内存回收到了10%的位置,为后续的使用腾出了90%的内存空间。内存回收仍然比较彻底,说明基本没有内存泄漏问题。

        经过这几天的监控分析,我们可以看出:

        • Web应用服务器的内存使用已经比较合理,内存在工作日的占用在20%至30%之间,约1G的内存占用,有2G的内存空间富裕;而在空闲时间(周日,每天的凌晨等)内存可以回收到10%,有90%的内存空间富裕;
        • Web应用服务器的Full GC的次数明显减少了并且每次Full GC占用的时间也很少,基本控制在10-20秒之间,有的甚至在10秒以内,明显改善了内网应用服务器内存的使用;
        • 从6月2日重新部署之后,Web应用服务器没有出现宕机重启的现象。

         

        总结

         通过本文,我们可以看到,内存的泄露将会导致服务器的宕机,系统性能就更别说了。对于系统内存泄露问题应该从服务器GC日志方面进行早诊断,使用工具早确认并提出解决方案,排除内存泄露问题,提高系统性能,以规避项目风险。

      • LoadRunner 使用system函数进行log的自动分析

        qiguojie 发布于 2007-08-23 14:10:58

        LoadRunner 使用system函数进行log的自动分析

         

        PS:本人在51testing和sina blog上的文章全部为原创,转载请注明出处!!

        我在《明确LoadRunner可以输出的结果》中,讲到可以使用lr_out_message输出log,但是这个是lr自己的log,是按vuser分成一个个的小文件;也可以使用fprintf()等相关函数来进行自定义log的输出,使fprintf()函数进行的log输出,有很大的灵活性,语句也不复杂,实在是强化脚本一大利器。

        但是如果运行1000vuser,测试过程中脚本平均每个vuser迭代执行50次,每个脚本共输出5条log,那么log文件有多少行?
               1000*50*5=250000
        如果用记事本打开+查找那也实在太麻烦了,我这人太懒,琢磨着还是自己写脚本实现吧。

        其实在文本处理这块,用perl程序(脚本语言)或者shell(脚本语言)来处理是比较方便的,在windows下也可以用批处理文件+find来进行自动分析,不过偶既然在学lr,当然是用lr来实现是最好。

        主要实现方法介绍:
        1、使用fprintf()及相关函数输出log
        2、使用mkdir创建新文件夹
        3、使用system调用dos命令,对log文件进行条件分解


        如下面的例子,共有5个fprintf()函数进行log输出:
        ===================================================================
        /*********************************
          * Author:qiguojie
          * object:software login
          * date:2007-5-28
        ***********************************/
        Action()
        {
        //变量定义区
        typedef long time_t;       //定义一个时间变量
        char *filename = "c:\\work\\log\\log.log";      //定义一个文件指针,指向log输入的地址
        long file_stream;        //定义一个长整型变量
        time_t t;        //定义一个时间变量

        if ((file_stream = fopen(filename,"a+")) == NULL)   //打开文件
        {
            lr_error_message("Cannot open %s", filename);
            return -1;
        }
        web_reg_save_param("IsRight","LB=Cache-control: private\r\n\r\n","RB=|",LAST);  //保存返回值
        time(&t);        //获取当前时间
        web_url("abclogin.asp",
            "URL=http://192.168.1.9/soft/abclogin.asp?U={user}&P={password}&L=0&H=3HS28QKH",
            "Resource=0",
            "RecContentType=text/html",
            "Referer=",
            "Snapshot=t1.inf",
            "Mode=HTML",
            LAST);
        fprintf(file_stream,"迭代过程开始…………,时间是%s",ctime(&t));
        fprintf(file_stream,"%s,随机数是%d,",ctime(&t),n);
        fprintf(file_stream,"用户是:%s,密码是:%s,",lr_eval_string("{user}"),lr_eval_string("{password}"));
        //判断返回值,输入对应日志
        if (strcmp(lr_eval_string ("{IsRight}"),"A") == 0)//如果返回值是A
        {
            fprintf(file_stream,"success:用户登录成功,返回值是:%s\n",lr_eval_string("{IsRight}"));
        }
        else if (strcmp(lr_eval_string ("{IsRight}"),"X") == 0) //如果返回值是X
        {
            fprintf(file_stream,"failed:用户登录失败,返回值是:%s\n",lr_eval_string("{IsRight}"));
        }
        else if (strcmp(lr_eval_string ("{IsRight}"),"Z") == 0)//如果返回值是Z
        {
            fprintf(file_stream,"success_others:登录特殊页成功,返回值是:%s\n",lr_eval_string("{IsRight}"));
        }
        else //如果返回值是D
        {
            fprintf(file_stream,"success_free:登录免费用户成功,返回值是:%s\n",lr_eval_string("{IsRight}"));
        }
        fprintf(file_stream,"迭代过程结束…………,时间是%s",ctime(&t));
        fclose(
        file_stream); 
        return 0;
        }

        ===================================================================
        脚本设置1000个vuser和迭代50次,那么测试完毕正常的话可以输出250000条日志!!这些日志以不同的关键字开始(success、failed、success_others、success_free)!!
        好了,不多白活了,进行分解的脚本编写!!
        mkdir()函数说明
        int mkdir ( const char *path );
        功能:创建一个目录(输入一个完整路径)

        system()函数说明
        int system ( const char *string );
        功能:执行一个操作系统的命令行命令
        PS:system可以运行dos命令,这样我们的脚本就可以扩展更多的功能

        DOS命令find函数简易用法
        find[空格][const char *string][空格][要查找的文件路径]输出运算符">"[查找结果保存的文件]
        例如:find "123" c:\result.log > c:\123.log
              就是把result.log文件里所有包含"123"的行取出来,放到新文件"123.log"里

        创建新文件夹放在init()里,而分解log的system()函数则放在end里;脚本分别如下:
        vuser_init()
        {
            char new_dir[] = "C:\\work\\log\\FJ_log";
            mkdir(new_dir);
            return 0;
        }

        vuser_end()
        {
            system("find \"success:\" c:\\work\\log\\log.log >C:\\work\\log\\FJ_log\\success.log");
            system("find \"failed:\" c:\\work\\log\\log.log >C:\\work\\log\\FJ_log\\failed.log");
            system("find \"success_others\" c:\\work\\log\\log.log >C:\\work\\log\\FJ_log\\success_others.log");
            system("find \"success_free\" c:\\work\\log\\log.log >C:\\work\\log\\FJ_log\\success_free.log");
            return 0;
        }
        PS:这些例子里路径都是写死的,每次重新启动测试,都需要更新脚本;大家可以通过强化脚本来实现参数化路径和文件名。
        这样,在全部脚本执行完毕后,去C:\work\log\FJ_log目录下,就可以看到有分别记录不同的结果的4个文件了(success.log、failed.log、success_others.log、success_free.log)

      • (转)LoadRunner脚本解释分析

        shuishixingyu 发布于 2009-03-21 17:05:33

        1、获得网站首页
            web_url("www.seventest.net",
                "URL=www.seventest.net/",
                "TargetFrame=",  //
        目标窗口_BLANK:打开一个新窗口
                                                  _PARENT:
        取代最后一个窗口的父窗口
                                                  _SELF:
        取代最后一个窗口

                                                  _TOP:
        取代整个页面
                "Resource=0",            //URL
        是否为一个资源  0:不是

                                                             1:

                "RecContentType=text/html", //
        录制过程中,响应报头内容格式
                "Referer=",                 //
        提交网页的URL
                "Snapshot=t1.inf",          //
        快照文件名

                "Mode=HTML",                //
        录制水平: HTML or HTTP.

        HTML level:指导VuGen录制直观的HTML动作,录制web_url,web_link,web_image。返回的是HTML页面,而不是脚本和程序。
        HTTP level:
        指导VuGen录制全部的服务器响应。不产生web_link,web_image,web_submit_form。比HTML高级,但当读脚本时不是很直观。
                EXTRARES,                   //
        参数表划分标志(下个标志是一个资源特征表)
               "Url=/dy.css", "Referer=http://www.seventest.net/index.htm", ENDITEM,     //
        资源结束志
           
               "Url=/images/bg_03.gif", "Referer=http://www.seventest.net/index.htm", ENDITEM, 
               "Url=/images/logo-end%2020GAI.swf","Referer=http://www.seventest.net/index.htm", ENDITEM,
                "Url=/images/2.swf", "Referer=http://www.seventest.net/index.htm", ENDITEM,
                LAST);                      //
        特征表结束标志

        2、下载一个游戏
        web_url("Games",
               "URL=ftp://joe:secret@mygames.com/games/archive/loderunner.exe",
               "FtpAscii=1",         //1:
        ASCII模式执行FTP传输
                                                //0:
        二进制模式
               LAST);

        3、百度搜索科学
        Action()
        {
            //
        打开首页

         web_add_cookie ("BAIDUID=AAFDECDD16EF55636CA63DC64381BBEC:FG=1; DOMAIN=www.baidu.com");

        web_add_cookie("BDSTAT=7e00ef72b41d6156ecc574f4a7efce1b9d16fdfaaf51f3debd8f8c5497eef01f3a292df5e2fe587d;DOMAIN=www.baidu.com");

                                     //网络接口的对象表达式,经常用在JavaVB.

                                    //name=VALUE;必须
                                     //domain=DOMAIN_NAME;
        必须
                                      //expires=DATE;
                                      //path=PATH; (default path is "/")
                                      //secure
                                     //The elements in the Cookie parameter are the same as the elements in the
                                     //Set–Cookie HTTP Response Header.

         web_url("www.baidu.com",
          "URL=http://www.baidu.com/",  
          "TargetFrame=",
          "Resource=0",
          "RecContentType=text/html",
          "Referer=",
          "Snapshot=t1.inf",
          "Mode=HTML",
          EXTRARES,
          "Url=/favicon.ico", "Referer=", ENDITEM,
          LAST);

         web_add_cookie("BAIDUID=AAFDECDD16EF55636CA63DC64381BBEC:FG=1; DOMAIN=s.baidu.com");

         web_add_cookie("BDSTAT=7e00ef72b41d6156ecc574f4a7efce1b9d16fdfaaf51f3debd8f8c5497eef01f3a292df5e2fe587d;

        DOMAIN=s.baidu.com");

         lr_think_time(13);
           //
        搜索科学

         web_submit_data("s",         //
        提交数据

          "Action=http://www.baidu.com/s",    //
        提交数据的HTTP address
          "Method=GET",
          "EncType=",                       //
        编码方式

          "TargetFrame=",
          "RecContentType=text/html",
          "Referer=http://www.baidu.com/",
          "Snapshot=t2.inf",
          "Mode=HTML",               //
        录制水平
          ITEMDATA,
          "Name=wd", "Value=?", ENDITEM,
          "Name=cl", "Value=3", ENDITEM,
          EXTRARES,
          "Url=http://s.baidu.com/w.gif?path=http://www.baidu.com/s?wd=%BF%C6%D1%A7&cl=3&t=1200288916042",

        "Referer=http://www.baidu.com/s?wd=%BF%C6%D1%A7&cl=3", ENDITEM,
          LAST);

         return 0;
        }

         


      • (转)软件项目测试管理经验谈

        wyy83 发布于 2006-12-06 14:47:46

             软件项目测试管理经验谈
         
             文章出处:51testing博客 作者:hades 发布时间:2006-12-06
         
             一、软件测试员自身素质培养

            (1) 首先,应对软件测试感兴趣和对自己有自信,如果具备了这两点,那么在开发过程中不管遇到什么样的困难,我相信你一定能克服。

            (2) 善于怀疑,世界上没有绝对正确的,总有错误的地方,具有叛逆心理,别人认为不可能发生的事,我却认为可能发生。别人认为是对的,我却认为不是对的。

            (3) 打破砂锅问到底的精神,对于只出现过一次的bug,一定找出原因,不解决誓不罢休。

            (4) 保持一个良好的心情,否则可能无法把测试作好。不要把生活中的不愉快的情绪带到工作中来。

            (5) 做测试时要细心,不是所有的bug都能很容易的找出,一定要细心才能找出这些bug。

            (6) 灵活一些,聪明一点,多制造一些容易产生bug的例子。

            (7) 在有条件的情况下,多和客户沟通,他们身上有你所需要的。

            (8) 设身处地为客户着想,从他们的角度去测试系统。

            (9) 不要让程序员,以“这种情况不可能发生”这句话说服你,相反,你应该去说服他,告诉他在客户心里,并不是这样的。

            (10) 考虑问题要全面,结合客户的需求、业务的流程、和系统的构架,等多方面考虑问题。

            (11) 提出问题不要复杂化,这一点和前面的有点矛盾,如果你是一新手,暂时不要管这一点,因为最终将有你的小组成员讨论解决。

            (12) 追求完美,对于新测试员来说,努力的追求完美,这对你很好,尽管有些事无法做到,但你应该去尝试。

            (13) 幽默感,能和开发小组很好的沟通是关键,试着给你的开发小组找一个“BUG杀手”,或对他们说“我简直不敢相信,你写的程序居然到现在没有找到BUG”。

            (14) 到此是不是对测试很有兴趣呢?不过我要告诉你,测试过程中有酸甜苦辣,其中的滋味只有你知道,也许你会感到枯燥,要学会放松自己,去溜冰或做你喜欢做的事,不过,别放弃,因为你的自信告诉过你“你会是很优秀的测试员”不是吗?

            二、浅谈软件测试之技巧

            软件测试虽然辛苦,但是掌握了一定的技巧之后将使你事半功倍。

            (1) 边界测试,测试用户输入框中的数值的最大数和最小数,以及为空时的情况。

            (2) 非法测试,例如在输入数字的地方输入字母。

            (3) 跟踪测试,跟踪一条数据的流程,保证数据的正确性。

            (4) 在开始测试时应保证数据的正确性,然后在从系统中找出各种BUG。

            (5) 接口测试,程序往往在接口的地方很容易发生错误,要在此模块测试勿掉以轻心。

            (6) 代码重用测试,在开发过程中有些模块功能几乎相同,程序员在重用代码时可能忘记在原有代码上修改或修改不全面,而造成的错误。

            (7) 突发事件测试,服务器上可能发生意外情况的测试。

            (8) 外界环境测试,有些系统在开发时依赖于另外一个系统,当另外一个系统发生错误时, 这个系统所受到的影响的情况。

            (9) 在程序员刚修复Bug之后的地方,再找一找,往往程序员只修复报告出来的缺陷而不去考虑别的功能在修改时可能会重新造成错误。

            (10) 认真做好测试记录在做完一天的测试记录之后,第二天再根据第一天的测试记录重复测试你会发现有未修正的错误。

            (11) 文字测试,如果在系统中有用词不当的地方,我想这是不应该的。

            (12) 系统兼容测试,例如有些程序在IE6能运行正常,到IE5下不能运行。有些程序在WIN2000下能运行,而到WIN98却不能运行。像一些很特别的用户去使用系统,你很有可能发现BUG。

            (13) 用户的易用性测试,往往用户的需求是不断的变化的,而其中的一部份变化的原因,是有用户操作上不方便引起的。

            软件测试是软件开发中的重中之重,没有一点可以马虎的,在项目管理过程,强调的是每个过程的每一个环节都要进行测试,保证系统在每个阶段可以控制。因为软件测试中考虑的问题基本上是项目管理中考虑的问题。 工作中真的需要多总结,多剖析,对于毛病:“有则改之、无则加冕”。

            软件开发是一件很辛苦的事,只有在工作中多总结,才能找到符合自己的方式方法,才能在工作中事半功倍。

            原始链接:http://blog.51testing.com/?33734/action_viewspace_itemid_628.html
         

      Open Toolbar