IDEA中Quarkus框架(3.13版本)容器编排、压测与调优、注意事项等
Quarkus框架学习的第一部分,请访问:
IDEA中Quarkus框架(3.13版本)开发、调试、部署、打包等
五、docker-compose容器编排
1、创建编排文件
cd quarkus-helloworldvi docker-compose.yml
docker-compose.yml内容如下:
# yaml 配置实例
version: '3'
services:quarkus-hello-world:image: quarkus/code-with-quarkus:latest # docker中已存在的镜像名+版本名ports:- "8080:8080" # 主机Port: 容器暴露Portenvironment:TZ: Asia/Shanghai deploy:replicas: 2update_config:parallelism: 2delay: 1srestart_policy:condition: on-failurevolumes:logvolume01: {}
2 docker-compose启动(单实例):
cd quarkus-helloworld
docker-compose up -d
如果启动有问题(端口占用等)则可停止(会杀死容器实例)
docker-compose down
3、 docker-compose启动(多实例,弹性伸缩、负载均衡):
docker-compose.yml 文件内容调整为:
# yaml 配置实例
version: '3'
services:quarkus-hello-world:image: registry.cn-hangzhou.aliyuncs.com/lizhou828/code-with-quarkus:1.0.0-SNAPSHOT # docker中已存在的镜像名+版本名ports:- "8080" # 将容器内部的多个端口映射到宿主机的端口上restart: alwaysenvironment:TZ: Asia/Shanghainginx:image: nginx:latestvolumes:- type: bindsource: /run/desktop/mnt/host/d/xxxx/quarkus-helloworld/nginx.conf # /run/desktop/mnt/host/ 前缀来表示 WSL 中访问 Windows 主机文件系统的路径映射 /d/xxxx/quarkus-helloworld/nginx.conf 是windows文件路径在linux系统的表示方式target: /etc/nginx/nginx.conf # 容器中的路径depends_on:- quarkus-hello-worldports:- "81:81"volumes:logvolume01: {}
新增 nginx.conf文件
cd quarkus-helloworld
vi nginx.conf
nginx.conf 文件内容如下:
user nginx;
events {worker_connections 1000;
}
http {server {listen 81;location / {proxy_pass http://quarkus-hello-world:8080;}}
}
执行启动命令(2个实例):
docker-compose up -d --scale quarkus-hello-world=2
六、压测与调优
1、启动参数未加 任何 参数,且docker-compose.yaml未限制CPU与内存资源 情况下:
在不停的访问 http://localhost:9000/hello/testData 接口时,内存占用情况从启动时的21M一直升到50M(单实例):
2、启动增加参数 -Xmx32m 参数,且 docker-compose.yaml限制了CPU与内存资源 情况下(两个实例,1个并发,测试接口访问10000次):
使用工具压测 http://localhost:81/hello/testData 接口时,测试访问10000+次,内存占用情况非常平稳:
3、启动增加参数 -Xmx32m 参数,且 docker-compose.yaml限制了CPU与内存资源 情况下(10个实例、1000个并发):
使用工具压测 http://localhost:81/hello/testData 接口时,启动10个实例、1000个并发,内存占用情况也非常平稳(在预热期间,CPU在短时间内有个峰值):第一轮测试情况:
第二轮测试情况:
七、参考文档
7.1、官方文档
quarkus最新指南
quarkus-quickstarts
Quarkus实战:专为Kubernetes而优化的Java解决方案.pdf
quarkus-quickstarts
7.2、开发、部署、调试
日志文件的日志是正常,但控制台打印日志中文乱码的问题
IDEA中Quarkus框架(3.13版本)开发、调试、部署、打包等
quarkus实战之四:远程热部署
7.3、Web层
Quarkus的JAX-RS采用Resteasy的实现,可以实现各类Web操作:上传、下载、导入、导出等
Resteasy官方文档
Related guide section…
quarkus数据库篇之三:单应用同时操作多个数据库(有链接要改)
quarkus+saas 多租户动态数据源切换实现简单完美
7.4、持久层ORM
hibernate-orm-panache 单表操作 的 官方文档
JPA SQL 查询、结果集映射(@NamedNativeQuery、@ColumnResult注解说明)
JPA EntityManager采用原生SQL语句执行后,返回LIst自定义对象的方法
hibernate使用createNativeQuery做原始的字段映射处理
EntityManager使用原生查询createNativeQuery并把值映射到自定义实体
JPA Repository: 自定义SQL的2种方法
JPA原生SQL(单表自定义SQL)分页查询逻辑
完美的 jpa 多表 原生sql 分页查询
JPA使用原生SQL实现分页查询、排序
DB操作 Hibernate Panache
Quarkus使用了Panache来简化数据库操作
在quarkus上使用panache执行自定义JPQL查询
Quarkus - Using MyBatis
hibernate-orm#multitenancy
quarkus+saas 多租户动态数据源切换实现简单完美
quarkus-mybatis
quarkus-mybatis-plus
7.5、原生应用
quarkus官方关于原生应用的提示
原生包中使用反射,GraalVM 提供了一些解决方案
GraalVM如何支持原生包中的反射、JNI、proxy?
Graalvm构建原生镜像时,如何嵌入配置文件(静态文件、反射、动态代理、序列化等)
quarkus云原生构建的配置,官方文档
编写quarkus原生应用程序的提示
在云原生镜像中如何自动识别反射、动态代理、序列化等、静态资源、JNI、URL协议等所用到的类和方法的说明
quarkus原生应用,一直刷接口,内存一直在升高?
quarkus原生应用,一直刷接口,内存从21M上升到50M,内存没有回收?
解决方式一:启动命令增加参数: -Xmx64m解决方式二:
构建原生镜像时,添加参数: -Dquarkus.native.native-image-xmx=64M
https://docs.redhat.com/en/documentation/red_hat_build_of_quarkus/2.13/html-single/compiling_your_quarkus_applications_to_native_executables/index#proc_native-memory-configuration_quarkus-building-native-executable
7.6、容器化
docker compose 命令自定义参数 docker-compose使用
谁说docker-compose不能水平扩展容器、服务多实例?
Docker-desktop启用k8s挂载hostpath类型的pv时挂载不到windows磁盘的问题
7.7、单元测试
Test a Quarkus application with Junit5, Mockito and H2 Database
quarkus-testing-restassured
REST Assured 实践:断言实现
h2database
7.8、RBAC 基于角色的权限访问控制
Quarkus中基于角色的权限访问控制教程
7.9、quarkus 微服务( rest-api)
quarkus-microservice
Quarkus集成Dubbo Rpc远程通讯框架(8)
Quarkus集成Dubbo框架扩展开源了(23)
quarkus-dubbo-rpc
Dubbo 一款云原生微服务开发框架 官网
How quarkus/helidon/micronaut support Apache Dubbo Component ?
7.10、quarkus的扩展(二方包、三方包)
quarkus编写您自己的扩展
quarkus-building-my-first-extension
quarkus编写扩展的常见问题
quarkus官方依赖的源码库 Quarkiverse Hub
quarkus框架的所有配置项
7.11、国内博主专栏
程序员欣宸的博客 CSDN专栏 java 云原生
程序员欣宸的博客 知乎专栏 quarkus
kl博主 在腾讯云开发者社区的专栏 quarkus
CSDN博客专家程序员欣宸的github,这里有六百多篇原创文章的详细分类和汇总,以及对应的源码,内容涉及Java、Docker、Kubernetes、DevOPS等方面
软件开发记录—是我冒饭了
quarkus框架开发的个人博客项目
八、编码注意事项
明确调用自己类的实例方法(this),还是调用父类的方法( super)
子类通过super调用了父类的方法, 父类里面的该方法内部不能再有调用链,否则报错
quarkus框架中,尽量避免使用 this 调用其他方法,而是通过 静态方法 或 工具类 来实现逻辑。也尽可能少使用:动态代理、反射等特性
hibernate-orm 执行原生SQL时,映射结果集的类MnItemVo 会被反射调用构造器,如果需要打原生包运行本应用的话,MnItemVo类必须要大打上@RegisterForReflection 注解
hibernate-orm 执行原生SQL时,要映射的结果集的类,每个字段的类型必须准确,否则报错 : argument type mismatch ,或者使用project() 投影 VO类
九 、spring框架的对比
1. 代理类生成机制的不同
Spring 的代理机制默认使用 JDK 动态代理或 CGLIB:Spring 使用 JDK 动态代理(接口代理)或 CGLIB(基于子类的字节码生成)。AOP 和代理行为透明:Spring 会尽可能保留类的原始逻辑,super 调用通常不会被代理拦截,因为 Spring 的代理层对父类方法并没有特殊处理。Quarkus 的代理机制基于字节码增强:Quarkus 不使用传统的动态代理(如 JDK 或 CGLIB)。取而代之,Quarkus 在构建时通过字节码增强(Bytecode Enhancement)生成代理类。代理类替换原始类:Quarkus 的代理机制更偏向运行时性能优化,使用的是增强后的类作为代理。增强后的类可能不会直接调用原始父类的逻辑,而是将方法调用委托给特定的拦截器。导致问题 :在 Quarkus 中,super 的调用通常会绕过代理类的增强逻辑。如果代理类对父类方法有特殊的增强逻辑(例如注解解析、事务管理等),直接调用 super 会导致增强逻辑无法生效。这与 Spring 的行为不同,因为 Spring 的代理机制通常不会破坏方法调用链。
2. CDI 和 AOP 实现的差异
Spring 的 AOPSpring 的 AOP 基于 AspectJ 或代理机制,支持拦截方法调用,包括子类方法调用。如果子类调用父类的 super 方法,Spring 不会主动拦截,因为代理通常只针对接口或类的公开方法。Quarkus 的 CDIQuarkus 使用的是 Jakarta CDI(Context and Dependency Injection)的实现,它更加严格地依赖注解元数据和代理类增强。父类方法在 Quarkus 的代理中可能不会自动包含注解元数据(如 @Path、@Transactional 等)。因此,当子类调用 super 方法时,代理无法处理注解解析,导致 NullPointerExceptionQuarkus 的 CDI 机制支持懒加载,这意味着某些方法调用可能会被代理类拦截,从而导致方法调用链被破坏。Quarkus 在构建时会对字节码进行增强,以优化性能和减少内存占用。这种增强可能会影响类的继承结构,导致父类方法调用出现问题。
3. 生命周期和上下文的处理差异
Spring 的 Bean 生命周期Spring 的 Bean 生命周期在运行时动态管理,Spring 的代理类是在运行时加载和初始化时生成的。因为代理的目标是增强现有的 Bean,父类方法调用通常不会受到代理逻辑的影响。Quarkus 的 Bean 生命周期Quarkus 的 Bean 生命周期通过构建时分析生成字节码进行优化,代理类和增强逻辑在编译时就已经被固定。如果子类调用父类的 super 方法时,增强逻辑或注解处理需要运行时动态解析,Quarkus 可能无法支持这种行为,因为代理类与父类的注解处理是分离的。
十、常见的第三方依赖的扩展包
已有的扩展:redis、kafka、mongoDB、ES、microsoft-server-sql、quarkus-scheduler、itext、zookeeper、flyway、hibernate、JDBC没有的扩展:nacos、aliyun-sdk-oss、xxl-job