发布新日志

  • LR结果分析——TPS和吞吐率(转载)

    2009-09-16 11:08:41

    针对吞吐率和TPS的关系,这个在结果分析中如何使用,就个人经验和朋友讨论后,提出如下建议指导,欢迎同僚指正。

      TPS:transaction per second 服务器每秒处理的事务数。

      吞吐率:测试过程中每秒从服务器返回的字节数。

      从定义上来看,如果TPS很小,但是吞吐率比较大,说明服务器的返回的页面文件(字节数)是比较大的,此时根据页面细分图,如果存在页面问题,考虑页面压缩。

      还应根据A1---A3,N1---N3实际考虑。

      如果A1或者A3比较大,说明webserver处理可能存在问题,如果A2比较大,则说明DBserver处理存在问题,建议sql优化。

      当增大系统的压力(或增加并发用户数)时,吞吐率和TPS的变化曲线呈大体一致,则系统基本稳定。

      若压力增大时,吞吐率的曲线增加到一定程度后出现变化缓慢,甚至平坦,同时TPS也趋于平坦,查看系统资源使用,如果资源使用率比较低,说明服务器硬件资源不存在问题,查看网络流量,估计网络带宽存在问题。

      同理若点击率/TPS曲线出现变化缓慢或者平坦, 点击率(用户每秒发出的请求数)如果在压力增加时,趋于平坦,很可能是服务器响应时间增加,观察服务器资源使用情况,确定是否是服务器问题。

      TPS是TransactionsPerSecond的缩写,也就是事务数/秒。它是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数,最终利用这些信息来估计得分。客户机使用加权协函数平均方法来计算客户机的得分,测试软件就是利用客户机的这些信息使用加权协函数平均方法来计算服务器端的整体TPS得分。

      一般的,评价系统性能均以每秒钟完成的技术交易的数量来衡量。 系统整体处理能力取决于处理能力最低模块的TPS 值。依据经验,应用系统的处理能力一般要求在10-100左右。不同应用系统的TPS有着十分大的差别,一般需要通过性能测试进行准确估算。

  • 转载:实例讲解asp vbscript 读写xml文件

    2008-07-02 16:25:05

    本文是一篇实例讲解的文章。作为一个普通的程序员,我深知,一个优秀的例程,对于正在学习编程的人是多么的有帮助。本文中使用的例程,是一个联系信息管理程序,我也是写来以方便自己和朋友们互相联系用的。但麻雀虽小,五脏俱全,相信对正在学习ASP+XML编程的朋友们,还是具备一定的参考价值的。

    读者可以通过此实例,了解在ASP(Active Server Page)中如何操纵XML文件,并进行数据的各种处理,包括XML节点的建立、修改、删除和保存等等。文中涉及到的技术包括ASP,VBscrīpt,DOM,XML和XSL等。

    本文未对使用到的技术进行深入的理论介绍,因此,读者需要具备一定的相关知识,尤其是对ASP、XML和DOM应该有一定的了解。通读本文,并参考源代码,相信读者一定可以熟练地掌握XML编程。
      一、程序说明

    例程基于B/S结构,使用XML文件存储联系信息,然后通过一个VBscrīpt写的Class,使用DOM,对XML文件中的联系信息进行各种操作。

    例程提供的代码采用了统一的命名规范,主要包括:用三个字母的缩写说明变量类型,如数字类型——int,字符串类型——str,对象——obj,等等,虽然在ASP/VBscrīpt中,不区分数据类型,但使用明显的数据类型说明,对程序的编写和维护还是很有意义的;使用有意义的变量名称,如XMLDocument对象,定义为objXmlDoc,等等,同样,这样做的也是为了更好地编写和维护程序。

    此程序可以分为后台数据处理和前台界面表现两部分。

    程序后台,使用VBscrīpt编写了一个Class,这是在VBscrīpt5.0版中提供的新特性。虽然这里Class的概念和真正的面向对象相去甚远,但是,在ASP中合理地使用Class,还是可以在一定程度上提高程序的运行效率和可维护性。

    前台表现,使用XSL对XML文件中的数据进行了格式化,然后以HTML的形式输出到客户端,充分体现了XML技术带来的灵活性与可定制性。格式化的过程放在了服务器端,使用ASP程序完成,这样,客户端得到的是经过格式化之后的HTML信息,避免了兼容性问题的出现。

    当然,程序对于具体的操作细节未作非常严格的检验,比如联系信息必填项的检查,但是,对于在ASP中使用DOM操作XML的有关部分,程序提供了完整的示例代码。

      二、XML文件说明(persons.xml)

    例程中使用到的XML文件结构十分简单,并且没有定义相关的Schema或者DTD,因为,对于此程序这是不必要的。当然,如果读者愿意自己定义一个的话,也不会对程序的运行产生影响。

    程序的数据结构定义如下,Persons集合,它包含多个Person对象,每一个Person对象包括姓名Name、英文名Nick、手机Mobile、电话Tel、电子邮件Email、腾讯QQ和所在公司Company的属性。将以上定义对应到XML文件即,Persons为根节点,Person为Persons的子节点,Name、Nick、Mobile、Tel、Email、QQ和Company为Person的子节点。

    这样,我们得到的XML文件内容如下:
    <?xml version="1.0" encoding="gb2312"?>
    <Persons>
    <Person>
        <Name>小东</Name>
    <Nick>gwd</Nick>
    <Mobile>139XXXXXXXX</Mobile>
    <Tel>XXXXXXXX</Tel>
    <Email>gwd@chinaren.com</Email>
    <QQ>7066015</QQ>
    <Company>XXX</Company>
    <Person>
    </Person>
    读者需要注意<?xml version="1.0" encoding="gb2312"?>这一行,XML默认不支持中文,通过设置encoding属性,才可以使XML正确地显示中文。读者可以在IE5.0及以上版本的浏览器中访问此文件,它会以 树型结构把数据显示出来。
    三、格式转换XSL文件说明(Persons.xsl)

    例程中使用XSL对XMl数据进行格式化,并以HTML的形式返回到客户端。这个过程也可以放在客户端进行,但考虑到兼容性的问题,例程中采用了在服务器端通过ASP操纵DOM进行格式化的方法。

    XSL文件的内容如下,

    <?xml version="1.0" encoding="gb2312"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/Persons">

    <table width="600" border="0" align="center">
     <tr>
      <td align="right"><a href="javascrīpt:add();" title="添加新联系人">添加新联系人</a>  </td>
     </tr>
    </table>

    <table align="center" width="680" cellspacing="1" cellpadding="2" border="0" bgcolor="#666600">
     <tr class="title" bgcolor="#E5E5E5">
      <td width="25"><xsl:text disable-output-escaping="yes">&</xsl:text>nbsp;</td>
      <td>姓名</td>
      <td>英文名</td>
      <td>手机</td>
      <td>电话</td>
      <td>Email</td>
      <td>QQ</td>
      <td>所在公司</td>
     </tr>
     <xsl:for-each select="Person">
     <TR BGCOLOR="#FFFFFF">
      <TD ALIGN="right"><xsl:value-of select="position()"/></TD>
      <TD STYLE="color:#990000"><A><xsl:attribute name="HREF">javascrīpt:edit('<xsl:value-of select="position()"/>');</xsl:attribute><xsl:attribute name="title">修改信息  </xsl:attribute><xsl:value-of select="Name"/></A></TD>
      <TD><xsl:value-of select="Nick"/></TD>
      <TD><xsl:value-of select="Mobile"/></TD>
      <TD><xsl:value-of select="Tel"/></TD>
      <TD><A><xsl:attribute name="HREF">mailto:<xsl:value-of select="Email"/></xsl:attribute><xsl:value-of select="Email"/></A></TD>
      <TD><xsl:value-of select="QQ"/></TD>
      <TD><xsl:value-of select="Company"/></TD>
     </TR>
     </xsl:for-each>
    </table>
    </xsl:template>
    </xsl:stylesheet>

    在服务器端的转换使用一个函数来完成,格式化成功,返回HTML字符串,格式化失败,打印出错误信息,如下,


    '*******************************************
    ' 说明:使用XSL文件格式化XML文件。
    ' 作者:gwd 2002-11-05
    ' 参数:strXmlFile -- Xml文件,路径+文件名
    ' strXslFile -- Xsl文件,路径+文件名
    ' 返回:成功 -- 格式化后的HTML字符串
    ' 失败 -- 自定义的错误信息
    '*******************************************
    Function FormatXml(strXmlFile, strXslFile)
     Dim objXml, objXsl

     strXmlFile = Server.MapPath(strXmlFile)
     strXslFile = Server.MapPath(strXslFile)

     Set ōbjXml = Server.CreateObject("MSXML2.DOMDocument")
     Set ōbjXsl = Server.CreateObject("MSXML2.DOMDocument")

     objXML.Async = False
     If objXml.Load(strXmlFile) Then
      objXsl.Async = False
      objXsl.ValidateonParse = False
      If objXsl.Load(strXslFile) Then
       On Error Resume Next ' 捕获transformNode方法的错误
       FormatXml = objXml.transformNode(objXsl)
       If objXsl.parseError.errorCode <> 0 Then
        Response.Write "<br><hr>"
        Response.Write "Error Code: " & objXsl.parseError.errorCode
        Response.Write "<br>Error Reason: " & objXsl.parseError.reason
        Response.Write "<br>Error Line: " & objXsl.parseError.line
        FormatXml = "<span class=""alert"">格式化XML文件错误!</span>"
       End If
      Else
       Response.Write "<br><hr>"
       Response.Write "Error Code: " & objXsl.parseError.errorCode
       Response.Write "<br>Error Reason: " & objXsl.parseError.reason
       Response.Write "<br>Error Line: " & objXsl.parseError.line
       FormatXml = "<span class=""alert"">装载XSL文件错误!</span>"
      End If
     Else
      Response.Write "<br><hr>"
      Response.Write "Error Code: " & objXml.parseError.errorCode
      Response.Write "<br>Error Reason: " & objXml.parseError.reason
      Response.Write "<br>Error Line: " & objXml.parseError.line
      FormatXml = "<span class=""alert"">装载XML文件错误!</span>"
     End If

     Set ōbjXsl = Nothing
     Set ōbjXml = Nothing
    End Function
    四、操作Xml数据的Cls_Person类说明(clsPerson.asp)

    Cls_Person类用来完成与联系人信息相关的各种操作,包括添加、修改和删除等等,它使用VBscrīpt编写。Cls_Person包括Id、Name、Nick、Mobile、Tel、Email、QQ和Company属性,对应于XML文件中的Person节点。Cls_Person包括GetInfoFromXml、AddToXml、EditToXml和DeleteFormXml四个主要方法,分别完成获取信息,添加信息,修改信息和删除信息四个功能。

    Cls_Person的具体实现如下,

    '***************************************************
    ' 说明:Person类
    ' 作者:gwd 2002-11-06
    ' 引用:pub/constpub.asp
    '***************************************************

    Class Cls_Person

    Private m_intId ' Id,对应Person节点在Persons集合中的位置
    Private m_strName ' 姓名
    Private m_strNick ' 英文名
    Private m_strMobile ' 手机
    Private m_strTel ' 电话
    Private m_strEmail ' 电子邮件
    Private m_strQQ ' QQ号
    Private m_strCompany ' 所在公司
    Private m_strError ' 出错信息

    ' 类初始化
    Private Sub Class_Initialize()
     m_strError = ""
     m_intId = -1
    End Sub

    ' 类释放
    Private Sub Class_Terminate()
     m_strError = ""
    End Sub

    '-----读写各个属性---------------------------

    Public Property Get Id
     Id = m_intId
    End Property

    Public Property Let Id(intId)
     m_intId = intId
    End Property

    Public Property Get Name
    Name = m_strName
    End Property

    Public Property Let Name(strName)
     m_strName = strName
    End Property

    Public Property Get Nick
     Nick = m_strNick
    End Property

    Public Property Let Nick(strNick)
     m_strNick = strNick
    End Property

    Public Property Get Mobile
     Mobile = m_strMobile
    End Property

    Public Property Let Mobile(strMobile)
     m_strMobile = strMobile
    End Property

    Public Property Get Tel
     Tel = m_strTel
    End Property

    Public Property Let Tel(strTel)
     m_strTel = strTel
    End Property

    Public Property Get Email
     Email = m_strEmail
    End Property

    Public Property Let Email(strEmail)
     m_strEmail = strEmail
    End Property

    Public Property Get QQ
     QQ = m_strQQ
    End Property

    Public Property Let QQ(strQQ)
     m_strQQ = strQQ
    End Property

    Public Property Get Company
     Company = m_strCompany
    End Property

    Public Property Let Company(strCompany)
     m_strCompany = strCompany
    End Property

    '-----------------------------------------------

    ' 获取错误信息
    Public Function GetLastError()
     GetLastError = m_strError
    End Function

    ' 私有方法,添加错误信息
    Private Sub AddErr(strEcho)
     m_strError = m_strError + "<Div CLASS=""alert"">" & strEcho & "</Div>"
    End Sub

    ' 清除错误信息
    Public Function ClearError()
     m_strError = ""
    End Function

    ' 从Xml中读取指定节点的数据,并填充各个属性
    ' 需要首先设置Id
    Public Function GetInfoFromXml(objXmlDoc)
     Dim objNodeList
     Dim I

     ClearError

     If objXmlDoc Is Nothing Then
      GetInfoFromXml = False
      AddErr "Dom对象为空值"
      Exit Function
     End If

     If CStr(m_intId) = "-1" Then
      GetInfoFromXml = False
      AddErr "未正确设置联系人对象的ID属性"
      Exit Function
     Else
      I = m_intId - 1 ' 要读取得节点位置
     End If

     ' 选择并读取节点信息,赋予各个属性
     Set ōbjNodeList = objXmlDoc.getElementsByTagName("Person")
     If objNodeList.length - m_intId >= 0 Then
      On Error Resume Next
      m_strName = objNodeList(I).selectSingleNode("Name").Text
      m_strNick = objNodeList(I).selectSingleNode("Nick").Text
      m_strMobile = objNodeList(I).selectSingleNode("Mobile").Text
      m_strTel = objNodeList(I).selectSingleNode("Tel").Text
      m_strEmail = objNodeList(I).selectSingleNode("Email").Text
      m_strQQ = objNodeList(I).selectSingleNode("QQ").Text
      m_strCompany = objNodeList(I).selectSingleNode("Company").Text
      GetInfoFromXml = True
     Else
      GetInfoFromXml = False
      AddErr "获取联系信息发生错误"
      Set ōbjNodeList = Nothing
      Exit Function
     End If
     Set ōbjNodeList = Nothing
    End Function

    ' 添加信息到XML文件中
    ' 需要首先设置好要填充的属性
    Public Function AddToXml(objXmlDoc)
     Dim objPerson, objNode

     ClearError

     If objXmlDoc Is Nothing Then
      AddToXml = False
      AddErr "Dom对象为空值"
      Exit Function
     End If

     ' 创建Person节点
     Set ōbjPerson = objXmlDoc.createElement("Person")
     objXmlDoc.documentElement.appendChild objPerson

     ' 创建各个子节点
     '-----------------------------------------------------
     Set ōbjNode = objXmlDoc.createElement("Name")
     objNode.Text = m_strName
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Nick")
     objNode.Text = m_strNick
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Mobile")
     objNode.Text = m_strMobile
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Tel")
     objNode.Text = m_strTel
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Email")
     objNode.Text = m_strEmail
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("QQ")
     objNode.Text = m_strQQ
     objPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Company")
     objNode.Text = m_strCompany
     objPerson.appendChild objNode
     '-----------------------------------------------------

     Set ōbjNode = Nothing
     Set ōbjPerson = Nothing

      On Error Resume Next
     objXmlDoc.save Server.MapPath(C_XMLFILE) '保存XML文件
     If Err.Number = 0 Then
      AddToXml = True
     Else
      AddToXml = False
      AddErr Err.Descrīption
     End If
    End Function

    ' 从XML文件中删除数据
    ' 需要首先设置Id
    Public Function DeleteFromXml(objXmlDoc)
     Dim objNodeList, objNode

     ClearError

     If objXmlDoc Is Nothing Then
      DeleteFromXml = False
      AddErr "Dom对象为空值"
      Exit Function
     End If

     If CStr(m_intId) = "-1" Then
      DeleteFromXml = False
      AddErr "未正确设置联系人对象的ID属性"
      Exit Function
     End If

     Set ōbjNodeList = objXmlDoc.getElementsByTagName("Person")
     If objNodeList.length - m_intId < 0 Then
      DeleteFromXml = False
      AddErr "未找到相应的联系人"
      Set ōbjNodeList = Nothing
      Exit Function
     End If

     On Error Resume Next
     Set ōbjNode = objXmlDoc.documentElement.removeChild(objNodeList(intId-1))
     If objNode Is Nothing Then
      DeleteFromXml = False
      AddErr "删除联系人失败"
      Set ōbjNodeList = Nothing
      Exit Function
     Else
      objXmlDoc.save Server.MapPath(C_XMLFILE)
     End If
     Set ōbjNode = Nothing
     Set ōbjNodeList = Nothing

     If Err.Number = 0 Then
      DeleteFromXml = True
     Else
      DeleteFromXml = False
      AddErr Err.Descrīption
     End If
    End Function

    ' 修改XML文件中的数据
    ' 需要首先设置好Id
    Public Function EditToXml(objXmlDoc)
     Dim objPersonList, objOldPerson, objNewPerson, objNode

     ClearError

     If objXmlDoc Is Nothing Then
      EditToXml = False
      AddErr "Dom对象为空值"
      Exit Function
     End If

     If CStr(m_intId) = "-1" Then
      EditToXml = False
      AddErr "未正确设置联系人对象的ID属性"
      Exit Function
     End If

     Set ōbjPersonList = objXmlDoc.getElementsByTagName("Person")
     If objPersonList.length - m_intId < 0 Then
      DeleteFromXml = False
      AddErr "未找到相应的联系人"
      Set ōbjPersonList = Nothing
      Exit Function
     End If

     Set ōbjOldPerson = objPersonList(m_intId-1) ' 要修改的旧节点

     Set ōbjNewPerson = objXmlDoc.createElement("Person") ' 用来替换旧节点的新节点
     Set ōbjNode = objXmlDoc.createElement("Name")
     objNode.Text = m_strName
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Nick")
     objNode.Text = m_strNick
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Mobile")
     objNode.Text = m_strMobile
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Tel")
     objNode.Text = m_strTel
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Email")
     objNode.Text = m_strEmail
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("QQ")
     objNode.Text = m_strQQ
     objNewPerson.appendChild objNode

     Set ōbjNode = objXmlDoc.createElement("Company")
     objNode.Text = m_strCompany
     objNewPerson.appendChild objNode

     On Error Resume Next
     ' 进行替换
     Set ōbjNode = objXmlDoc.documentElement.replaceChild(objNewPerson, objOldPerson)
     If objNode Is Nothing Then
     EditToXml = False
     AddErr "修改联系人失败"
     Set ōbjOldPerosn = Nothing
     Set ōbjNewPerson = Nothing
     Set ōbjPersonList = Nothing
     Exit Function
    Else
     objXmlDoc.save Server.MapPath(C_XMLFILE)
    End If

    Set ōbjOldPerson = Nothing
    Set ōbjNewPerson = Nothing
    Set ōbjPersonList = Nothing

    If Err.Number = 0 Then
     EditToXml = True
    Else
     EditToXml = False
     AddErr Err.Descrīption
    End If
    End Function

    End Class
    五、程序首页(default.asp)

    调用相应的包含文件和公共函数,格式化XML文件,并进行显示。可以看到,页面Title是可定制的,公共的头部和尾部都做成了相应的包含文件。C_TITLE、C_XMLFILE和C_XSLFILE为公共常量,在constpub.asp文件中定义,至于它们的意义,相信读者可以很容易地明白。这里调用了上面定义的FormatXml函数。


    <% Option Explicit
    '***********************************************
    ' 说明:通讯录
    ' 作者:gwd 2002-11-05
    '***********************************************
    %>

    <!--#include file="pub/funcxml.asp"-->
    <!--#include file="pub/constpub.asp"-->
    <HTML>
    <HEAD>
    <TITLE><% = C_TITLE %></TITLE>
    <META HTTP-EQUIV="content-type" CONTENT="text/html;charset=GB2312"/>
    <link rel="stylesheet" href="contact.css" type="text/css">
    </HEAD>
    <BODY>
    <!--#include file="pub/header.asp"-->
    <% = FormatXml(C_XMLFILE, C_XSLFILE) %>
    <br>
    <!--#include file="pub/footer.asp"-->
    </BODY>
    </HTML>

      六、添加、修改和删除XML中的信息

    我们知道,在Cls_Person中已经定义了相应的方法,因此,在各个文件中,只需要调用对应的方法即可。添加信息的文件为add.asp,修改信息的文件为edit.asp,删除信息的文件为delete.asp,我们仅以add.asp文件为例进行说明。其中的CheckStrInput和CheckStrOutput函数,用来格式化用户的输入和输出字符串。

    <% Option Explicit
    '***********************************************
    ' 说明:37080308通讯录
    ' 作者:gwd 2002-11-05
    '***********************************************
    %>

    <!--#include file="pub/funcxml.asp"-->
    <!--#include file="pub/constpub.asp"-->
    <!--#include file="pub/funcpub.asp"-->
    <!--#include file="pub/class/clsPerson.asp"-->

    <%
     Dim objXml, objPerson
     Dim strErr

     Set ōbjXml = Server.CreateObject("MSXML2.DOMDocument")
     Set ōbjPerson = New Cls_Person ' 生成Cls_Person对象
     If Request.Form("btnOk") <> "" Then
      If LoadXmlDoc(objXml, C_XMLFILE, False, strErr) Then ' 装载XML文件
       ' 给相应的属性赋值
       objPerson.Name = CheckStrInput(Request.Form("txtName"))
       objPerson.Nick = CheckStrInput(Request.Form("txtNick"))
       objPerson.Mobile = CheckStrInput(Request.Form("txtMobile"))
       objPerson.Tel = CheckStrInput(Request.Form("txtTel"))
       objPerson.Email = CheckStrInput(Request.Form("txtEmail"))
       objPerson.QQ = CheckStrInput(Request.Form("txtQQ"))
       objPerson.Company = CheckStrInput(Request.Form("txtCompany"))
       If Not objPerson.AddToXml(objXml) Then ' 调用Cls_Person类的AddToXml方法,添加数据
        AddErr strErr, objPerson.GetLastError
       Else
        AddErr strErr, "添加成功"
        Response.Write ""
       End If
      End If
     End If
     Set ōbjXml = Nothing
    %>
    <HTML>
    <HEAD>
    <TITLE><% = C_TITLE %></TITLE>
    <META HTTP-EQUIV="content-type" CONTENT="text/html;charset=GB2312"/>
    <link rel="stylesheet" href="contact.css" type="text/css">

    </HEAD>
    <BODY>
    <% = strErr %>
    <div class="title">添加联系信息</div>
    <form name="form1" method="post" action="add.asp" >
     <table align="center" width="100%" cellspacing="1" cellpadding="2" border="0" bgcolor="#666600">
      <tr bgcolor="#ffffff">
       <td width="25%" bgcolor="#e5e5e5" align="right"><b>姓名:</b></td>
       <td width="75%"><input type="text" name="txtName" size="25" class="input" value="<%=CheckStrOutput(objPerson.Name)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>英文名:</b></td>
       <td><input type="text" name="txtNick" size="25" class="input" value="<%=CheckStrOutput(objPerson.Nick)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>手机:</b></td>
       <td><input type="text" name="txtMobile" size="25" class="input" value="<%=CheckStrOutput(objPerson.Mobile)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>电话:</b></td>
       <td><input type="text" name="txtTel" size="25" class="input" value="<%=CheckStrOutput(objPerson.Tel)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>Email:</b></td>
       <td><input type="text" name="txtEmail" size="25" class="input" value="<%=CheckStrOutput(objPerson.Email)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>QQ:</b></td>
       <td><input type="text" name="txtQQ" size="25" class="input" value="<%=CheckStrOutput(objPerson.QQ)%>"></td>
      </tr>
      <tr bgcolor="#ffffff">
       <td bgcolor="#e5e5e5" align="right"><b>所在公司:</b></td>
       <td><input type="text" name="txtCompany" size="25" class="input" value="<%=CheckStrOutput(objPerson.Company)%>"></td>
      </tr>
     </table>
     <br>
     <div align="center">
     <input type="submit" name="btnOk" value="提交">
     <input type="button" name="btnClose" value="关闭" >
     </div>
    </form>
    </BODY>
    </HTML>
    <%
    Set ōbjPerson = Nothing
    %>

      七、总结

    到此,我们的联系信息管理程序就大功告成了。怎么样,感觉如何,应该来说还是相当简单的吧。当然了,这个例程还有许多可以改进的地方,我这里也只不过是抛砖引玉,希望读者在掌握了XML编程之后,自行修改完善吧。

  • Methods and properties of Microsoft.XMLDOM)

    2008-06-16 14:59:13

    Methods and properties of Microsoft.XMLDOM

    Document
    Properties


    *async
    boolean: specifies whether asynchronous download of the document is permitted.
    *doctype
    *documentElement
    *implementation
    *ondataavailable [ie]
    *onreadystateChange [ie]
    *ontransformnode [ie]
    *parseError [ie]
    *preserveWhiteSpace [ie]
    *readyState
    *resolveExternals [ie]
    *setProperty ) [ie]
    The following (2nd level) properties can be set:
    *AllowDocumentFunction
    * ForcedResync
    *MaxXMLSize
    *NewParser
    *SelectionLanguage
    *SelectionNamespace
    *ServerHTTPRequest
    for example:
    xmlDoc.setProperty("SelectionLanguage", "XPath");
    selection = xmlDoc.selectNodes("//Customer");

    *url [ie]
    *validateOnParse [ie]

    Methods
    *abort [ie]
    *createAttribute
    *createCDATASection (data )
    *createComment (comment)
    *createDocumentFragment (data )
    *createElement (tagName)
    *createEntityReference (name )
    *createNode [ie] (type, name, nameSpaceURI)
    *createProcessingInstruction (target, data)
    *createTextNode (data)
    *getElementsByTagName (tagName)
    *load [ie] (url)
    *loadXML [ie] (xml_string)
    *nodeFromID [ie] (id_string)
    *save [ie] (objTarget)

    Node
    Properties
    *attributes
    *returns an array of objects. An object in this array has the name and value property.
    *baseName [ie]
    *childNodes
    *dataType [ie]
    *definition [ie]
    *firstChild
    *lastChild
    *namespaceURI [ie]
    *nodeName
    *nodeType
    Can be
    1: Element
    2: Attribute
    3: Text
    4: CDATA Section
    5: Entity Reference
    6: Entity
    7: Processing Instruction
    8: Comment
    9: Document
    10: Document Type
    11: Document Fragment
    12: Notation
    *nodeTypedValue [ie]
    *nodeTypeString [ie]
    *nodeValue
    This property defines the content of a div. The following example uses nodeValue to write the seconds since the page was loaded:
    <scrīpt type='text/javascrīpt'>
     var secs=0;

     setTimeout('write_seconds()', 1000); // 1 second

     function write_seconds() {
     var span;
     if (document.getElementById) {
     span = document.getElementById('time');
     if (span && span.firstChild && span.firstChild.nodeType == 3) {
     span.firstChild.nodeValue = secs;
     secs++;
     }
     setTimeout('write_seconds()', 1000); // 1 second
     }
     }

    </scrīpt>

    <span id='time'>0</span>

    *ownerDocument
    *parentNode
    *parsed [ie]
    *prefix
    *previousSibling [ie]
    *specified [ie]
    *text [ie]
    *xml [ie]

    Methods
    *appendChild (tagName)
    *cloneNode (deep )
    If deep is true, the children and children's children are cloned as well.
    *hasChildNodes ()
    *insertBefore (newChild, refChild)
    *removeChild (child)
    *replaceChild (newChild, oldChild)
    *selectNodes [ie] (patternString)
    Returns a list of nodes.
    For example:
    xmlDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
    xmlDoc.setProperty("SelectionLanguage", "XPath");
    objNodeList = xmlDoc.documentElement.selectNodes("//xsl:template");
    *selectSingleNode [ie] (patternString)
    *transformNode [ie] (stylesheet)
    *transformNodeToObject [ie] (stylesheet, outputObject)

    async 属性

    作 用 async 属性表示是否允许异步的下载。
    基本语法 boolValue = XMLDocument.async;XMLDocument.async = boolValue;
    说 明 布尔值是可擦写的(read/write),如果准许异步下载,值为True;反之则为False。
    范 例

    xmlDoc.async = "false";
    alert(xmlDoc.async);

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

    attribute 属性

    作 用 传回目前节点的属性列表。
    基本语法 ōbjAttributeList = xmlNode.attributes;
    说 明 传回一个物件。如果此节点不能包含属性,则传回空值。
    范 例

    objAttList = xmlDoc.documentElement.attributes;
    alert(objAttList);

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

    childNodes 属性

    作 用 传回一个节点清单,包含该节点所有可用的子节点。
    基本语法 ōbjNodeList=node.childNodes;
    说 明 传回一个物件。假如这节点没有子节点,传回null。
    范 例

    objNodeList = xmlDoc.childNodes;
    alert(objNodeList);

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

    doctype 属性

    作 用 传回文件型态节点,包含目前文件的DTD。这节点是一般的文件型态宣告,例如,节点,名为EMAIL 的节点物件会被传回。
    基本语法 ōbjDocType=xmlDocument.doctype;
    说 明 传回一个对象,这个属性是只读的。假如这文件不包含DTD,会传回null。
    范 例

    objDocType = xmlDoc.doctype;
    alert(objDocType.nodeName);

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

    documentElement 属性

    作 用 确认XML 文件的根(Root)节点。
    基本语法 ōbjDoc=xmlDocument.documentElement;
    说 明 回一个在单一根文件元素中包含数据的对象。此属性可读/写,如果文件中不包含根节点,将传回null。
    范 例

    objDocRoot = xmlDoc.documentElement;
    alert(objDocRoot);

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

    firstChild 属性

    作 用 确认在目前节点中的第一个子元素。
    基本语法 objFirstChild = xmlDocNode.firstChild ;
    说 明 此属性只读且会传回一对象,如果节点中没有包含第一个子元素,将传回null。
    范 例

    objFirstChild = xmlDoc.documentElement.firstChild;
    alert(objFirstChild);

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

    implementation 属性

    作 用 DOM 应用程序能使用其它实作中的对象。implementation 属性确认目前XML 文件的DOMimplementation 对象。
    基本语法 objImplementation = xmlDocument.implementation;
    说 明 此属性只读且传回一个对象。
    范 例

    objImp = xmlDoc.implementation;
    alert(objImp);

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

    lastChild 属性

    作 用 确认目前节点中最后的子元素。
    基本语法 objLastChild = xmlDocNode.lastChild;
    说 明 此属性只读且传回一个对象。如果节点中没有包含最后子元素,将传回null。
    范 例

    objLastChild = xmlDoc.documentElement.lastChild;
    alert(objLastChild);

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

    nextSibling 属性

    作 用 在目前文件节点的子节点列表中传回下一个兄弟节点。
    基本语法 objNextSibling = xmlDocNode.nextSibling;
    说 明 此属性是只读且传回一个对象。如果节点中没有包含其它的相关节点,会传回null。
    范 例

    objSibling = xmlDoc.documentElement.childNodes.item(1) .nextSibling;
    alert(objSibling);

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

    nodeName 属性

    作 用 传回代表目前节点名称的字符串。
    基本语法 strNodeName = xmlDocNode.nodeName ;
    说 明 传回一个字符串。这个属性是只读的,传回元素名称、属性或实体参照。
    范 例

    strNodeName = xmlDoc.documentElement.nodeName;
    alert(strNodeName);

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

    nodeType 属性

    作 用 辨识节点的DOM 型态。
    基本语法 numNodeType = xmlDocNode.nodeType ;
    说 明 此属性只读且传回一个数值。

    有效的数值符合以下的型别:
    1-ELEMENT
    2-ATTRIBUTE
    3-TEXT
    4-CDATA
    5-ENTITY REFERENCE
    6-ENTITY
    7-PI (processing instruction)
    8-COMMENT
    9-DOCUMENT
    10-DOCUMENT TYPE
    11-DOCUMENT FRAGMENT
    12-NOTATION
     
    范 例

    numNodeType = xmlDoc.documentElement.nodeType;
    alert(numNodeType);

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

    nodeValue 属性

    作 用 传回指定节点相关的文字。这并非一个元素中数据的值,而是与一个节点相关且未解析的文字,就像一个属性或者一个处理指令。
    基本语法 varNodeValue = xmlDocNode.nodeValue;
    说 明 传回的文字代表以节点的nodeType 属性为主的型态值。(请参考附录中的nodeType 属性。)因为节点型态可能是几种数据型态中的一种,传回值也因此有差异。传回null 的节点型态有:DOCUMENT、ELEMENT、DOCUMENT TYPE、DOCUMENT FRAGMENT、ENTITY、ENTITY REFERENCE,和NOTATION。此属性可擦写。
    范 例

    varNodeValue = xmlDoc.documentElement.nodeValue;
    alert(varNodeValue);

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

    ondataavailable 属性

    作 用 指定一个事件来处理ondataavailable 事件。
    基本语法 xmlDocNode.ondataavailable = value;
    说 明 此属性是唯写,允许文件作者一旦数据为可用,即可尽快的使用数据来运作。
    范 例

    xmlDoc.ondataavailable = alert("Data is now available.");

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

    onreadystatechange 属性

    作 用 指定一个事件来处理onreadystatechange 事件。这个事件能辨识readyState 属性的改变。
    基本语法 xmlDocNode.onreadystatechange = value;
    说 明 此属性是唯写的,允许文件作者指定当readyState 属性改变时呼叫事件。
    范 例

    xmlDoc.onreadystatechange = alert("The readyState property has changed.");

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

    ownerDocument 属性

    作 用 传回文件的根节点,包含目前节点。
    基本语法 objOwnerDoc = xmlDocument.ownerDocument;
    说 明 此属性是只读的,传回一个包含文件根节点的对象,包含特定的节点。
    范 例

    objOwnerDoc = xmlDoc.childNodes.item(2).ownerDocument;
    alert(objOwnerDoc);

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

    parentNode 属性

    作 用 传回目前节点的父节点。只能应用在有父节点的节点中。
    基本语法 objParentNode = xmlDocumentNode.parentNode;
    说 明 此属性是只读的,传回包含指定节点的父节点对象。如果此节点不存在于文件树中,将传回null。
    范 例

    objParentNode = xmlDoc.childNodes.item(1).parentNode;
    alert(objParentNode);

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

    parseError 属性

    作 用 传回一个DOM 解析错误对象,此对象描述最后解析错误的讯息。
    基本语法 objParseErr = xmlDocument.parseError;
    说 明 此属性是只读的。如果没有错误发生,将传回0。
    范 例

    objParseErr = xmlDoc.parseError;
    alert(objParseErr);

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

    previousSibling 属性

    作 用 传回目前节点之前的兄弟节点。
    基本语法 objPrevSibling = xmlDocument.previousSibling;
    说 明 传回一个对象,这个属性是只读的。若该节点没有包含前面的兄弟节点,会传回null。
    范 例

    objPrevSibling = xmlDoc.documentElement.childNodes.item(3).previousSibling;
    alert(objPrevSibling);

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

    readyState 属性

    作 用 传回XML 文件资料的目前状况。
    基本语法 intState = xmlDocument.readyState;
    说 明 这个属性是只读的,传回值有以下的可能:
    0-UNINITIALIZED:XML 对象被产生,但没有任何文件被加载。
    1-LOADING:加载程序进行中,但文件尚未开始解析。
    2-LOADED:部分的文件已经加载且进行解析,但对象模型尚未生效。
    3-INTERACTIVE:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。
    4-COMPLETED:文件已完全加载,代表加载成功。
    范 例

    alert("The readyState property is " + xmlDoc.readyState);

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

    url 属性

    作 用 传回最近一次加载XML 文件的URL。
    基本语法 strDocUrl = xmlDocument.url;
    说 明 这个属性是只读的,传回最近一次加载成功文件的URL,若文件仅存在主存储器中(表示该文件并非由外部档案加载),则传回null。
    范 例

    alert(xmlDoc.url);

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

    validateOnParse 属性

    作 用 告诉解析器文件是否有效。
    基本语法 boolValidate = xmlDocument.validateOnParse; xmlDocument.validateOnParse = boolValidate;
    说 明 此属性是可擦写的。如果传回值为true,表示文件被解析时被确认是有效的。如果传回false,表示文件是无效的,并被认为只是标准格式的(well-formed)文件。
    范 例

    xmlDoc.validateOnParse = true;
    alert(xmlDoc.validateOnParse);

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

    xml 属性

    作 用 传回指定节点的XML 描述和所有的子节点。
    基本语法 xmlValue = xmlDocumentNode.xml;
    说 明 此属性是只读的。
    范 例

    xmlValue = xmlDoc.documentElement.xml;
    alert(xmlValue);
  • [收藏]使用QC和QTP构建自动测试体系

    2008-04-25 11:53:08

     

    如果要搭建自动测试体系,需要完成以下几个工作:
    1、规范测试脚本的配置管理
    2、制定测试脚本的编码规范,QTP脚本还要制定对象仓库和VBS的规范
    3、创建自动测试实验室,通过控制台指挥各个测试机分布式执行脚本,并集中收集测试结果
    4、健全测试脚本的维护机制,脚本责任到人


    下面先讲一下第一点:脚本的配置管理,因为QTP本身提供了和QC集成的功能,使用QC作为配置管理工具非常合适,而且在组建测试实验室的时候,QC也有很强的优势,后面会讲到。


    只要利用QTP的QC连接功能,就可以直接把Test、对象仓库等资源保存在QC服务器上,这里我主要讲一下QC的目录分类管理。在根目录下可以建一个common目录,里面主要存放vbs脚本文件,这些脚本文件提供了各个Test需要调用的公共方法,比如和数据库交互。


    然后在根目录按照功能模块的名称建立文件夹,下面保存每个功能模块的所有Test和资源。建议每个功能模块目录下面建三个大目录,分别是framework、主要流程、功能点。


    framework里面保存对象仓库文件和此功能Test私有的vbs文件;“主要流程”和“功能点”保存测试脚本也就是Test。“流程”里的每个Test,都覆盖了一个完整的、正常的、独立的流程,Test的名称就是流程的名称,比如“注册用户”、“发布新帖子”。注意不要一个Test包含多个流程。“功能点”中每个Test只覆盖一个功能点,比如“检查用户是否已存在”、“密码长度不能小于6字节”。总之,每个Test要做到独立,请参考这篇文章:
    《测试脚本的独立性》


    我们只要执行了“流程”的Test,就能保证基本的功能OK。但是这还远远不够,还有一些重要的功能点需要覆盖。其实我们的测试脚本并不需要覆盖100%的功能点,根据28原则和我们的历史经验,大部分的bug都是集中在那一小部分(大约20%)主要的功能点中。我们的脚本要以这些功能点为主。当然,以后在回归过程中,如果需要增加功能点的Test,就直接在这个目录下新建Test即可,这一点非常重要,通过对功能点Test的不断积累,就能让我们的自动测试越来越完善。而流程的Test一般改动不多。


    关于第二点测试脚本编码规范,本文不做详细介绍。大家需要注意的是,测试脚本就是我们的测试代码,是代码就需要编码规范。如果要实现一个团队的合作,必须有规范。关于对象仓库的规范,请参考这篇文章:
    《管理QTP测试脚本的对象仓库》


    构建测试实验室的工作是比较开心的,我们可以准备一批PC作为测试机,也可以购买配置较好的服务器,安装虚拟机,将虚拟机作为测试机。关于QC远程调用QTP的相关设置,请参考这篇文章:
    《QC远程调用QTP》


    通过以上的工作,技术问题基本解决了,我们还需要管理流程,来保证测试体系的健康。这里我只讲一点:测试脚本责任到人。比如A君负责几个模块的自动测试,那么他需要做什么呢?这里总结了几点:
    1、主要流程的脚本编写
    2、确定主要功能点的范围和组织团队成员编写脚本
    3、保证QC中的脚本始终可用
    4、如果需要增加功能点的Test,需要他来跟踪并保证脚本质量
    5、当脚本出现问题时负责解决问题


    负责人并不需要完成所有的脚本编写工作,他可以组织大家一起做,但是他需要保证脚本库的健康,最好也能保证脚本的编码规范。
  • LoadRunner压力测试实例{转载}

    2007-11-23 16:22:26

    LoadRunner压力测试实例

     摘要:本文通过实例讲解介绍了LoadRunner 工具的使用,介于公司的实际情况,文中主要是对工具的基本使用做了详细描述,高级运用方面除性能计数器与参数设置外其它均未涉及,待以后补充。目的是使公司人员根据该手册便可以独立运用Loadrunner进行压力测试

    主题词:Loadrunner 工具 压力测试

     1 LoadRunner 概要介绍 LoadRunner 是一种预测系统行为和性能的工业标准级负载测试工具。通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner 能够对整个企业架构进行测试。通过使用LoadRunner , 企业能最大限度地缩短测试时间, 优化性能和加速应用系统的发布周期。目前企业的网络应用环境都必须支持大量用户,网络体系架构中含各类应用环境且由不同供应商提供软件和硬件产品。难以预知的用户负载和愈来愈复杂的应用环境使公司时时担心会发生用户响应速度过慢, 系统崩溃等问题。这些都不可避免地导致公司收益的损失。Mercury Interactive 的 LoadRunner 能让企业保护自己的收入来源, 无需购置额外硬件而最大限度地利用现有的IT 资源, 并确保终端用户在应用系统的各个环节中对其测试应用的质量, 可靠性和可扩展性都有良好的评价。LoadRunner 是一种适用于各种体系架构的自动负载测试工具, 它能预测系统行为并优化系统性能。LoadRunner 的测试对象是整个企业的系统, 它通过模拟实际用户的操作行为和实行实时性能监测, 来帮助您更快的查找和发现问题。此外,LoadRunner 能支持广范的协议和技术, 为您的特殊环境提供特殊的解决方案。

     1.1 基本步骤使用LoadRunner 完成测试一般分为四个步骤: 1)Vvitrual User Generator 创建脚本 创建脚本,选择协议 录制脚本 编辑脚本 检查修改脚本是否有误 2)中央控制器(Controller)来调度虚拟用户 创建Scenario,选择脚本 设置机器虚拟用户数 设置Schedule  如果模拟多机测试,设置Ip Spoofer 3)运行脚本 分析scenario 4)分析测试结果 2 安装LoadRunner 中文版 LoadRunner 分为Windows 版本和Unix 版本。如果我们的所有测试环境基于Windows 平台, 那么我们只要安装Windows 版本即可。本章讲解的安装过程就是LoadRunner7.8中文的Windows 版本的安装。 2.1 系统要求目前部门的测试机和工作机器足可以满足LoadRunner7.8 的最低要求。不过要比较好的运行LoadRunner, 内存最好在512M 以上, 安装LoadRunner 的磁盘空间至少剩余500M。操作系统最好为Windows 2000。

    2.2 安装过程 LoadRunner7.8中文版安装基本分两个步骤:首先安装LoadRunner7.8英文原版,然后安装中文语言插件包 LoadRunner7.8英文原版存放位置:\\10.138.149.139\ test tools\LR7.8nt.rar将压缩文件拷贝解压到本机的安装,过程比较简单要开始安装LoadRunner,以Administrator 的身份登陆Windows2000 后,运行LoadRunner 安装目录下Setup.exe 即可进入安装程序。 1. 在“Registration Information” 界面中, 输入序列号( 不用改动, 就是n 个8) 2. 在安装类型界面中, 选择一种安装类型 下面简单的对这三种安装类型进行介绍 ●Standalone Installation 将要安装LoadRunner 在一台计算机上 ●Network Installation 把LoadRunner 安装在一个网络驱动器上, 这样任何能连接到这个网络驱动器的计算机都可以使用LoadRunner 的部分或者全部组件。 ●Network Installation and shortcuts 和Network Installation 类似,不同的只是这种类型将把自己的计算机配置成Workstation 来运行LoadRunner。如果选择了第二项, 我们还需要进行

    2.3 的安装来配置Workstation.。考虑到我们是自己学习研究学习, 选择第一种安装方法。 3. 在安装方式界面中, 需要选择一种安装方式。建议选择“ 自定义安装”, 这样所有的组件都会一次安装。下面简单的对各个安装方式进行介绍 ●Typical Installation 安装比较通用的组件, 包括Controller、Vuser、在线帮助和脚该选项适合于控制Vusers 的机器。 ●Load Generator 只安装运行Vusers 产生负载的组件。该选项适合于只产生负载, 而不控制Vusers 的机器。 ●MI Listener 安装MI Listener 组件, 用来透过防火墙来运行Vusers 并且监视性能。 ●Custom Installation 自定义安装, 我们将使用该选项, 安装全部的组件。 4. 在“License Information” 中输入License Key 后,Next, 继续 100个用户(无时间限制):AEAMAUIK-YAFEKEKJJKEEA-BCJGI 10000个用户(有时间限制):AEABEXFR-YTIEKEKJJMFKEKEKWBRAUNQJU-KBYGB 5. 如果是网络安装,最好把网络驱动器映射成本机的一个盘符, 安装LoadRunner 的各级目录不要包含中文字符。 6. Next 后进入拷贝文件的界面 7. 拷贝文件完成后, 进入“User Login Settings” 界面。 ●Allow virtual users to run on this machine without user login 需要在下面输入域、用户名和密码, 这样运行Load Generator 的机器会自动登陆到网络, ●Manual log in to the Load Generator machine 运行Vusers 时, 自动登陆到网络, 无需登陆用户名和密码, 这样Vusers 就会不用任何干预自动的启动运行。推荐选择该项。这里选择第一项和第二项都可以。 8. 重新启动, 安装完成 LoadRunner7.8英文原版存放位置:\\10.138.149.139\test tools\ LoadRunner7.8中文版.rar 将压缩文件拷贝解压到本机的安装.。过程比较简单要开始安装以Administrator 的身份登陆Windows2000 后,(注意要退出已经运行的英文原版)运行安装目录下Setup.exe 即可进入安装程序,安装过程中一切人机交流窗口多选择默认“下一步”即可注意:解压文件存放的文件夹不可起中文名字,安装目录最好使用默认,如果更改则安装目录不要使用中文名!

    3.项目背景介绍

    3.1 背景概述 “LMS网校考试平台”是一个典型的三层B/S架构的MIS系统(客户端/应用服务器/数据库管),中间层是业务逻辑层,应用服务器处理所有的业务逻辑,但应用服务器本身不提供负载均衡的能力,而是利用开发工具提供的ORB(对象请求代理)软件保证多个应用服务器间的负载均衡。本次测试的目的是:进行应用服务器的压力测试,找出应用服务器能够支持的最大客户端数。方法是:按照正常业务压力估算值的1~10倍进行测试,考察应用服务器的运行情况。

    3.2压力测试用例 场景描述一:

     1. 用户登录的lmm模块,总共登陆24个用户,所有用户都同时并发操作。 2. 用户点击“登记的教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。 5. 点击“返回LMS” 按钮,返回到lmm模块,点击“退出”按钮,退出系统场景描述二: 1. 用户登陆lmm模块,总共登录48个用户,每1秒登录1个用户 2. 用户点击“已登记教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习; 5. 点击“返回LMS” 按钮,返回到lmm模块,点击“退出”按钮,退出系统场景描述三: 1. 用户登录的lmm模块,总共登陆48个用户,所有用户都同时并发操作。 2. 用户点击“登记的教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。 5. 点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统场景描述四: 1. 用户登录的lmm模块,总共登陆48个用户,每秒同时登录10个用户。 2. 用户点击“登记的教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。 5. 点击“返回LMS” 按钮,返回到lmm模块,点击“退出”按钮,退出系统场景描述五: 1. 用户登录的lmm模块,总共登陆100个用户,所有用户同时并发操作。 2. 用户点击“登记的教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。 5. 点击“返回LMS” 按钮,返回到lmm模块场景描述六: 1. 用户登录的lmm模块,总共登陆200个用户,所有用户同时并发操作 2. 用户点击“登记的教程” 3. 用户点击“启动”,进行课程学习,进入DS模块 4. 在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。 5. 点击“返回LMS” 按钮,返回到lmm模块,点击“退出”按钮,退出系统场景描述七: 1. 户登录的lmm模块,总共登陆24个用户。所有用户都同时并发操作 2. 所有用户都同时并发操作,户点击“登记的教程”中“test”课件使用自发测试工具,目的测试24个用户同时打开课件时服务器性能场景描述八: 1. 登录的lmm模块,总共登陆60个用户。所有用户都同时并发操作 2. 有用户都同时并发操作,户点击“登记的教程”中“test”课件使用自发测试工具,目的测试60个用户同时打开课件时服务器性能

    4.使用LoadRunner进行负载/压力测试

     4.1录制基本的用户脚本创建用户脚本需要用到VuGen。

    提示: 运行VuGen 最好在1024*768 的分辨率下, 否则有些工具栏会看不到。启动Visual User Generator 后, 通过菜单新建一个用户脚本, 选择系统通讯的协议。这里我们需要测试的是Web 应用,同时考虑到后台SQL数据库所以我们需要选择Web(HTTP/HTML)协议+SQL SERVER协议,确定后, 进入主窗体。通过菜单来启动录制脚本的命令。 ●在URL 中添入要测试的Web 站点地址..。 ●测试http://lms.ah.sp.com.cn/lms-lmm/loginForm.do选择要把录制的脚本放到哪一个部分, 默认情况下是“Action”。这里简单说明一下:VuGen 中的脚本分为三部分:vuser_init、vuser_end 和Action。其中vuser_init 和vuser_end 都只能存在一个, 不能再分割, 而Action 还可以分成无数多个部分( 通过点击New 按钮, 新建ActionXXX)。在录制需要登陆的系统时, 我们把登陆部分放到vuser_init 中, 把登陆后的操作部分放到Action 中, 把注销关闭登陆部分放到vuser_end 中。( 如果需要在登陆操作设集合点, 那么登陆操作也要放到Action 中, 因为vuser_init 中不能添加集合点) 在其他情况下, 我们只要把操作部分放到Action 中即可。注意: 在重复执行测试脚本时,vuser_init 和vuser_end 中的内容只会执行一次, 重复执行的只是Action 中的部分。 ●点“ 选项 ”按钮, 进入录制的设置窗体, 这里一般情况下不需要改动。 ●然后点“OK” 后,VuGen 开始录制脚本。在录制过程中, 不要使用浏览器的“ 后退” 功能,LoadRunner 支持不太好! 录制过程中, 在屏幕上会有一个工具条出现。录制的过程和WinRunner 有些类似, 不再多介绍。录制完成后, 按下“ 结束录制” 按钮,VuGen 自动生成用户脚本, 退出录制过程。

     4.2 完善测试脚本当录制完一个基本的用户脚本后, 在正式使用前我们还需要完善测试脚本, 增强脚本的灵活性。一般情况下, 我们通过以下几种方法来完善测试脚本。插入事务、插入结合点、插入注解、参数化输入。这里只举例介绍参数化如何设置,其它只作简单介绍。 4.2.1 插入事务事务(Transaction): 为了衡量服务器的性能, 我们需要定义事务。比如: 我们在脚本中有一个数据查询操作, 为了衡量服务器执行查询操作的性能, 我们把这个操作定义为一个事务, 这样在运行测试脚本时,LoadRunner 运行到该事务的开始点时,LoadRunner 就会开始计时, 直到运行到该事务的结束点, 计时结束。这个事务的运行时间在结果中会有反映。插入事务操作可以在录制过程中进行, 也可以在录制结束后进行。LoadRunner 运行在脚本中插入不限数量的事务。具体的操作方法如下: 在需要定义事务的操作前面, 通过菜单或者工具栏插入。输入该事务的名称。注意: 事务的名称最好要有意义, 能够清楚的说明该事务完成的动作。插入事务的开始点后, 下面需要在需要定义事务的操作后面插入事务的“ 结束点”。同样可以通过菜单或者工具栏插入。默认情况下, 事务的名称列出最近的一个事务名称。一般情况下, 事务名称不用修改。事务的状态默认情况下是LR_AUTO。一般情况下, 我们也不需要修改, 除非在手工编写代码时, 有可能需要手动设置事务的状态。 4.2.2 插入集合点插入集合点是为了衡量在加重负载的情况下服务器的性能情况。在测试计划中, 可能会要求系统能够承受1000 人同时提交数据,在LoadRunner 中可以通过在提交数据操作前面加入集合点, 这样当虚拟用户运行到提交数据的集合点时,LoadRunner 就会检查同时有多少用户运行到集合点,如果不到1000 人,LoadRunner 就会命令已经到集合点的用户在此等待, 当在集合点等待的用户达到1000 人时,LoadRunner 命令1000 人同时去提交数据, 从而达到测试计划中的需求。注意: 集合点经常和事务结合起来使用。集合点只能插入到Action 部分,vuser_init 和vuser_end 中不能插入集合点。具体的操作方法如下: 在需要插入集合点的前面, 通过菜单或者工具栏操作输入该集合点的名称。注意: 集合点的名称最好要有意义, 能够清楚的说明该集合点完成的动作。 4.2.3 插入注释注释的作用就不多说了, 不过插入注释最好是在录制过程中。具体的操作方法如下: 在需要插入注释的前面, 通过菜单或者工具栏操作 4.2.4 参数化输入如果用户在录制脚本过程中, 填写提交了一些数据, 比如要增加数据库记录。这些操作都被记录到了脚本中。当多个虚拟用户运行脚本时, 都会提交相同的记录, 这样不符合实际的运行情况, 而且有可能引起冲突。为了更加真实的模拟实际环境, 需要各种各样的输入。参数化输入是一种不错的方法。用参数表示用户的脚本有两个优点: ① 可以使脚本的长度变短。 ② 可以使用不同的数值来测试你的脚本。例如, 如果你企图搜索不同名称的图书, 你仅仅需要写提交函数一次。在回放的过程中, 你可以使用不同的参数值, 而不只搜索一个特定名称的值。参数化包含以下两项任务: ① 在脚本中用参数取代常量值。 ② 设置参数的属性以及数据源。参数化仅可以用于一个函数中的参量。你不能用参数表示非函数参数的字符串。另外, 不是所有的函数都可以参数化的。参数化输入的讲解, 我们采用一个例子的方式来进行。在本例中我们参数化用户的登陆名:先看如下脚本,通过脚本录制找到用户登陆部分,如图 框选住登陆名,点鼠标右键,弹出对话框,选择“替换为新参数”弹出对话框 参数名随意取,建议取通俗易懂的名字,下面我们重点介绍一下参数的类型。 ●DateTime: 很简单, 在需要输入日期/时间的地方, 可以用DateTime 类型来替代。其属性设置也很简单, 选择一种格式即可。当然也可以定制格式。 .●Group Name:暂时不知道何处能用到,但设置比较简单。在实际运行中,LoadRunner 使用该虚拟用户所在的Vuser Group 来代替。但是在VuGen 中运行时,Group Name 将会是None .●Load Generator Name: 在实际运行中,LoadRunner 使用该虚拟用户所在Load Generator 的机器名来代替。 .●Iteration Number: 在实际运行中,LoadRunner 使用该测试脚本当前循环的次数来代替。 .●Random Number: 随机数。很简单。在属性设置中可以设置产生随机数的范围 .●Unique Number:唯一的数。在属性设置中可以设置第一个数以及递增的数的大小。注意: 使用该参数类型必须注意可以接受的最大数。例如: 某个文本框能接受的最大数为99。当使用该参数类型时, 设置第一个数为1, 递增的数为1, 但100 个虚拟用户同时运行时,第100 个虚拟用户输入的将是100,这样脚本运行将会出错。注意: 这里说的递增意思是各个用户取第一个值的递增数, 每个用户相邻的两次循环之间的差值为1。举例说明: 假如起始数为1, 递增为5, 那么第一个用户第一次循环取值1, 第二次循环取值2; 第二个用户第一次循环取值为6, 第二次为7; 依次类推。 ●Vuser ID: 设置比较简单。在实际运行中,LoadRunner 使用该虚拟用户的ID 来代替,该ID 是由Controller 来控制的。但是在VuGen 中运行时,Vuser ID 将会是–1。 File: 需要在属性设置中编辑文件,添加内容,也可以从现成的数据库中取数据( 下面我们将会介绍) ●User Defined Function: 从用户开发的dll 文件提取数据。就目前我认为, 这种方式没有必要。VuGen 支持C 语言的语法,在VuGen 中重新编写类似的函数应该不难。上面的例子中, 我们取随机数即可。点“Properties… ..” 按钮, 进行属性设置窗口添入随机数的取值范围为(1-50), 选择一种数据格式。在“属性” 中有以下几个选项: ◆Each Occurrence:在运行时, 每遇到一次该参数, 便会取一个新的值 ◆Each iteration:运行时, 在每一次循环中都取相同的值 ◆Once:运行时, 在每次循环中, 该参数只取一次值这里我们用的是随机数, 选择Each Occurrence 非常合适。下面我们再介绍用数据库中的用户名来参数化登陆用户名。框选住登陆名,点鼠标右键,弹出对话框,选择“替换为新参数”弹出对话框,此时参数名输入:name,参数类型选择File,如图 点“属性”按钮, 出现以下窗口 注意: 参数的文件名不要使用con.dat、pm.dat 或者lpt*.dat 等系统装置名下面我们将会连接数据库, 从数据表中选择用户名。点“数据向导” 按钮,显示如图 使用第2 项, 选择“使用手动指定SQL语句”点下一步,出现如图窗口 添入连接字符串, 点“创建” 按钮,选择事先配置好的ODBC连接。在SQL语句里输入select查询语句,出现如图窗口 提醒: 在参数数据显示区, 最多只能看到100 行, 如果数据超过100 行, 只能点“编辑” 按钮, 进入记事本看。 “选择下一行 ” 有以下几种选择: ●Sequential: 按照顺序一行行的读取。每一个虚拟用户都会按照相同的顺序读取 ●Random: 在每次循环里随机的读取一个, 但是在循环中一直保持不变 ●Unique : 唯一的数。注意: 使用该类型必须注意数据表有足够多的数。比如Controller 中设定20 个虚拟用户进行5 次循环, 那么编号为1 的虚拟用户取前5 个数, 编号为2 的虚拟用户取6-10 的数, 依次类推, 这样数据表中至少要有100 个数据, 否则Controller 运行过程中会返回一个错误。 “按编号”指选择列表中的那一列数据,从左到右分别是1、2、3依次通常用在有关联性的数据上面。我们这里取值Sequential 即可。完成设置关闭即可

     4.3 单机运行测试脚本经过以上的各个步骤后, 脚本就可以运行了。运行脚本可以通过菜单或者工具栏来操作。执行“ 运行” 命令后,VuGen 先编译脚本, 检查是否有语法等错误。如果有错误,VuGen 将会提示错误。双击错误提示,VuGen 能够定位到出现错误的那一行。为了验证脚本的正确性, 我们还可以调试脚本, 比如在脚本中加断点等, 操作和在VC 中完全一样, 相信大家谁都不会感到陌生。如果编译通过, 就会开始运行。然后会出现运行结果。

     5实施测试

    5.1 选择脚本,创建虚拟用户 启用“controller”弹出如图窗口 选择刚才录制并保存好的脚本,添加到方案中,点“确定”出现如图 根据需要修改虚拟用户数量,这里我们取“100”根据实现场景设计,取不同数字 点“编辑计划”细化方案,计划名里选择计划种类:加压,缓慢加压、默认计划或新建立计划。 默认计划:同时加载所有vuser,直到完成 加压:每15秒启动2个vuser 持续时间5分种 缓慢加压:每2分种启动2个vuser 持续时间10分种这里我们选择“加压” 出现如图 点“加压”标签设置加压方法,点“持续时间”标签选择完成时间,点“加压”标签选择退出方法,点“方案开始时间”可以定义时间后自动到点执行,并在一个限定的时间范围内结束,所有设置完毕后,点“ok”返回上一级窗口,点“开始方案”启动运行,出现如图窗口

    5.2 添加windows资源监视窗口 loadruner默认性能监视窗口四个,分别是“运行vuser“、”事务响应时间“、 “每秒点击次数”最后一个可以根据用户自己选择现实什么窗口。打开可用图中目录树,选择系统资源,找到windows资源双击,则windows资源监视窗口便自动替换原窗口如上图。当然loadrunner也可以同时显示1-16个窗口,方法是点右键,在弹出菜单中选择“查看图”选择显示的图数,也可以自定义数字。

     5.3 添加windows性能计数器鼠标选择windows资源监视窗口,点击右键弹出菜单中选择“ADD Measurements..”弹出如图窗口 点“添加”把监视的服务器ip地址输入,点确定,如图 如果可以正常联机到服务器,则在资源度量中会显示全部计数器,此时如果点“确定”则系统默认全部选中,在监视窗口中会显示所有性能曲线,无法单独过滤显示某条曲线,如果选中某个计数器后点“添加”则弹出该项目下的其它性能指标,选择需要的计数器后点“添加”如图 此时要注意,你登陆客户端(也就是你装有loadrunner机器)的用户应该是管理员身份,同时还要保证该用户在被监视的服务器上也是管理员身份。这样选择虽然监视窗口中仍会显示所有性能曲线,但是可以通过鼠标右键弹出菜单,选中你指定的某条曲线单独显示。方法是双击监视窗口放大显示,然后右键选择“仅显示指定图”监视窗口还可以互相叠加等操作,功能强大,通过右键菜单选择可以进行复杂显示操作。常用的还有web程序服务器图、数据库服务器资源图等,添加方法雷同。计数器有那些,有什么含义,理想值是多少,可以参见第六章节。

     5.4 执行脚本此时设置完毕后,那就简单了,点击“开始方案”注意观察吧。

    5.4.1 分析结果 脚本执行完毕后,loadrunner会自动分析结果,生成分析结果图或表,方法是点导航栏“结果”选现,在弹出窗口中选择“分析结果”

    6 分析以及监视场景在运行过程中, 可以监视各个服务器的运行情况(DataBase Server、Web Server 等)。监视场景通过添加性能计数器来实现。这一章非常的重要, 确定系统瓶颈全靠它了。下面重点讲讲需要添加那些计数器, 以及那些计数器代表什么意思。由于Win2000 Professional、Server 以及Advanced Server 提供的计数器不完全相同, 这里我们讨论将以Server 为基准。监视场景需要在Run 视图中设置然后, 出现添加计数器的对话框其他的操作就和控制面板“ 性能” 中添加性能计数器的操作一样, 这里不再详细说明。本章主要说明一下各个系统计数器的含义( 数据库的计数器不做重点, 只是拿SQL Server2000 作为例子进行说明。因为数据库各个版本之间差异比较大, 请参考您使用的数据库系统的帮助)。

     6.1 Memory相关内存是第一个监视对象, 确定系统瓶颈的第一个步骤就是排除内存问题。内存短缺的问题可能会引起各种各样的问题。 Object( 对象) Counters Descrīption( 描述) 参考值 Memory Available MBytes 物理内存的可用数(单位 Mbytes)。默认情况下IIS5.0 使用50%的可用物理内存, 作为IIS 的文件缓存(file cache)。IIS 基本占用 2.5 MB,每个附加连接将在此基础上占用 10 KB 左右 至少要有10% 的物理 Memory Page/sec Page Faults/sec Pages Input/sec Pages Input/sec Page Reads/sec Transition Faults/sec 物理内存的可用数(单位 Mbytes)。默认情况下IIS5.0 使用50%的可用物理内存, 作为IIS 的文件缓存(file cache)。IIS 基本占用 2.5 MB,每个附加连接将在此基础上占用 10 KB 左右。至少要有10% 的物理内存值当处理器向内存指定的位置请求一页( 可能是数据或代码) 出现错误时, 这就构成一个Page Fault。如果该页在内存的其他位置, 该错误被称为软错误( 用Transition Fault/sec 数器衡量); 如果该页必须从硬盘上重新读取时, 被称为硬错误。许多处理器可以在有大软错误的情况下继续操作。但是, 硬错误可以导致明显的拖延。Page Faults/sec 是处理器每秒钟处理的错误页( 包括软错误和硬错误)。Pages Input/sec 是为了解决硬错误页, 从硬盘上读取的页数, 而Page Reads/sec 是为了解决硬错误, 从硬盘读取的次数。如果 Page Reads/Sec 比率持续保持为 5, 表示可能内存不足。Pages/sec 是指为解析硬页错误从磁盘读取或写入磁盘的页数。 Page/sec 推荐00-20( 如果服务器没有足够的内存处理其工作负荷, 此数值将一直很高。如果大于80,表示有问题)。这些计数器的值比较低, 说明Web服务器响应请求比较快, 否则可能是服务器系统内存短缺引起( 也可能是缓存太大, 导致系统内存太少)。Page Input/sec 的值可以衡量出硬错误页发生的速率, 通常它的值会于或者等于Page Reads/sec。Memory Cache Bytes Memory Cache Bytes 文件系统缓存(File System Cache) 默默认情况下认情况下为50%的可用物理内存。如为50%的可IIS5.0 运行内存不够时, 它会自动整理用物理内存缓存。需要关注该计数器的趋势变化 Internet File Cache Hits % File Cache Hits %是文件缓存命中全部( 对于一个Information File Cache 缓存需求的比例, 反映了IIS 的文件缓大部分是静Services Flushes 存设置的工作情况。而File Cache Hits 态网页组成 Global File Cache Hits 是文件缓存命中的具体值,File Cache 的网站)File Flushes 是自服务器启动之后文件缓存Cache Hits% 刷新次数, 如果刷新太慢, 会浪费内存; 如果刷新太快, 缓存中的对象会太频繁属于非常好! 的丢弃生成, 起不到缓存的作用。通过File Cache Hits 和File Cache Flushes 可以得到一个适当的刷新值( 参考IIS 的设置ObjectTTL 、MemCacheSize 、MaxCacheFileSize) Memory PoolPaged BytesPool Nonpaged Bytes Pool Paged Bytes Pool Nonpaged Bytes 这两个计数器监视服务器上各个进程的分页池字节数和非分页池字节数。 在访问数比较固定的情况下, Pool Nonpaged Bytes 是比较定的, 如果访问数逐步增加, 该值会缓慢的增加 Process Virtual Bytes Working Set 计数器 Virtual Bytes( 实Virtual Bytes 数器监视IIS5.0 保留的例inetinfo 、虚地址空间的数量, 实例化为inetinfo dllhost) Working Set( 实例进程(IIS 运行的核心)和Dllhost 进程( 隔离/ 连接池的应用程序必需的)。inetinfo 、dllhost) Working Set 计数器反映了每个进程使Dllhost#n 进程都用的内存页的数量。系统的内存页(pool 要添加计数器Page) 只能由操作系统的核心模块直接访问, 用户进程不能访问。运行IIS5.0 的服务器上, 负责web 连接的线程以及它需要的一些对象都保存在未分页的池中(nonpaged pool), 比如文件句柄和socket 连接 Process Private Bytes 指这个处理不能与其他处理共享的、已分配的当前字节数 Memory Committed Bytes 是指以字节表示的确认虚拟内存。(确认内存是指为磁盘分页文件在磁盘上保留的空间以便在需推荐不超过物理内存的75% 要将其写回磁盘时使用) 推荐部超过物理内存的75% 内存问题主要检查应用程序是否存在内存泄漏。如果发生了内存泄漏,Process\Private Bytes 计数器和Process\Working Set 计数器的值往往会升高, 同时Available Bytes 的值会降低。内存泄漏应该通过一个长时间的, 用来研究分析当所有内存都耗尽时, 应用程序反应情况的测试来检验。

     6.2 Processor相关 Object( 对象) Counters Descrīption( 描述) 参考值 Sytem Processor Queue Length Processor Queue Length 是指处理列队中的线程数。即使在有多个处理器的计算机上处理器时间也会有一个单列队。不象磁盘计数器, 这个计数器仅计数就绪的线程, 而不计数运行中的线程。如果处理器列队中总是有两个以上的线程通常表示处理器堵塞 小于2。显示在由 Web 服务器所有处理器共享的队列中等待执行的线程数。处理器瓶颈会导致该值持续大于2 Processor %Processor Time CPU 使用率。这是查看处理器饱和状况的最佳计数器。显示所有 CPU 的线程处理时间。如果一个或多个处理器的该数值持续超过 90%,则表示此测试的负载对于目前的硬件过于沉重。为多处理器服务器添加该计数器的 0 到 x 个实例 小于75%。排除内存因素, 如果该计数器的值比较大, 而同时网卡和硬盘的值比较低, 那么可以定CPU 瓶颈 System Context Switches/sec Context Switches/sec 指计算机上的所有处理器全都从一个线程转换到另一个线程的综合速率。当正在运行的线程自动放弃处理器时出现上下文转换, 由一个有更高优先就绪的线程占先或在用户模式和特权(内核)模式之间转换以使用执行或分系统服务。它是在计算机上的所有处理器上运行的所有线程的Thread: Context Switches/sec 的总数并且用转换数量衡量。在系统和线程对象上有上下文转换计数器 如果切换次数到5000*CPU个数和10000*CPU 个数中, 说明它忙于切换线程而不是处理ASP 脚本 Processo %Privileged Time % Privileged Time 是在特权模式下处理线程执行代码所花时间的百分比。当调用 Windows 系统服务时, 此服务经常在特权模式运行, 以便获取对系统专有数据的访问。在用户模式执行的线程无法访问这些数据。对系统的调用可以是直接的(explicit)或间接的(implicit), 例如页面错误或中断。不像某些早期的操作系统,Windows 除了使用用户和特权模式的传统保护模式之外, 还使用处理边界作为分系统保护。某些由Windows 为您的应用程序所做的操作除了出现在处理的特权时间内, 还可能在其他子系统处理出现 Time Switches/sec ( 实例化inetinfo 和dllhost 如果你决定要增加线程字节池的大小,你应该监视这三个计数器( 包括上面的一个)。增加线数可能会增加上下文切换次数, 这样性能不会上升反而会下降。如果十个实例的上下文切换值非常高, 就应该减小线程字节池的大小 Processor Interrupts/sec %DPC Time Time 这两个计数器能够反映处理器用在处理中断以及推迟处理调用的时间。如果处理器使用率超过Interrupts/sec 指处理器每秒钟接收并维90% 且 硬件中断的平均值。正常的线程操作在中断时悬停。大多数的系统时钟每Interrupt Time 大于隔 10 毫秒中断处理器一次, 形成了间15%, 则处理隔活动的后台 如果处理器使用率超过90%,且Interrupts/sec time大于15%则处理器可能负载过重,并发生中断 Processor Interrupts/sec %DPC Time 这两个计数器能够反映处理器用在处理中断以及推迟处理调用的时间。如果处理器使用率超过Interrupts/sec 指处理器每秒钟接收并维90% 且 硬件中断的平均值。正常的线程操作在中断时悬停。大多数的系统时钟每Interrupt Time 大于隔 10 毫秒中断处理器一次, 形成了间15%, 则处理隔活动的后台。器可能负荷过重, 并发生中断。判断应用程序是否存在处理器瓶颈的方法: 如果Processor Queue Length 显示的队列长度保持不变(>=2) 个并且处理器的利用率%Processor Time 超过90%, 那么很有可能存在处理器瓶颈。如果发现Processor Queue Length 显示的队列长度超过2, 而处理器的利用率却一直很低, 那么或许更应该去解决处理器阻塞问题, 这里处理器一般不是瓶颈。如果系统由于应用程序代码效率低下或者系统结构设计有缺陷而导致大量的上下文切换(Context Switches/sec 显示的上下文切换次数比较大), 那么就会占用大量的系统资源。如果系统的吞吐量降低并且CPU 的使用率很高,并且此现象发生时切换水平在15000 以上, 那么意味着上下文切换次数过高同时还可以比较Context Switches/sec 和%Privileged Time 来判断上下文切换是否过量。如果后者的值超过40%, 且上下文切换的速率也很高, 那么应该检查为什么会产生这样高的上下文切换。

     6.3 网络吞吐量以及带宽 Object Counter Descrīption 参考值 Network Interface Bytes Total/se Bytes Total/sec 为发送和接收字节的速率, 包括帧字符在内。判断网络连接速该计数器的值和目前网度是否是瓶颈, 可以用该计数器的值和络的带宽相目前网络的带宽比较 改计数器的值和目前网络带宽相除,结果应该小于50% Web Servic Maximum Maximum Connections Maximum Maximum Connections :“ 最大连接数” Attempts Total Connection Attempts :“ 连接尝试总数” 是从服务启动时利用 Web 服务尝试连接的总数。该计数器应用于全部所列的实例。

    6.4 磁盘相关 Object( 对象) Counters( 计数器名称) Descrīption( 描述) 参考值 Object Counters Descrīption 参考值 Network Bytes Total/sec Bytes Total/sec 为发送和接收字节的速Interface 率, 包括帧字符在内。判断网络连接速度是否是瓶颈, 可以用该计数器的值和目前网络的带宽比较 Processo %Processor Time % Privileged Time CPU 使用率该计数器对应于处理器执行Windows. 2000 内核命令( 如处理SQL Server I/O 请求) 所用时间的百分比。如果 Physical Disk 计数器的值很高时该计数器的值也一直很高, 则考虑使用速度更快或效率更高的磁盘子系统。 PhysicalDisk %Disk Time % Disk Time 指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。如果三个计数器都比较大, 那么硬盘不是瓶颈。如果只有%Disk Time 比较大, 另外两个都比较适中, 硬盘可能会是瓶颈。在记录该计数器之前, 请在 Windows 2000 的命令行窗口中运行 diskperf -yD 。若数值持续超过 80%, 则可能内存泄漏。 PhysicalDisk AverageDisk Queue Length 指读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。 PhysicalDisk PhysicalDisk 指在此盘上读取操作的速率 PhysicalDisk Disk Writes/sec 指在此盘上写入操作的速率 判断磁盘瓶颈的方法是通过以下公式来计算: 每磁盘的I/O 数 = [读次数 + (4 * 写次数)] / 磁盘个数如果计算出的每磁盘的I/O 数大于磁盘的处理能力, 那么磁盘存在瓶颈。

    6.5 Web应用程序这里以ASP.NET 开发的Web 应用程序为例进行说明。 Object Counters Descrīption 参考值 ASP.NET Applications Request/Sec Request Executing 每秒执行的请求数。 如果Request/Sec ApplicationsRequest Executing 当前执行的请求数。的值比较小, 你的Web 程序可能是瓶颈 ASP.NET ASP.NETRequestWait Time Request Executing Time 最近的请求在队列中等待的毫秒数。执行最近的请求所用的毫秒数。Queued 在理想状况下应该接近0, Request Queued 等候处理的请求数。该计数器应保持接近 0。超过 IIS 队列长度会出如果这两个值太大, 那么需要重现“服务器太忙”错误

    6.6 SQL Server 这里针对SQL Server2000, 而且只是列出比较关键的几个。更加详细的信息可以参考SQL Server 的联机文档。 Object( Counters Descrīption 参考值 Processor %Processor time CPU 使用率 SQL Server: Logins/sec 这是每秒登录到 SQL Server 的计数 SQLServer:CacheManage Cache Hit Ratio (all instances) 显示在高速缓存中找到数据的命中率。如果数值持续小于 85%, 则表示内存有问题。 SQL Server General Statistics User Connections 显示当前 SQL 用户数。与 Active Server Pages:Requests/Sec 计数器进行比较, 可帮助了解脚本对 SQL Server 的影响程度。如果差别过大, 则表示测试脚本不能有效地对SQL Server 进行应力测试。 SQLServer:Locks Lock Waits/sec 显示在当前进程完成之前强制其他进程等待的每秒锁定请求的数量。如果该值始终大于 0, 则表示事务有问题。 SQLServer: BuffeManage Buffer Manager Hit Ratio 计数器值依应用程序而定, 但比率最好为 90% 或更高。增加内存直到这一数值持续高于 90%, 表示90% 以上的数据请求可以从数据缓冲区中获得所需数据。 SQLServer SQL Statistics Batch Requests/sec 每秒收的Transact-SQL 命令批数。这一统计信息受所有约束( 如I/O、用户数、高速缓存大小、请求I/O、用户数、高速缓存大小、请求的复杂程度等) 影响。批请求数值高意味着吞吐量很好。 SQL Server: Buffer Manager Lazy Writes/sec 每秒被缓冲区管理器的惰性写入器写入的缓冲区数。惰性写入器是一个系统进程, 其主要任务是刷新成批的老化的脏缓冲区( 指包含更改的缓冲区, 这些更改必须写回磁盘, 才能使该缓冲区由其它页重新使用), 并使之可由用户进程使用。惰性写入器消除了为创建可用缓冲区而频繁执行检查点的需要。 SQL Server: Buffer Manager Page Reads/sec 每秒发出的物理数据库页读取数。这一统计信息显示的是在所有数据库间的物理页读取总数。由于物理I/O 的开销大, 可以通过使用更大的数据高速缓存、智能索引、更高效的查询或者改变数据库设计等方法, 使开销减到最小。 SQL Server:Databases Transactions/sec 每秒为数据库启动的事务数 这里针对SQL Server2000, 而且只是列出比较关键的几个。更加详细的信息可以参考SQL Server 的联机文档。

     6.7 Network Delay 如果要监视的两台计算机在同一个局域网络内, 建议不要使用Network Delay Monitor。因为在同一局域网内,Network Delay 会非常的小, 网络监视器会有足够的时间在每秒钟内发送成百上千的请求, 这样会导致源计算机(source machine) 的CPU 和内存超负荷工作。默认情况下“Enable display of network nodes by DNS names” 选择是没有选中的, 因为选中它会明显的降低该监视器的速度。

    7 分析实时监视图表这一章仅仅介绍几个最重要的图表。 Q1 事务响应时间是否在可接受的时间内? 哪个事务用的时间最长? 看Transaction Response Time 图, 可以判断每个事务完成用的时间, 从而可以判断出那个事务用的时间最长, 那些事务用的时间超出预定的可接受时间。 Q2 网络带宽是否足够? “Throughput”图显示在场景运行期间的每一秒钟, 从Web Server 上接受到的数据量的值。拿这个值和网络带宽比较, 可以确定目前的网络带宽是否是瓶颈。如果该图的曲线随着用户数的增加, 没有随着增加, 而是呈比较平的直线, 说明目前的网络速度不能够满足目前的系统流量。 Q3 硬件和操作系统能否处理高负载? “Windows Resources” 图实时地显示了Web Server 系统资源的使用情况。利用该图提供的数据, 可以把瓶颈定位到特定机器的某个部件。

    8 经常遇到的问题

     8.1 VuGen的问题在使用VuGen 中经常会遇到的问题。

     8.2 Controller的问题在使用Controller 中经常会遇到的问题。 1. 在添加完Load Generators 机器时, 连接老是失败; 添加的机器明明已经安装了 loadrunner, 并且网络通讯正常。解决方法: 在安装loadrunner 的第七步骤, 应该选择第2 项, 如果选择了第一项, 就会有这种问题。重新安装一下即可。 2. 在VuGen 中运行良好的脚本, 到Controller 中运行却出问题。这种问题可能会遇到。为了确定问题出在Controller 中的场景,而不是脚本的问题, 你应该在所有的Load Generators 机器上使用VuGen 运行测试脚本, 确保都能够运行正确。因为VuGen 和Controller 运行的机制不一样。在VuGen 中运行时使用的是完整的浏览器, 而在Controller 中运行时使用的只是浏览器的基本的部分。

     8.3 计数器的问题在使用性能计数器中经常会遇到的问题。 1. 添加了Windows Resources 计数器后, 却看不到实时的数据。解决方法: 要得到监视的数据, 必须要在被监视的服务器(Web Server) 上获得管理员权限。最简单的方法是在“ 网络邻居”中以administrator 身份登陆Web Server。当然使用下面的控制台命令也可以:net use \\< 机器名> 然后登陆用户名和密码即可。(登陆的用户名必须具有管理员权限) 2. 添加了一些默认的性能计数器后, 出现了错误。解决方法: 可能是一些LoadRunner 默认的计数器在WebServer 上已经不存在的原因, 尤其是数据库的计数器方面。简单的解决方法, 就是删除有问题的计数器, 添加比较接近的计数器( 可能需要参考Windows 帮助或者数据库的帮助)

    9.结果分析根据不同的场景设计,配置脚本后进行测试得到如下结果测试环境 LMM: CPU:4x2.7G RAM:4G Websphere 5.0 + IBM Http Server 线程池:100 JDBC连接池:100 会话超时:30分钟 DS: CPU:4x2.2 RAM:4G Websphere 5.0 + IBM Http Server 线程池:100 JDBC连接池:100 会话超时:30分钟 DB&LDAP: CPU:2x2.2G RAM:4G Oralce 8.1.7 + LDAP 测试工具:Load Runner 7.8 用户数据:用户名test1 – test100; 口令与用户名相同。 测试用例1 测试场景描述用户登录的lmm模块,总共登陆24个用户,所有用户都同时并发操作。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在10%以下。LMM服务器CPU利用率峰值为20%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为7秒),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户平均操作响应时间不超过5秒,所有交易成功。 测试用例2 测试场景描述用户登陆lmm模块,总共登录48个用户,每1秒登录1个用户用户点击“已登记教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习;点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在5%以下。LMM服务器CPU利用率峰值为10%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为8%,其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户操作响应时间不超过3秒,所有交易成功。测试用例3 测试场景描述用户登录的lmm模块,总共登陆48个用户,所有用户都同时并发操作。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在20%以下。LMM服务器CPU利用率峰值为40%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为10秒),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户平均操作响应时间不超过10秒,所有交易成功。测试用例4 测试场景描述用户登录的lmm模块,总共登陆48个用户,每秒同时登录10个用户。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在10%以下。LMM服务器CPU利用率峰值为10%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为2秒),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户平均操作响应时间不超过5秒,所有交易成功。测试用例5 测试场景描述用户登录的lmm模块,总共登录100个用户,每1秒登录一个用户。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在20%以下。LMM服务器CPU利用率峰值为10%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为2’20分钟),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户最大操作响应时间30秒,所有交易成功。测试用例6 测试场景描述用户登录的lmm模块,总共登陆100个用户,所有用户同时并发操作。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM与DS模块CPU平均利用率在20%以下。LMM服务器CPU利用率峰值为40%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为3分钟),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户超时1个。测试用例7 测试场景描述用户登录的lmm模块,总共登陆200个用户,所有用户同时并发操作。 用户点击“登记的教程” 用户点击“启动”,进行课程学习,进入DS模块在DS模块中进行学习,过程包括:首先,点击一次课程结构树;然后,进行课程内容的学习。点击“返回LMS” 按钮,返回到lmm模块点击“退出”按钮,退出系统测试结果 LMM CPU平均利用率在20%以下。LMM服务器CPU利用率峰值为40%,其阶段为LMM处理多个用户同时的登录请求与点击“已登记教程”的学习课程查询。DS服务器CPU利用率峰值为100%(持续时间为5分钟),其阶段为DS处理多个用户单一登录验证和同时对课程结构树查询。用户超时108个。

     10参考文献 LoadRunner中文使用手册(完全版) LoadRunner 7.8 联机帮助

  • loadrunner关于集合点问题

    2007-11-22 22:20:23

      虽然前面已经学过了loadrunner的理论知识,但是还没有真正的应用到工作中,这次因为项目的需要,我也只好硬着头皮上了,在性能测试的实施的过程中,却发现集合点图并不是所有的用户都到了集合点时,用户才释放的,而是释放了几次,就象开始我设置了20个虚拟用户,但是在1014..20的时候都释放了一次,开始一直不知道为什么会释放几次(因为我一直认为是所有的虚拟用户都到达了集合点后才开始释放的),后来到网上去查了相关的问题的解决办法,得到的答案是:第一,这和设置的集合点策略有关系(集合点设置的策略有三种:1种所有用户达到100%的加载的虚拟用户后才释放;2种是当到达集合点的用户是正在运行用户的100%时集合点释放;3种是);第二,这和设置的虚拟用户的timeout相关,当运行用户数增加的同时,集合点的等待的用户数也在增加,当集合点等待的用户数达到了设置的集合点策略的用户数时,集合点就开始释放;但是若此时集合点等待的用户数未达到设置的集合点策略的用户数,而设置的用户等待时间timeout,此时集合点也会释放;当然释放可以是多次也可以是一次,若设置的集合策略的用户等待时间较长,就有可能在整个过程中集合点只释放一次,相反如果设置的用户等待时间较短,集合点就可能释放几次,而且每个释放点的用户数可能还会不一样;

Open Toolbar