异步接口性能测试方案中关键技术设计优化与实践
2023-09-04孙立哲
孙 立 哲
(公安部第三研究所 上海 201204)
0 引 言
前期在异步接口性能测试方面做了一些初步性探索工作,并以HTTP异步接口为例设计一种能够覆盖异步接口内部完整业务流程的性能测试方案[1]。该性能测试方案的核心思想是在待测异步接口中增加将请求数据和异步响应数据分别写入不同数据库表的处理逻辑,并在压测结束后通过对数据库表中请求数据和响应数据作比对统计分析,以评估异步接口完整业务下的性能情况。该方案覆盖了异步接口内部完整业务处理流程,能对整体性能表现作出较为全面的评测。但尚未对方案中所涉及的关键技术以及这些技术实现是否会对待测异步接口原有性能表现产生影响等作较为深入的设计优化研究与实践验证。这些关键技术主要表现在两方面,一是异步接口中增加的数据入库模块;二是对库中数据作快速统计分析的模块。本文重点针对这些技术及其影响做进一步的技术探索与实践验证。
1 数据入库设计与验证
1.1 设计思路
采用Hibernate框架对象持久化技术[2]、EJB组件封装与依赖注入[3]、线程池与多线程并发技术[4-5]来实现将数据写入数据库。
首先,以Hibernate框架对象持久化技术实现对Java对象数据与数据库表字段映射,以及与数据库之间的连接与数据访问操作执行。Hibernate是一个开源的对象关系映射框架,它实现了对数据库连接轻量级的对象封装,能提供高性能的对象关系型持久化存储和查询服务[6]。
其次,采用EJB组件封装技术将对数据库的增删改查等操作封装成接口,通过调用EJB组件接口触发对数据库的操作。采用EJB依赖注入技术将已封装好的接口注入异步接口内,异步接口内以直接调用EJB接口的方式完成对数据库表数据的写入。EJB是服务端组件模型,设计目标与核心应用是部署分布式应用程序。EJB容器(如JBoss)提供了对象池和缓存机制,没有事务机制的无状态Session Bean比普通JavaBeans具有更强的性能。
采用线程池,根据实际需求创建一定数量的线程数,把向数据库写数据的操作放入线程池以多线程的方式去执行,降低数据库操作对异步接口自身性能的影响。在高并发场景下,可通过调整线程数来调整性能表现。线程池及各线程在异步接口服务程序部署启动时创建。异步接口将写数据的任务传给线程池时,线程池将任务分配给一个线程来执行。任务执行结束后,该线程返回线程池中成为空闲状态,等待执行下一个任务。线程池多线程处理机制具有很好的性能优势。
1.2 具体实现
与用于记录数据的各数据库表对应,创建实体类。采用JPA对象持久化技术建立实体类与数据库表的映射关系。采用EntityManager接口实现对Java对象到数据库表的写入操作。EntityManager是JPA中用于对数据库表数据进行增删改查的接口,连接内存中的Java对象和数据库的数据存储[7]。采用EntityManager的persist方法和flush方法将实体类对象持久化写入数据库表。用EJB本地接口封装对数据库表的操作。以EJB依赖注入的方式将EJB接口实例注入异步接口,异步接口内调用EJB接口实例的各方法来完成对数据库表的操作。采用Java开发工具包中Executors类的newFixedThreadPool方法创建线程池。将写入数据库的操作单独封装为一个数据库写入方法。在异步接口实现类中新建内部类并实现Runnable接口,在覆写的run方法中调用外部类的数据库写入方法,以新建内部类对象的方式新建线程并放入线程池。以一级异步接口为例,写数据入对应数据库表的类图如图1所示。
图1 一级异步接口写数据入数据库表类图
以一级异步接口为例,具体实现:
1) 定义实体类,实现持久化。与请求表和响应表相对应,创建两个实现序列化接口的实体类,记为请求实体类和响应实体类。两个实体类中定义各属性,分别对应表中各字段,并在各字段前添加相应注释,如唯一自增注释。创建两个普通类,记为请求类和响应类,分别对应请求实体类和响应实体类,普通类中属性分别对应实体类中除唯一自增属性之外的其他各属性。
2) 定义EJB接口,用于封装将实体类数据持久化写入数据库的操作。创建两个EJB接口,记为请求接口和响应接口,接口中声明数据写入方法,方法入参类型分别为请求类类型和响应类类型。创建两个EJB无状态Session Bean类,记为EJB请求类和EJB响应类,分别实现请求接口和响应接口,类前加无状态注释,加PersistenceContext依赖注入EntityManager实例,PersistenceContext依赖中的“持久化单元名”与配置文件persistent.xml中定义的持久化单元persistence-unit的name属性值一致。在ds.xml文件中配置MySQL数据源,然后在persistent.xml文件中引入该数据源。ds.xml文件与异步接口部署在相同目录下。实现接口中声明的数据写入方法,方法中将入参类对象作数据转换转为对应的实体类对象,调用EntityManager实例的persist方法和flush方法将实体类对象数据写入数据库表。
3) 在异步接口中加依赖注入EJB接口实例,并以线程池多线程方式调用EJB接口实例的数据库写入方法。在异步接口中依赖方式注入EJB实例时,异步接口需设为EJB组件接口。在异步接口中加EJB注释引入EJB请求类实例和EJB响应类实例。创建.properties属性配置文件,在配置文件中设定线程池线程数。创建线程池工具类,类中读取配置文件获取线程数,并在类加载时自动创建静态线程池及各线程。在异步接口实现类中,将调用EJB接口实例方法进行数据库写入的操作单独封装为一个数据库写入方法,方法内调用EJB请求类实例对象的数据写入方法和EJB响应类实例对象的数据写入方法。在异步接口实现类中新建内部类并实现Runnable接口,在覆写的run方法中调用外部类的数据库写入方法。在异步接口内部作异步响应返回前,获取线程池工具类中预创建的静态线程池,以新建内部类对象的方式新建线程并放入线程池中执行。
1.3 性能验证
基于以上设计与实现,以HTTP异步接口为例,对异步接口分将数据写入数据库和不写数据库两种场景作性能对比验证测试。测试环境整体架构如图2所示。
图2 性能测试环境整体架构
异步接口请求数据与响应数据均采用序列化的JSON(JavaScript Object Notation)字符串格式。请求数据串中包含业务请求时间、业务流水号、其他特定业务数据键值对。异步响应数据串中包含异步响应时间、业务流水号、业务处理结果、其他特定业务处理结果数据键值对。响应串中业务流水号与对应的请求串中业务流水号一致。请求数据表中每一条请求串都能在响应数据表中找到唯一响应数据记录,说明所有请求均被成功响应。
验证测试时,请求数据业务请求时间取压测客户端当前系统时间并精确到毫秒级。采用随机生成通用唯一标识作为业务流水号,确保每个请求具有唯一性业务流水号。响应数据业务响应时间取服务端当前系统时间。服务端系统时间与压测客户端系统时间同步。异步接口内每个响应数据的业务流水号取其对应请求数据的业务流水号。请求数据与响应数据中其他特定业务数据采用固定数据。
压测过程中按上述格式及方式准备请求数据串请求异步接口。
验证环境为:
1) 数据库所在服务器硬件配置为8核处理器、16 GB内存、300 GB硬盘。
2) 异步接口部署所在服务器硬件配置为8核处理器、16 GB内存、300 GB硬盘。
3) 异步回调接口部署所在服务器硬件配置为4核处理器、8 GB内存、300 GB硬盘。
4) JMeter所在压测客户机硬件配置为8核处理器、16 GB内存、200 GB硬盘。
5) 整套环境通过一个千兆以太网交换机部署在同一局域网内。
验证结果如下:
在并发数相同以及客户端和服务端处理器、内存等系统资源未出现资源耗尽等性能瓶颈情况下,客户端压测并发数和服务端线程池线程数配置均为70,不写数据库时异步接口每秒处理请求数2 824.8次,写数据库时异步接口每秒处理请求数2 473.9次。对比结果显示,写数据库时异步接口性能有略微下降。但相比而言,增加写数据库处理逻辑对异步接口原有性能产生的影响不大。
2 数据统计设计优化与验证
2.1 设计思路
前期设计实现的数据统计分析程序可以对请求数据与响应数据作出正确的统计分析。但因采用的是单线程处理,且数据库表未创建索引,在数据量较大的情况下,统计分析执行过程耗时会比较长。为了提高统计分析执行速率,采用数据库表索引、线程池和多线程并发技术作进一步的设计优化。索引的合理创建可提高数据库表数据的查询检索速度[8],线程池多线程并发技术可实现对数据分组作并行查询比对,从而提高统计分析执行速率。
数据统计分析过程中,对请求表作数据查询时的检索条件是唯一属性字段。唯一属性字段本身是一种特殊的主键索引[9],因此数据检索速度会比较快。对响应表作数据查询时的检索条件为业务流水号,业务流水号默认不是主键,也没有对应的索引,因此,对响应表的数据查询速度会比较慢。故对响应表增加业务流水号字段索引,以提高表数据检索速度。
在统计分析过程中,数据比对是从请求表中根据唯一属性自增字段依序提取请求数据,然后根据请求数据中业务流水号与响应表中数据作查询并比对。请求表中不同的请求数据之间没有关联关系,请求表中数据与响应表中数据预期存在一一对应关系。在同一时间可以并行地在不同的线程中分别对不同的数据作查询比对。因此,可引入线程池多线程来实现并行处理,从而减少统计分析时间。将请求数据按照唯一属性自增字段作分组,对不同分组分别同时在不同线程进行独立统计分析,并记录分组内统计分析结果。在所有线程全部执行结束后,对各分组内统计分析结果再作汇总统计。
2.2 具体实现
创建.properties属性配置文件,在文件中设定数据分组长度,分组长度表示分组内的数据个数。统计分析程序读取配置文件,获取分组长度,将所有请求数据按分组长度作分组。若请求数据总数是分组长度的整数倍,则请求数据总数除以分组长度所得整数即为分组个数。若请求数据总数非分组长度的整数倍,则请求数据总数除以分组长度所得整数再加一即为分组个数。如果请求数据总数小于等于分组长度,则以单线程作统计分析,如果请求数据总数大于分组长度,则以多线程分组作统计分析。以分组个数作为线程数,创建线程池。一个线程对应一个分组,单个分组内的数据统计分析在一个线程中执行,不同分组在不同线程中并行执行。对每个分组中各请求数据根据唯一属性自增字段值按顺序逐一提取并与响应表中数据作查询比对,分别统计各分组内的请求成功数、请求失败数、平均响应时间、最小响应耗时、最大响应耗时,并将每个分组的统计结果分别记录在不同的文件内,一个分组对应一个文件。所有线程执行结束后,对各分组统计分析结果作汇总集成统计,得出总请求成功数、总请求失败数、总平均响应时间、总最小响应耗时、总最大响应耗时。多线程统计分析处理逻辑流程如图3所示,分组统计子流程如图4所示。
图3 多线程统计分析处理逻辑流程
图4 分组统计子流程
线程池中线程数与分组个数相同,分组个数取决于配置文件中分组长度设定值。因此,在总请求数一定的情况下,配置文件中设定的分组长度越小,线程数越多,分组长度越大,线程数越少。线程数过少,统计分析执行耗时越接近单线程处理耗时,耗时会比较久。线程数过多,统计分析程序执行时会过多地占用系统资源,系统资源耗尽时会影响统计分析程序的执行速率。合理设定数据分组长度,才能使统计分析程序达到较优的性能。
2.3 性能验证
基于以上设计优化与实现,对数据统计分析程序作优化前后的性能对比验证测试。
统计分析过程中所用数据为异步接口性能压测时分别写入请求数据表和响应数据表中的数据。
验证环境如下:
1) 统计分析程序所在客户机硬件配置为8核处理器、16 GB内存、200 GB硬盘。
2) 数据库服务所在服务器硬件配置为4核处理器、8 GB内存、60 GB硬盘。
3) 客户机与服务器在同一局域网内。
验证结果如下:
1) 总请求数为479 400时,优化前的单线程统计分析耗时为385.77 s,优化后的多线程统计分析耗时为183.53 s。
2) 总请求数为741 812时,优化前的单线程统计分析耗时为829.16 s,优化后的多线程统计分析耗时为317.97 s。
3) 总请求数为1 531 640时,优化前的单线程统计分析耗时为1 726.97 s,优化后的多线程统计分析耗时为603.48 s。
对比结果显示,优化后的基于多线程并发技术的统计分析程序执行速率提升显著。
3 结 语
本文在前期进行的关于异步接口性能测试方案设计基础上,针对方案中所涉及的一些关键技术点,作了进一步的设计优化研究与实践验证。主要表现在两方面,一方面是采用Hibernate框架JPA对象持久化技术、EJB组件封装与依赖注入、线程池与多线程并发技术,对异步接口数据写入数据库模块作了优化设计与实现以及验证测试,另一方面是采用数据库表索引、线程池与多线程并发处理等技术对数据统计分析程序作了优化设计与实现以及对比验证测试。验证结果显示,本文做优化设计并实现的异步接口数据写入数据库的模块性能表现良好,对异步接口原有性能影响较小,优化后的数据统计分析程序相比优化前在执行速率上提升了1~2倍,性能提升较明显。