1引入JMeter TCP Sample
JMeter自带的TCP Sample可以完成并发的TCP性能测试,下面通过一个实例说明应用方法。
需要进行的性能测试需求如下:待测试流量监控系统需要支持1W条业务的流量监控。基于产品定位和系统实现分析,该流量监控系统可以进行多种业务的流量监控和分析。系统通过采集业务传输设备(交换机、路由器等)的流量信息,进行分析和评估。主要过程是,系统与设备建立管理通道,设备定时(5分钟)将流量信息通过TCP推送给系统。系统根据存储的业务信息,匹配流量信息,完成相应计算并入库。
当前需要进行验证的性能需求为:该系统能够同时进行1W条业务的流量监控。经过上述分析,可以明确测试的关键,当同时进行1W条业务的监控时,最差情况系统应能在5分钟内完成这些业务的数据分析和入库。当然,这是最低的要求,如果不满足该要求,系统就无法在一个周期内完成该周期的处理,相应的就会出现丢数据、无法处理其他响应等问题。
那么初步的测试方案就确定了:通过JMeter线程组完成并发,定时器每5分钟进行一次TCP请求,其中请求的内容为业务的流量数据。
2 模拟场景设计
考虑测试过程影响场景设计的变量:设备数目、单设备业务数。二者相乘为1W条业务(复杂的单设备业务条数不同不是影响系统性能的关键因素,所以不考虑)。区分二者的原因在于,设备数目决定了系统需要进行的TCP连接数目(即一个设备一个TCP连接);单设备业务数决定了单条连接在周期时间需要推送并处理的数据量。以上分析与系统实现息息相关。
既定前提是不考虑设备的瓶颈,比如单设备最多只能完成10条业务的推送,超出后设备在5分钟内无法推送完成。单纯考虑流量系统的能力,初期设计如下场景:
(1)1W*1,即场景为1W个设备,每个设备1条业务。重点验证系统能否建立1W连接。
(2)100*100,即场景为100个设备,每个设备100条业务。
(3)1*1W,即场景为1个设备,该设备有1W条业务。重点验证系统能否在周期点一次完成1W数据的处理。
上述场景仅为初期的想法,其中包括了对系统实现的分析和假设,后续需要根据测试结果进行验证和修改。
100*100为通用场景,下面描述以该场景为例进行说明。下图说明测试的场景设计。
3 工作分解
整体场景设计完成后,可以针对性能测试工作进行分解,具体工作如下:
(1)业务数据模拟。通过TCP推送的数据需要与系统已经存储的业务进行关联,所以需要预先创建好1W条业务。可以通过SQL语句完成数据插入,原理不复杂,主要要了解系统实现的表结构。
(2)设备在线模拟。根据设备与系统的管理协议模拟在线的设备,有很多现成的模拟工具可以借鉴。
(3)TCP连接和推送模拟。利用JMeter的TCP Sample完成TCP连接以及数据的推送,本文重点介绍。
(4)执行场景测试。执行测试,设置不同档位的压力,收集数据。
(5)结果分析、测试、验证。根据测试结果分析性能瓶颈,进行优化、调整、测试并验证。
4 TCP连接和推送模拟
4.1 TCP模拟示意
通过上述分析确定了JMeter在本次测试中的关键地位,同时也确定了使用的主要元件:TCP Sample,下图可以描述整体模拟示意。
对比之前的场景设计,从待测系统的视角看到的是100个TCP连接,收到数据后进行数据库的业务关联和数据计算。在模拟设备侧,使用JMeter线程组并发,TCP Sample携带100条业务的流量数据。所以可以看出,完全可以欺骗待测系统,建立模拟环境。
4.2 JMeter配置
JMeter配置如下图,涉及到的元件包括:
Thread Group-作用为线程并发;
Loop Controller-循环进行管理推送,作为推送多少次(也就是多久的配置);
Synchronizing Timer-线程并发定时器,约定所有线程在此并发;
TCP Sampler-主要元件,推送TCP数据;
Constant Timer-作为每5分钟的间隔;
BeanShell Assertion-不在TCP请求中进行返回验证,完后后根据数据库入库的流量数据数目进行验证;
View Reaults Tree-查看结果。
重点说明TCP Sample的配置。
Name和Comments为自定义,无需过多解释。
TCPClient classname为TCP Sample使用的TCP Client的实现,可以是自定义的,可以是JMeter提供的。本例中使用的是自定义的,原因见后面的问题分析。介绍一下JMeter自带的TCP Client实现类。
TCPClientImpl:TCPClient最简单实现类,也是默认使用的Client。以文本方式发送和接收数据。读取响应时读到输入流结束或者结束符停止。其中结束符通过JMeter属性的tcp.eolByte定义。使用的字符集通过tcp.charset配置,未配置则使用默认。
BinaryTCPClientImpl:TCPClient的二进制实现类。以二进制(Hex流)的方式将配置的数据传送,所以要求配置的数据必须是二进制(Hex流)。读取数据的时候会把数据重新转为二进制(Hex流)。读取响应时一直读到输入流结束,或者定义好的结束字节,该字节通过tcp .BinaryTCPClient.eomByte配置。
Target Server相关配置为TCP服务器的配置,包括Server Name or IP,Port Number。Timeouts为超时时间,单位是毫秒,可以配置连接的超时时间和读取响应的超时时间。
Re-use connection:选中表示重用TCP连接,含义是同一线程重用,即同一个线程内的多个请求使用客户端同一IP和相同端口与服务器连接,服务器维护的是一个TCP连接。当然,并发的不同线程使用的不同的连接。当在请求过程中出现错误,即使该配置被选中,也会在下一次请求时重新打开一个连接。
Close connection:选中表示请求结束后关闭连接。该配置会影响Re-use connection,如果选中Close connection则无论Re-use connection是否选中,都会在请求结束后关闭连接,而下一次请求重新创建一个连接。也就是Re-use connection配置无效。
Set NoDelay:选中则禁用 Nagle算法,与TCP协议的缓存有关的算法。简单讲就是,是立即发送数据,还是缓存一会儿收集一个大包再发送。有实时性要求的系统设置NoDelay,默认是关闭的(就是默认的TCP协议启用Nagle算法)。
SO_LINGER:TCP协议中的延迟关闭时间,具体参考TCP协议。简单讲就是客户端要关闭连接时,是否要等待以秒为单位的时间。默认不配置或者配置为0,可以防止服务端维持大量处于TIME_WAIT状态的连接。
End of line(EOL) byte value:结束字符配置,与配置文件中的tcp.eolByte一个作用。
4.3 脚本结果验证
配置完成后,进行一次简单的测试,模拟一个设备10条业务推送5次的情况,通过抓包看结果如下:
可以明确的看到三次握手,5次推送和ACK以及最后的断开连接的过程。通过数据库查看结果与预期一致。就像真的一样,完成了模拟的使命。
4.5 遇到主要问题:BinaryTCPClientImpl重写
实际脚本开发中遇到很多问题,其中改写BinaryTCPClientImpl是比较费劲的一个。改写本身很简单,问题是为什么改写。先上一个使用BinaryTCPClientImpl的测试结果:
查看数据库,实际的数据已经入库了,但是JMeter报错,是什么原因呢?在JMeter官网上对TCP Sample有如下说明:
TCP Sample与指定的服务器简历TCP/IP连接,发送指定文本并且等待响应。
而被测系统在收到推送的数据后,只会发送ACK确认收到,但不会给出任何响应。而TCP Sample需要一直等待读取到数据,ACK仅是自己发送成功的确认,不是响应。在网上查找很多资料后,终于在如下网址中获得答案:
https://stackoverflow.com/questions/24825064/how-to-make-jmeters-binarytcpclientimpl-accept-ack。
所以只好重写BinaryTCPClientImpl,实际的代码非常简单,其余工作都有父类完成,重写read函数,直接返回。
看完本文有收获?请分享给更多人
关注水滴测试,不知不觉变大牛
领取专属 10元无门槛券
私享最新 技术干货