阅读 126

Quarkus开发入门(2)🔥

开发环境

参见Quarkus入门​ ​

image.png

  1. 安装IntelliJ IDEA
  2. 配置开发JDK,可以使用JDK8,推荐JDK11。当然如果要尝试Native,那可以安装GraalVM
  3. 安装Maven3.6.2以上。

快速搭建一个Quarkus应用

参见Quarkus Start Coding image.png 我们选择了Quarkus吸引我们的特性,开始体验Reactive编程。

选择完毕后,点击Generate your application下载工程。 ​

分析POM

引入Quarkus的pom

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
复制代码

Quarkus的版本更新很频繁,但都是通过quarkus-universe-bom管理的,引入这部分后,后续的版本升级会方便很多。 ​

Reactive Routes

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-vertx-web</artifactId>
    </dependency>
复制代码

QuarkusReactive Web是基于Vert.x实现的,通过一些注解和封装,让代码编写更简单。 ​

Reactive Panache

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-reactive-panache</artifactId>
    </dependency>
复制代码

Panache是基于Hibernate的实现,类似于JPA,更简单。 ​

Reactive DB Client

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-reactive-mysql-client</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-reactive-pg-client</artifactId>
    </dependency>
复制代码

根据数据库选型不同,引入对应的数据库Client

OpenAPI

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-openapi</artifactId>
    </dependency>
复制代码

如果喜欢Swagger的话,可以引入Quarkus对应的OpenApi实现。 ​

接口1-hello1,quarkus

代码

@OpenAPIDefinition(
    info = @Info(
        title = "Hello API",
        version = "1.0.0",
        contact = @Contact(
            name = "Hello API Support",
            url = "http://127.0.0.1:8080/swagger-ui/",
            email = "mengxiangyuancc@gmail.com"),
        license = @License(
            name = "Apache 2.0",
            url = "https://www.apache.org/licenses/LICENSE-2.0.html"))
)
@ApplicationScoped
public class HelloResource extends BaseResource {
    private static final Logger LOGGER = LoggerFactory.getLogger(HelloResource.class);

    @Route(path = "/hello1", methods = HttpMethod.GET)
    @Operation(description = "hello1 接口")
    void hello1(RoutingContext ctx) {
        ctx.response().end("hello1, quarkus");
    }
    
    @Route(path = "/hello2", methods = HttpMethod.GET)
    String hello2(RoutingContext ctx) {
        // non-blocking
        return "hello2, quarkus";
    }

    @Route(path = "/hello3", methods = HttpMethod.GET)
    String hello3(@Param Optional<String> name) {
        return "hello3, " + name.orElse("quarkus");
    }

    @Route(path = "/hello4", methods = HttpMethod.GET)
    Uni<String> hello4(RoutingContext context) {
        return Uni.createFrom().item("hello4, quarkus");
    }
}
复制代码

注解

  1. @OpenAPIDefinition@Operation都是OpenApi的注解,用于生成接口文档。
  2. @ApplicationScoped 生成Bean
  3. @Route(path = "/hello1", methods = HttpMethod.GET) 定义一个Get接口。

启动

以Dev模式启动

./mvnw compile quarkus:dev
复制代码

打包

./mvnw package
复制代码

打包uber-jar

./mvnw package -Dquarkus.package.type=uber-jar
复制代码

打包Native,需要GraalVM

./mvnw package -Pnative
复制代码

打包Native,不需要GraalVM,但需要Docker

./mvnw package -Pnative -Dquarkus.native.container-build=true
复制代码

调用

[root@ecs-1b4c-0002 k6]# curl http://127.0.0.1:8080/hello1
hello1, quarkus
复制代码

性能

[root@ecs-1b4c-0002 k6]# wrk -c50 -d20s 'http://localhost:8080/hello1'  --latency
Running 20s test @ http://localhost:8080/hello1
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.92ms    2.57ms  46.89ms   92.41%
    Req/Sec   120.34k    22.68k  185.55k    74.75%
  Latency Distribution
     50%  125.00us
     75%  398.00us
     90%    2.28ms
     99%   12.56ms
  4792636 requests in 20.03s, 457.06MB read
Requests/sec: 239328.58
Transfer/sec:     22.82MB

[root@ecs-1b4c-0002 k6]# wrk -c50 -d20s 'http://localhost:8080/hello2'  --latency
Running 20s test @ http://localhost:8080/hello2
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.24ms    3.09ms  57.90ms   90.09%
    Req/Sec   124.35k    22.26k  194.19k    74.50%
  Latency Distribution
     50%  103.00us
     75%  506.00us
     90%    4.28ms
     99%   14.60ms
  4949693 requests in 20.02s, 472.04MB read
Requests/sec: 247208.04
Transfer/sec:     23.58MB

[root@ecs-1b4c-0002 ~]# wrk -c50 -d20s 'http://localhost:8080/hello3'  --latency
Running 20s test @ http://localhost:8080/hello3
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.92ms    2.75ms  46.71ms   93.14%
    Req/Sec   115.25k    20.64k  177.04k    70.00%
  Latency Distribution
     50%  130.00us
     75%  400.00us
     90%    1.63ms
     99%   14.12ms
  4589497 requests in 20.03s, 437.69MB read
Requests/sec: 229162.08
Transfer/sec:     21.85MB

[root@ecs-1b4c-0002 ~]# wrk -c50 -d20s 'http://localhost:8080/hello4'  --latency
Running 20s test @ http://localhost:8080/hello4
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   797.89us    2.37ms  53.33ms   93.64%
    Req/Sec   109.77k    20.36k  171.02k    70.00%
  Latency Distribution
     50%  152.00us
     75%  390.00us
     90%    1.36ms
     99%   11.81ms
  4375750 requests in 20.07s, 417.30MB read
Requests/sec: 218072.60
Transfer/sec:     20.80MB
复制代码

4C8G服务器下QPS能达到20W+。 ​

接口2-查询数据库

代码

Route

    @Inject
    BrandInfoRepository brandInfoRepository;
	

	@Route(path = "/brandInfo", methods = HttpMethod.GET)
    Uni<BrandInfo> brandInfo(@Param Optional<String> brandId) {
        return brandInfoRepository.findById(brandId.orElse(""));
    }
复制代码

BrandInfoRepository

@ApplicationScoped
public class BrandInfoRepository extends ResourceRepository<BrandInfo> {
}
复制代码

ResourceRepository 不直接继承PanacheRepositoryBase是为了后续扩展的需要。

/**
 * Description: 不直接继承 PanacheRepositoryBase .<br>
 * <p>Created Time: 2021/5/25 下午5:29 </p>
 *
 * @author <a href="mail to: mengxiangyuancc@gmail.com" rel="nofollow">孟祥元</a>
 */
public class ResourceRepository<Entity> implements PanacheRepositoryBase<Entity, String> {
}
复制代码

BrandInfo

@Entity(name = "brand_info")
public class BrandInfo extends PanacheEntityBase {

    @Id
    private String brandId;
    private String brandName;
    
    // get set ……
}
复制代码

配置文件

quarkus.datasource.db-kind=mysql
quarkus.datasource.username=dev
quarkus.datasource.password=123456
quarkus.datasource.reactive.url=mysql://xxx.xxx.xxx.xxx:3306/quarkus
复制代码

性能

Mysql数据库中的brand_info表中大约18万条数据,QPS达到3万+

[root@ecs-1b4c-0002 ~]# wrk -d20s -c50 http://127.0.0.1:8080/brandInfo?brandId=1000003
Running 20s test @ http://127.0.0.1:8080/brandInfo?brandId=1000003
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.50ms    1.52ms  40.92ms   97.31%
    Req/Sec    18.56k     1.19k   31.68k    82.04%
  740605 requests in 20.10s, 92.52MB read
Requests/sec:  36846.26
Transfer/sec:      4.60MB
复制代码

闲话

QuarkusReactive 编码还是相对简单的,性能较高,充分使用了服务器资源,减少等待。

文章分类
后端
文章标签