比较分别使用虚拟线程的SpringBoot和使用Actix框架的Rust来实现QR码生成器API。
微信搜索关注《Java学研大本营》
本文重点比较使用虚拟线程的SpringBoot和使用Actix框架的Rust,来实现QR码生成器API。这两种技术都是成熟的,无需进一步介绍。接下来,让我们直接深入测试设置的细节。

1 测试设置
1.1 环境
所有测试都在装有16GB RAM的MacBook Pro M1上进行。使用的测试工具是Bombardier的定制版本,支持在请求体中包含随机URL。这些测试使用的软件版本如下:
-
SpringBoot 3.1.3,带有Java v20(启用预览以获取虚拟线程)
-
Rust 1.72.0
1.2 代码
这个QR码生成器应用程序被设计成接收一个JSON请求体,其中包含一个名为"urlToEmbed"的必需参数。该应用程序的主要功能是为指定的URL生成一个QR码,并在HTTP响应中以PNG格式传送QR码。为增加复杂性,该应用程序在HTTPS上运行。
SpringBoot(虚拟线程)
- server.port=3000
- server.ssl.certificate=/Users/mayankc/Work/source/certs/cert.pem
- server.ssl.certificate-private-key=/Users/mayankc/Work/source/certs/key.pem
- package com.example.qr;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
- import org.springframework.context.annotation.Bean;
- import java.util.concurrent.Executors;
-
- @SpringBootApplication
- public class QrApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(QrApplication.class, args);
- }
-
- @Bean
- public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
- return protocolHandler -> {
- protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
- };
- }
- }
- package com.example.qr;
-
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.http.ResponseEntity;
- import org.springframework.http.HttpStatus;
- import org.springframework.http.HttpHeaders;
- import org.springframework.web.bind.annotation.RestController;
- import java.util.Optional;
- import com.example.qr.QrRequest;
- import com.example.qr.QrGenerator;
-
- @RestController
- public class QrController {
-
- @PostMapping("/qr")
- public ResponseEntity handleRequest(@RequestBody QrRequest qrRequest) {
- if(qrRequest.getUrlToEmbed() == null) {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
- }
-
- try {
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.add(HttpHeaders.CONTENT_TYPE, "image/png");
- return new ResponseEntity<byte[]>(
- QrGenerator.generateQR(qrRequest.getUrlToEmbed(), 512, 512),
- httpHeaders,
- HttpStatus.OK);
- } catch (Exception e) {
- return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
- }
- }
- }
- package com.example.qr;
-
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
-
- import com.google.zxing.BarcodeFormat;
- import com.google.zxing.WriterException;
- import com.google.zxing.client.j2se.MatrixToImageConfig;
- import com.google.zxing.client.j2se.MatrixToImageWriter;
- import com.google.zxing.common.BitMatrix;
- import com.google.zxing.qrcode.QRCodeWriter;
-
- public class QrGenerator {
-
- public static byte[] generateQR(String text, int width, int height) throws WriterException, IOException {
- QRCodeWriter qrCodeWriter = new QRCodeWriter();
- BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
-
- ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
- MatrixToImageConfig con = new MatrixToImageConfig() ;
-
- MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream, con);
- byte[] pngData = pngOutputStream.toByteArray();
- return pngData;
- }
- }
- package com.example.qr;
-
- public class QrRequest {
- private String urlToEmbed;
-
- public String getUrlToEmbed() {
- return this.urlToEmbed;
- }
-
- public void setUrlToEmbed(String urlToEmbed) {
- this.urlToEmbed = urlToEmbed;
- }
- }
Rust
- [package]
- name = "actix_qr_generator"
- version = "0.1.0"
- edition = "2021"
-
- [dependencies]
- actix-web = { version = "4", features = ["openssl"] }
- qrcode-generator = "4.1.8"
- serde = { version = "1.0", features = ["derive"] }
- serde_json = "1"
- openssl = { version = "0.10" , features = ["vendored"] }
- use actix_web::{web, post, App, HttpServer, HttpResponse, Responder};
- use qrcode_generator::QrCodeEcc;
- use serde::Deserialize;
- use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
-
- #[derive(Deserialize)]
- struct QrRequest {
- urlToEmbed: String,
- }
-
- #[post("/qr")]
- async fn generate_qr(qr_request: web::Json<QrRequest>) -> impl Responder {
- if qr_request.urlToEmbed.is_empty() {
- return HttpResponse::BadRequest().into();
- }
-
-
- let result: Vec<u8> = qrcode_generator::to_png_to_vec(qr_request.urlToEmbed.clone(), QrCodeEcc::Low, 512)
- .unwrap();
- return HttpResponse::Ok()
- .content_type("image/png")
- .body(result);
- }
-
- #[actix_web::main]
- async fn main() -> std::io::Result<()> {
- let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
- builder
- .set_private_key_file("/Users/mayankc/Work/source/perfComparisons/certs/key.pem", SslFiletype::PEM)
- .unwrap();
- builder
- .set_certificate_chain_file("/Users/mayankc/Work/source/perfComparisons/certs/cert.pem")
- .unwrap();
-
- HttpServer::new(|| App::new().service(generate_qr))
- .bind_openssl("127.0.0.1:3000", builder)?
- .run()
- .await
- }
-
-
- // 注意 ================================================
- // 该应用程序已在发布模式下构建。
- // =====================================================
2 结果
为了全面评估性能,这里进行了一系列细致的检查。每个检查包括10万个请求,并在10、50和100个并发连接的范围内评估它们的效率。考虑到QR码生成的资源密集型特性,故意保持了稍低的请求量,与其他场景相比。
结果如下:



根据以下公式,还生成了一个得分卡。对于每个测量,获取获胜的差距。如果获胜的差距是:
-
< 5%,不给予任何分数
-
在5%到20%之间,获胜者得1分
-
在20%到50%之间,获胜者得2分
-
50%,获胜者得3分
得分卡如下:


推荐书单
《名师讲坛:Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》
Java微服务架构是当下流行的软件架构设计方案,可以快速地进行代码编写与开发,维护起来也非常方便。利用微架构技术,可以轻松地实现高可用、分布式、高性能的项目结构开发,同时也更加安全。 《名师讲坛:Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》一共15章,核心内容为SpringBoot、SpringCloud、Docker、RabbitMQ消息组件。其中,SpringBoot 是SpringMVC技术的延伸,使用它进行程序开发会更简单,服务整合也会更容易。SpringCloud是当前微架构的核心技术方案,属于SpringBoot的技术延伸,它可以整合云服务,基于RabbitMQ和GITHUB进行微服务管理。除此以外,该书还重点分析了OAuth统一认证服务的应用。 《名师讲坛:Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》适用于从事Java开发且有架构与项目重构需求的读者,也适用于相关技术爱好者,同时也可作为应用型高等院校及培训机构的学习教材。
《名师讲坛:Java微服务架构实战(SpringBoot+SpringCloud+Docker+RabbitMQ)》
https://item.jd.com/12793864.html

精彩回顾
只需5步,将Spring Boot服务迁移到Kubernetes
微信搜索关注《Java学研大本营》
访问【IT今日热榜】,发现每日技术热点