Quarkus: 云原生时代的Java框架

云原生简介

什么是云原生?

云原生体系结构和技术是一种方法,用于设计、构造和操作在云中构建并充分利用云计算模型的工作负载。
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。

云原生的代表技术

微服务

云原生系统采用微服务,而微服务是一种用于构造新式应用程序的常用体系结构样式。
微服务构建为一组通过共享结构进行交互的分布式小型独立服务,共同具有以下特征:

  • 各自都在较大的域上下文中实现特定业务功能。

  • 各自都自主开发,可以独立部署。

  • 各自都是独立的,封装其自己的数据存储技术、依赖项和编程平台。

  • 各自都在自己的进程中运行,并使用 HTTP/HTTPS、gRPC、WebSocket 或 AMQP 等标准通信协议与其他微服务进行通信。

  • 它们组合在一起形成应用程序。

    容器

    容器是与系统其他部分隔离开的一系列进程
    容器提供进程级的隔离,可以将操作系统管理的资源划分到相互隔离的组中,在相互隔离的组之间解决资源使用存在冲突的问题
    容器是微服务的最佳载体,Docker是使用最广泛的一种容器技术。

    Kubernetes

    Kubernetes用于编排管理容器的生命周期,是整个云原生的基石,云原生的整个生态体系都是依靠Kubernetes建立起来的。
    Kubernetes作为云应用的部署标准,直接面向业务应用,大大提高了云应用的可移植性,解决云厂商锁定的问题,让云应用可以在跨云之间无缝迁移,甚至用来管理混合云,成为企业 IT 云平台的新标准。

服务网格

服务网格(Service Mesh),是指用以处理服务与服务之间通信的基础设施层。
服务网格 核心是业务逻辑与非业务逻辑解耦,实现开发只需关注业务逻辑的实现。将一大堆和业务逻辑无关的客户端 SDK(如服务发现,路由,负载均衡,限流降级等)从业务应用中剥离出来,放到单独的 Proxy(Sidecar) 进程中,之后下沉到基础设施中间件 Mesh(类似 TDDL 到 DRDS 的模式)。
服务网格的出现弥补了Kubernetes在微服务的连接、管理和监控方面的短板,为Kubernetes提供更好的应用和服务管理。
Istio是是目前最广为人知的一款服务网格架构。

云原生的优点

快速迭代

利用云原生应用程序开发,使得交付团队可以使用重复的自动化和编排来快速迭代,让开发人员有更多的精力聚焦于业务开发上。

自动部署

相比于传统方法需要投入大量的精力来构建开发环境,云原生架构具备自动化和组合功能,交付十分敏捷,而不再需要人工干预重复执行。

独立高效

云原生将应用程序代码解耦成独立模块化单元,降低微服务的部属时间与互依性,提高应用的扩展性等。

Java在云原生时代的挑战

Java的优势

  • 庞大的生态,丰富的插件,活跃的社区;
  • 平台无关性,一次运行,处处运行;
  • 垃圾回收机制,不用手动回收内存;

Java的劣势

  • 依赖JDK
  • 启动慢
  • 资源占用率高

Quarkus

什么是Quarkus

Quarkus 是专为 OpenJDK HotSpot 和 GraalVM 定制的全栈 Kubernetes 原生 Java 应用程序框架。与如 Spring 之类的其他框架相比,它提供了较小的内存占用并缩短了启动时间。它允许结合命令式和非阻塞响应式编程。
img

Quarkus的特性

img

Quarkus与传统Java应用的启动步骤对比

  • 传统应用的启动步骤
    img
  • Quarkus应用的启动步骤
    img

Quarkus功能介绍

页面-2

将应用从SpringBoot 迁移到Quarkus

依赖替换

  • io.quarkus:quarkus-spring-boot-properties: 使用注释如@ConfigurationProperties时需要;
  • io.quarkus:quarkus-spring-di:使用注释如@ServiceConfiguration时需要;
  • io.quarkus:quarkus-spring-web:使用注释如@RestControllerGetMapping时需要;

类替换

img

注解替换

img

异常处理替换

  • SpringBoot

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.ext.ExceptionMapper;
    import javax.ws.rs.ext.Provider;
    @Provider
    public class UncaughtExceptionMapper implements ExceptionMapper<Exception> {
    //...
    @Override
    public Response toResponse(Exception ex) {
    if (ex instanceof WebApplicationException) {
    return ((WebApplicationException)ex).getResponse();
    }
    logger.error("Uncaught exception", ex);
    return Response.status(Response.Status.BAD_REQUEST).build();
    }
    }COPY
  • Qurakus

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @ControllerAdvice
    public class GlobalExceptionHandlers {
    //...
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Void> handleException(Exception ex) {
    logger.error("Uncaught exception", ex);
    return ResponseEntity.badRequest().build();
    }
    }COPY

案例演示

SpringBoot工程

  • 打包mvn install
    img
  • 打包后产物img
  • 启动运行`java -jar -Dserver.port=3050 target/wakatime-sync.jar
    img

Quarkus工程

  • 打包 mvn package -Dnative
    img
  • 打包后产物img
  • 启动./target/wakatime-sync-1.0-runner
    img

Quarkus的局限性和缺点

  • 动态类加载
  • 反射
  • 动态代理
  • JNI
  • Java 安全管理器
  • 编译原生镜像耗时且占用资源较多
  • 生成的镜像没法做到一处编译,处处运行
  • 虽然社区活跃,支持的插件已有100多个,但相比Spring生态来说还是远远不够,需要插件都需要自己开发

参考阅读

  1. GraalVM指南
  2. Quarkus指南
  3. Quarkus插件社区
  4. Quarkus实战教程
  5. 原生镜像兼容性和优化指南