上期讲到LoadRunner性能测试关联函数介绍,这期我们一起学习异步技术。
同步与异步的区别
通常的一些Web的功能是使用同步的方式来处理请求,典型的同步请求的步骤如下:
1.用户使用Web浏览器与服务器进行交互;
2.基于用户的输入,通过Web浏览器向服务器提交请求;
3.然后服务器将请求的响应发送回客户端,并更新客户端的信息。
同步的方式有一些局限性,一个典型的弊端是无法在客户端显示服务器的动态数据,如动态的显示股票的价格,理想的情况应该是应用程序的客户端可以动态的显示服务器端更新的数据,同步每隔一段固定的时间更新股票的价格,如每隔10秒,浏览器会自动的发送一个请求到服务器上,并获得最新的股票价格。
在一些时候可以使用异步应用程序代替同步应用程序,当服务器发现事件变化时,那么异步程序会将通知客户端,异步应用程序能够更好的更新所需要的资料,这样客户端并不需要等待服务器将请求处理完成,而是在这个过程中可以处理其它的请求,只要等服务器处理完成后,会自动通知客户端更新处理后的值。
在性能测试过程中为了更好的处理这种服务器每隔一段时间动态更新值的业务,在最新的LoadRunner版本中添加了异步处理的API函数来处理这种情况,这样不至于每次回放时发送的请求将一些动态的值写成固定的值,进而更好的模拟用户的行为。
虽然异步处理的方式有很多种,但主要有三种方式:堆、轮询和长轮询。
异步通信方式
异步通讯是由请求和响应序列组成,通常的异步方式包括:堆、轮询和长轮询三种,录制脚本时如果选择异步的方式取决于所录制业务的异步处理方式。堆、轮询和长轮询通讯原理如下:
轮询异步通迅
客户端有规律的每隔一段时间向服务器发送HTTP请求,如每隔5秒钟,发送一次请求,如果服务接受响应更新了数据,那么会将更新后的数据返回到客户端,如果没有更新的数据,那么客户会继续向服务器发送HTTP请求,关于轮询异步的通讯原理如图所示。
长轮询异步通讯
长轮询是服务器收到请求后如果有数据,立刻响应请求,将数据返回到客户端,如果没有数据就会停留一段时间, 这段时间内如果有数据立刻响应请求,如果时间到了还没有数据,则响应HTTP请求,浏览器收到HTTP响应后立即再发送一个同样HTTP请求查询是否有更新的数据,关于轮询异步的通讯原理如图所示。
堆异步通讯
客户端打开一个连接,并向已知的服务器发送一个HTTP请求,这样客户端与服务器不再断开连接,必要的时候服务器会向客户发送“子消息”来更新打开的客户端,如果服务器没有真正的发送更新信息,那么服务器会发送“ping”信息以防止客户端关闭由于连接超时的连接,关于堆异步的通讯原理如图所示。
如何创建异步脚本
在录制脚本过程中,如果脚本中包含需要异步处理的数据,那么LoadRunner会自动扫描是否有需要异步处理的数据,录制完成后会弹出Aysnc设置对话框,在该设置对话框中会显示异步处理的情况。
本文中以去哪儿官方订票系统为例,如图所示。对异步脚本处理进行介绍,具体步骤如下:
1.选择HTTP/HTML协议录制脚本
注意:异步处理只适用于
HTTP/HTML、Flex、Silverlight和Web Services这四种协议。
2.设置Async Scan选项
进入Recording Options界面,选择General->Code Generation标签页,确定Async Scan复选项是选中状态。
单击Async Options按钮,弹出Asynchronous Request Thresholds对话框,如图所示,在该对话框中可以设置异步请求的参数。
A.Minimum Response Size:
指定堆异步会话服务器响应的最小字节数,如果服务器发送的字节数小于最小字节数,那么VuGen将不会将这种异步类型归纳为堆的方式。
B.Maximum Sub Message Size:
指定堆异步会话服务器响应的最大字节数,如果服务器发送的字节数大于最大字节数,那么VuGen将不会将这种异步类型归纳为堆的方式。
C.Minimum Number of
Sub Messages:
指定堆异步会话发送的最小有效子消息数,如果服务器发送的消息小于子消息数,那么VuGen将不会将这种异步类型归纳为堆的方式。
D.Interval Tolerance:
指定轮询异步的时间间隔时间,单位为毫秒。
E.Maximum Interval:
指定长轮询异步响应结束与发送下一个请求之间的时间间隔。
1.开始录制脚本
2.业务录制完成后,停止录制,此时VuGen会自动扫描是否需要异步处理,如果扫描发现有需要异步处理的信息,则会弹出发图所示的信息。
注意:为了VuGen能够成功地确定在异步行为,异步通信必须至少包含所需的最小客户端请求和服务器响应的数量。
1.单击Close按钮,完成脚本录制,VuGen中产生如下代码:
/ Added by Async CodeGen.ID=Poll_0ScanType = RecordingThe following urls are considered part of this conversation: http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status=1365582390617&_token=72210&deduce=true http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status=1365582391928&_token=19725&deduce=true http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status=1365582395184&_token=24410&deduce=trueTODO - The following callbacks have been added to AsyncCallbacks.c.Add your code to the callback implementations as necessary. Poll_0_RequestCB Poll_0_ResponseBodyBufferCB Poll_0_ResponseCB / web_reg_async_attributes("ID=Poll_0", "URL=http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status={CorrelationParameter_3}&_token=72210&deduce=true", "Pattern=Poll", "PollIntervalMs=3000", "RequestCB=Poll_0_RequestCB", "ResponseBodyBufferCB=Poll_0_ResponseBodyBufferCB", "ResponseCB=Poll_0_ResponseCB", LAST);.../ Removed by Async CodeGen.ID = Poll_0/ / web_url("onewayflight_groupdata.jsp_6","URL=http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status=1365582391928&_token=19725&deduce=true","Resource=1","RecContentType=text/plain","Referer=http://flight.qunar.com/site/oneway_list.htm?searchDepartureAirport=%E6%B7%B1%E5%9C%B3&searchArrivalAirport=%E5%8D%97%E6%98%8C&searchDepartureTime=2013-04-12&searchArrivalTime=2013-04-15&nextNDays=0&startSearch=true&from=qunarindex","Snapshot=t167.inf", LAST); // Removed by Async CodeGen.ID = Poll_0/ / web_url("onewayflight_groupdata.jsp_7","URL=http://flight.qunar.com/twell/flight/tags/onewayflight_groupdata.jsp?&departureCity=%E6%B7%B1%E5%9C%B3&arrivalCity=%E5%8D%97%E6%98%8C&departureDate=2013-04-12&returnDate=2013-04-12&nextNDays=0&searchType=OneWayFlight&searchLangs=zh&locale=zh&from=qunarindex&queryID=192.168.0.19%3A63ab0de2%3A13df30a3fd7%3A-597b&serverIP=l-tw6.f.cn1.qunar.com%2F192.168.0.19&status=1365582395184&_token=24410&deduce=true","Resource=1","RecContentType=text/plain","Referer=http://flight.qunar.com/site/oneway_list.htm?searchDepartureAirport=%E6%B7%B1%E5%9C%B3&searchArrivalAirport=%E5%8D%97%E6%98%8C&searchDepartureTime=2013-04-12&searchArrivalTime=2013-04-15&nextNDays=0&startSearch=true&from=qunarindex","Snapshot=t168.inf", LAST); // Added by Async CodeGen.ID = Poll_0/ web_stop_async("ID=Poll_0",