☰
基于 Voovan 的 Java Web 框架性能基准测试接入指南:从测试路由到源码调优
2026/10/15 6:01:28 网站建设 项目流程
  • 性能测试
  • 测试
  • 后端
  • 开发者工具

【免费下载链接】FrameworkBenchmarks

Source for the TechEmpower Framework Benchmarks project

项目地址:https://gitcode.com/gh_mirrors/fr/FrameworkBenchmarks
点击查看免费下载

Voovan 是 TechEmpower Framework Benchmarks(TFB)中 Java 平台分类下的一款 Web 框架测试实现,其相关说明文档位于 frameworks/Java/voovan/README.md。本文以该文档为主线,结合仓库内的基准测试配置、Java 源码、构建脚本与工具集实现,完整讲解 Voovan 在 TFB 中的接入方式:包括/json与/plaintext两个测试接口的 URL 约定、服务端路由的源码实现、运行时 JVM 参数与框架配置文件的调优要点,以及 TFB 工具集如何校验与压测这些接口。读完本文,你将能够理解并复现一个 Java Web 框架接入 TFB 基准测试的完整链路,并掌握 Voovan 服务端在性能测试场景下的关键配置项。

Voovan 在 FrameworkBenchmarks 中的定位

TechEmpower Framework Benchmarks 是一个用于横向比较各类 Web 开发平台性能的开源项目,项目源码位于本仓库根目录。Voovan 以 Java 平台成员的身份参与其中,其测试入口定义在 benchmark_config.json 中:

{ "framework": "voovan", "tests": [{ "default": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", "database": "None", "framework": "voovan", "language": "Java", "flavor": "None", "orm": "None", "platform": "Voovan", "webserver": "None", "os": "Linux", "database_os": "Linux", "display_name": "voovan-mvc", "notes": "voovan webserver with mvc" } }] }

该配置说明了 Voovan 测试的三项关键事实:

  • 测试类型:仅参与 JSON 编码与 Plaintext 编码两类无数据库测试,database与orm均为None;
  • 网络端口:固定监听8080端口,这也是整个仓库绝大多数框架测试的默认端口约定;
  • 定位分类:approach为Realistic(真实场景)、classification为Platform(平台级)、webserver为None(Voovan 自带 WebServer,不依赖外部服务器),display_name标注为voovan-mvc,即"Voovan WebServer + MVC"的组合。

与此对应,config.toml 以 TOML 形式记录了同一份元信息,供工具集内部解析使用,两处文件的字段一一对应。

版本差异说明

原 README 记录的版本为Java OpenJDK 1.8与Voovan 4.2.x。不过以当前仓库实际内容为准:构建阶段基于maven:3-eclipse-temurin-24-alpine镜像,运行阶段基于amazoncorretto:25镜像,而 pom.xml 中声明的 Voovan 框架版本为4.3.8,maven.compiler.source/target均为17。这意味着该测试实现实际面向的是较新的 JDK 与 Voovan 版本,README 中的版本描述属于历史记录,阅读时应以仓库源码为准。

测试 URL 约定

Voovan 参与的两项测试 URL 定义在 README 中,原文记录如下:

JSON Encoding Test

http://localhost:8080/json

Plaintext Encoding Test

http://localhost:8080/plaintext

这两个 URL 与benchmark_config.json中的json_url、plaintext_url字段严格对应。工具集在验证阶段会以http://{server_host}:{port}{url}的形式拼接请求地址(见 framework_test.py),因此端口 8080 与路由路径必须与配置保持完全一致,否则验证将直接失败。

服务端源码实现解析

Voovan 测试服务的全部业务逻辑集中在单个入口类 VoovanTFB.java 中,主类结构清晰:先构建并调优WebServerConfig,再注册两条路由,最后启动服务。

WebServer 配置调优

TReflect.register(Message.class); WebServerConfig webServerConfig = WebContext.buildWebServerConfig(); webServerConfig.setGzip(false); webServerConfig.setAccessLog(false); webServerConfig.setKeepAliveTimeout(1000); webServerConfig.setHost("0.0.0.0"); webServerConfig.setPort(8080); webServerConfig.setHotSwapInterval(0); webServerConfig.setCache(true); webServerConfig.getModuleConfigs().clear(); webServerConfig.getRouterConfigs().clear(); webServerConfig.setEnablePathVariables(false); webServerConfig.setEnableWebSocket(false); WebServer webServer = WebServer.newInstance(webServerConfig);

这些配置项对基准测试性能有直接影响,逐项说明:

  • setGzip(false):关闭 Gzip 压缩。基准测试响应体极小,压缩反而引入 CPU 开销与响应头变化;
  • setAccessLog(false):关闭访问日志,避免高并发下的磁盘 I/O 与锁竞争;
  • setKeepAliveTimeout(1000):Keep-Alive 超时设为 1000 毫秒,配合 wrk 压测脚本的 keep-alive 连接策略;
  • setHost("0.0.0.0")/setPort(8080):监听所有网卡接口的 8080 端口,保证容器内服务可被外部压测客户端访问;
  • setHotSwapInterval(0):关闭热部署扫描间隔,避免运行期的文件监听开销;
  • setCache(true):开启框架缓存;
  • getModuleConfigs().clear()/getRouterConfigs().clear():清空默认模块与默认路由,从源码结构看,这是为了剔除 Voovan 框架自带的路由分发与模块处理逻辑,让服务仅保留基准测试所需的最小处理链路;
  • setEnablePathVariables(false)/setEnableWebSocket(false):关闭路径变量解析与 WebSocket 支持,进一步削减每请求的处理开销。

WebContext.buildWebServerConfig()会读取 config/framework.properties 作为基础配置,上述代码再在内存中覆盖关键项。

路由注册与响应实现

// 性能测试请求; webServer.get("/plaintext", new HttpRouter() { public void process(HttpRequest req, HttpResponse resp) throws Exception { resp.header().put(HttpStatic.CONTENT_TYPE_STRING, HttpStatic.TEXT_PLAIN_STRING); resp.write(HELLO_WORLD_BYTES); } }); // 性能测试请求 webServer.get("/json", new HttpRouter() { public void process(HttpRequest req, HttpResponse resp) throws Exception { resp.header().put(HttpStatic.CONTENT_TYPE_STRING, HttpStatic.APPLICATION_JSON_STRING); resp.write(TString.toAsciiBytes(JSON.toJSON(new Message(HELLO_WORLD_STR), false, false))); } });

Plaintext 接口:设置Content-Type: text/plain响应头后,直接写出预编译的字节数组HELLO_WORLD_BYTES("Hello, World!".getBytes())。将字符串预编码为字节数组、每次请求复用同一份数组,避免重复的编码操作,这是 Web 框架 benchmark 中常见的优化手段。

JSON 接口:设置Content-Type: application/json后,构造一个Message对象并调用 Voovan 的 JSON 工具类序列化:

JSON.toJSON(new Message(HELLO_WORLD_STR), false, false)

Message是一个包含message私有字段与getMessage()取值方法的 POJO:

public static class Message { private final String message; public Message(String message) { this.message = message; } public String getMessage() { return message; } public int hashCode(){ return 98821452; } }

注意main方法开头调用了TReflect.register(Message.class),从源码结构看,这是向 Voovan 的反射工具注册该类型,使 JSON 序列化能够按反射元数据高效处理该 POJO,避免重复解析类结构。

序列化结果再经TString.toAsciiBytes(...)转为字节数组写出,最终响应体为{"message":"Hello, World!"}形式(JSON.toJSON的后两个布尔参数分别控制是否格式化与是否转义,此处均传false以输出最紧凑的 JSON)。

服务启动

Logger.setEnable(false); webServer.serve();

Logger.setEnable(false)关闭框架日志输出(与配置中的setAccessLog(false)互为补充),随后webServer.serve()阻塞启动服务。整个 main 方法即构成一个可直接java -jar运行的独立服务。

框架核心配置文件详解

config/framework.properties 是 Voovan 框架的全局配置,由WebContext.buildWebServerConfig()加载。该文件内每项配置均带有原始注释说明,完整整理如下:

配置项当前值框架默认值说明
NoHeapManualReleasetruetrue为true时框架会立即手动释放无堆内存
NoHeapReleaseInterval60030无堆对象被回收后,每隔该间隔(秒)释放一次无堆内存
ThreadPoolMinSize12每个 CPU 核心对应的线程池最小线程数
ThreadPoolMaxSize150每个 CPU 核心对应的线程池最大线程数
ThreadPoolStatusInterval01000线程池状态日志输出间隔(毫秒),0表示关闭
ByteBufferChannelMaxSize209715201024*1024*2ByteBufferChannel 最大容量(字节),当前约为默认值的 10 倍
SerializeTypeJDKJDK缓存使用的序列化方式,可选JDK或JSON
JSONConvertEscapeCharfalsetrue为false时 JSON 中的\f \b \r \n \t等转义字符不做 unicode 转换
RemoteClassSource(注释掉)-远程类源码位置,形如127.0.0.1:3001,当前未启用

其中两个线程池参数取值为1,表示每个 CPU 核心仅保留 1 个线程。从注释"one cpu core's min/max thread size"可以推断,Voovan 的线程池按 CPU 核心数伸缩;JSONConvertEscapeChar=false则保证 JSON 响应体保持最小的转义处理、输出最紧凑的字节。该文件在运行时通过-cp ./config置于 classpath 下(见下节 Dockerfile 的 CMD),因此修改参数后无需重新编译。

构建与运行:Dockerfile 与 JVM 参数

voovan.dockerfile 采用多阶段构建:

FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /voovan COPY pom.xml pom.xml COPY src src COPY config/framework.properties config/framework.properties RUN mvn package -q FROM amazoncorretto:25 WORKDIR /voovan COPY --from=maven /voovan/target/voovan-bench-0.1-jar-with-dependencies.jar app.jar COPY --from=maven /voovan/config/framework.properties config/framework.properties EXPOSE 8080

第一阶段在maven:3-eclipse-temurin-24-alpine中执行mvn package -q。这里依赖 pom.xml 中配置的maven-assembly-plugin,其jar-with-dependencies描述符会将 Voovan 框架依赖一并打入voovan-bench-0.1-jar-with-dependencies.jar,产出可直接运行的 fat jar。第二阶段使用amazoncorretto:25作为运行镜像,仅拷贝构建产物与配置文件,并声明EXPOSE 8080。

容器启动命令(CMD)是性能调优的核心:

java -DCheckTimeout=false \ -DThreadBufferPoolSize=1024 \ -DByteBufferSize=4096 \ -DAsyncSend=false \ -DAsyncRecive=false \ -DByteBufferAnalysis=-1 \ -DServer=v \ -server -Xms2g -Xmx2g \ -XX:+DoEscapeAnalysis \ -XX:+AlwaysPreTouch \ -XX:-RestrictContended \ -XX:+UseParallelGC -XX:+UseNUMA \ --add-opens java.base/java.lang=ALL-UNNAMED \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.io=ALL-UNNAMED \ --add-opens java.base/java.nio=ALL-UNNAMED \ --add-opens java.base/sun.nio.ch=ALL-UNNAMED \ --add-opens java.base/java.security=ALL-UNNAMED \ --add-opens java.base/java.util.concurrent=ALL-UNNAMED \ --add-opens java.base/java.net=ALL-UNNAMED \ -cp ./config:voovan.jar:app.jar org.voovan.VoovanTFB

各参数的作用可从命名与上下文合理推断:

  • Voovan 框架系统属性:-DCheckTimeout=false关闭连接超时检查;-DThreadBufferPoolSize=1024设置线程缓冲池容量;-DByteBufferSize=4096设置 ByteBuffer 初始大小;-DAsyncSend=false与-DAsyncRecive=false关闭异步收发(原样拼写即AsyncRecive);-DByteBufferAnalysis=-1关闭缓冲区分析;-DServer=v指定服务器实现标识;
  • JVM 堆与内存:-server -Xms2g -Xmx2g将堆最小/最大值固定为 2G(避免运行期堆扩容抖动);-XX:+AlwaysPreTouch在启动阶段即预提交全部堆内存页;
  • GC 与并发:-XX:+UseParallelGC选用吞吐优先的并行回收器;-XX:+UseNUMA启用 NUMA 感知内存分配;-XX:+DoEscapeAnalysis开启逃逸分析(利于栈上分配);-XX:-RestrictContended放宽@Contended注解的默认限制;
  • 模块开放:一批--add-opens java.base/...=ALL-UNNAMED用于在较新 JDK 上放开 Voovan 框架反射访问java.lang、java.util、java.nio、sun.nio.ch等内部包所需的权限(新 JDK 强封装限制下常见做法);
  • 启动入口:-cp ./config:voovan.jar:app.jar org.voovan.VoovanTFB将配置目录与依赖 jar 加入 classpath,以org.voovan.VoovanTFB作为主类启动。

工具集如何校验这两个接口

TFB 工具集对 Voovan 的验证逻辑由 json.py 与 plaintext.py 两个测试类型驱动,它们从benchmark_config.json中读取json_url与plaintext_url参数(见 abstract_test_type.py)。

JSON 测试的校验规则

json.py的verify方法按顺序执行:

  1. 以Accept: application/json,...头发起请求并读取响应;
  2. 通过basic_body_verification检查响应非空且可被json.loads解析;
  3. 通过verify_helloworld_object校验响应对象——要求包含message键、值不区分大小写地等于hello, world!,多余键值对与多余空白字节会给出warn(详见 verifications.py);
  4. 通过verify_headers检查必须存在Server、Date、Content-Type头以及Content-Length或Transfer-Encoding头,且Content-Type须匹配^application/json(; ?charset=(UTF|utf)-8)?$正则;同时会间隔 3 秒请求两次,校验Date头未被缓存(详见 verifications.py)。

这意味着 Voovan 的/json实现必须在Content-Type中使用application/json(Voovan 的HttpStatic.APPLICATION_JSON_STRING恰好满足),且响应体中不得包含多余字段。

Plaintext 测试的校验规则

plaintext.py的verify方法则要求:

  • 响应非空;
  • 响应体转小写后须包含hello, world!子串,返回的额外字节数超过 0 会触发warn(提示可能影响性能);
  • Content-Type匹配^text/plain(; ?charset=(UTF|utf)-8)?$;
  • 状态码为 200,头部要求与 JSON 测试相同。

这正是 Voovan 的/plaintext路由直接写出"Hello, World!"字节数组的原因——响应体被精确控制在最少字节数。

压测脚本

验证通过后,工具集调用 wrk 进行压测:JSON 测试使用 concurrency.sh(固定Accept头、先 primer 后 warmup、再按 concurrency level 阶梯压测),Plaintext 测试使用 pipeline.sh(额外加载pipeline.lua,以 16 级 HTTP 管线深度压测),两者均以Connection: keep-alive请求 Voovan 的 8080 端口。这也解释了源码中setKeepAliveTimeout(1000)与端口 8080 的配置来源。

本地手动验证

不依赖 TFB 工具集时,可以手动复现 Voovan 测试服务的验证过程。构建并启动容器后,分别执行:

# JSON 接口 curl -v http://localhost:8080/json # Plaintext 接口 curl -v http://localhost:8080/plaintext

JSON 接口应返回Content-Type: application/json与{"message":"Hello, World!"}响应体;Plaintext 接口应返回Content-Type: text/plain与Hello, World!响应体。之后可用 wrk 发起与工具集一致的压测,例如:

wrk -H "Host: localhost" -H "Accept: text/plain,text/html;q=0.9,*/*;q=0.7" \ -H "Connection: keep-alive" --latency -d 15 -c 512 -t 16 \ http://localhost:8080/plaintext

这也是理解 Voovan 在 TFB 中成绩构成的最直接方式——两个接口响应体极小、无数据库参与、无外部 WebServer 层,测得的吞吐与延迟基本反映 Voovan WebServer 与 JVM 本身的数据处理能力。

小结

Voovan 在 FrameworkBenchmarks 中的实现是一个"最小化、可复现"的基准测试范本:README 定义 URL 约定,benchmark_config.json声明测试元数据,VoovanTFB.java用约 80 行代码完成配置调优与路由注册,framework.properties与 Dockerfile 的 JVM 参数共同决定运行时行为,而工具集则以严格的头部/响应体校验保证所有参赛框架在同一规则下被测。理解这条链路,即可举一反三地将任意 Java Web 框架接入该基准测试体系。

  • 性能测试
  • 测试
  • 后端
  • 开发者工具

【免费下载链接】FrameworkBenchmarks

Source for the TechEmpower Framework Benchmarks project

项目地址:https://gitcode.com/gh_mirrors/fr/FrameworkBenchmarks
点击查看免费下载

相关推荐

上一篇:Ladybird浏览器高级构建指南:深入构建与调试技巧
下一篇:如何永久保存微信聊天记录?简单三步实现数据主权掌控

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询