Quarkus的Insert&Select数据库性能(5)🔥

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

通过Insert的性能来推测连接数据库的情况下,Quarkus的性能如何?

服务器配置

CentOS Linux release 7.6.1810 (Core)

Intel(R) Xeon(R) Gold 6278C CPU @ 2.60GHz

4C8G
复制代码

性能测试

数据库选用的是PG,如果喜欢Mysql的话,同理。

测试样例

数据模型

CREATE TABLE "public"."dynamic_info" (
    "id" int8 NOT NULL,
    "dynamic_type" int2,
    "dynamic_desc" varchar,
    "creator" varchar,
    "created_time" timestamp,
    PRIMARY KEY ("id")
);
复制代码

映射实体DynamicInfo

package org.mxx.pg.domain;

import com.google.common.collect.Lists;
import io.vertx.mutiny.sqlclient.Row;
import io.vertx.mutiny.sqlclient.RowSet;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * Description: 动态信息 .<br>
 * <p>Created Time: 2021/7/8 下午2:20 </p>
 *
 * @author <a href="mail to: mengxiangyuancc@gmail.com" rel="nofollow">孟祥元</a>
 */
@Entity(name = "dynamic_info")
public class DynamicInfo {

    @Id
    private Long id;
    private Integer dynamicType;
    private String dynamicDesc;
    private String creator;
    private LocalDateTime createdTime;

    public static DynamicInfo from(Row row) {
        return new DynamicInfo(
            row.getLong("id"),
            row.getInteger("dynamic_type"),
            row.getString("dynamic_desc"),
            row.getString("creator"),
            row.getLocalDateTime("created_time")
        );
    }

    public static List<DynamicInfo> froms(RowSet<Row> rows) {
        List<DynamicInfo> result = Lists.newArrayList();
        rows.forEach(row -> {
            result.add(from(row));
        });
        return result;
    }

    public DynamicInfo() {
    }

    public DynamicInfo(Long id, Integer dynamicType, String dynamicDesc, String creator, LocalDateTime createdTime) {
        this.id = id;
        this.dynamicType = dynamicType;
        this.dynamicDesc = dynamicDesc;
        this.creator = creator;
        this.createdTime = createdTime;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getDynamicType() {
        return dynamicType;
    }

    public void setDynamicType(Integer dynamicType) {
        this.dynamicType = dynamicType;
    }

    public String getDynamicDesc() {
        return dynamicDesc;
    }

    public void setDynamicDesc(String dynamicDesc) {
        this.dynamicDesc = dynamicDesc;
    }

    public String getCreator() {
        return creator;
    }

    public void setCreator(String creator) {
        this.creator = creator;
    }

    public LocalDateTime getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(LocalDateTime createdTime) {
        this.createdTime = createdTime;
    }
}

复制代码

创建BaseRepository

package org.mxx.config.base;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import io.quarkus.reactive.datasource.ReactiveDataSource;
import io.vertx.mutiny.pgclient.PgPool;
import javax.inject.Inject;

/**
 * Description: Pg .<br>
 * <p>Created Time: 2021/6/8 下午4:40 </p>
 *
 * @author <a href="mail to: mengxiangyuancc@gmail.com" rel="nofollow">孟祥元</a>
 */
public class BasePgRepository {
    @Inject
    @ReactiveDataSource("pg")
    protected PgPool pgPool;

    protected Snowflake snowflake = IdUtil.getSnowflake(1, 1);
}

复制代码

创建实体的Repository

package org.mxx.pg.repository;

import io.smallrye.mutiny.Uni;
import io.vertx.mutiny.sqlclient.Tuple;
import java.time.LocalDateTime;
import java.util.Date;
import javax.inject.Singleton;
import org.mxx.config.base.BasePgRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Description: 动态 .<br>
 * <p>Created Time: 2021/7/8 下午2:27 </p>
 *
 * @author <a href="mail to: mengxiangyuancc@gmail.com" rel="nofollow">孟祥元</a>
 */
@Singleton
public class DynamicInfoRepository extends BasePgRepository {
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicInfoRepository.class);

    public Uni<Long> addDynamicInfo() {
        return pgPool.preparedQuery(
            "insert into dynamic_info (id,dynamic_type,dynamic_desc,creator,created_time) values ($1,$2,$3,$4,$5) RETURNING id")
            .execute(Tuple.of(
                snowflake.nextId(),
                1,
                "admin 添加了动态",
                "admin",
                LocalDateTime.now()))
            .onItem()
            .transform(pgRowSet -> pgRowSet.iterator().next().getLong("id"));
    }
}
复制代码

创建Resource

package org.mxx.pg.resource;

import io.quarkus.vertx.web.Route;
import io.smallrye.mutiny.Uni;
import io.vertx.core.http.HttpMethod;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.mxx.pg.repository.DynamicInfoRepository;

/**
 * Description: 动态 .<br>
 * <p>Created Time: 2021/7/8 下午2:19 </p>
 *
 * @author <a href="mail to: mengxiangyuancc@gmail.com" rel="nofollow">孟祥元</a>
 */
@Singleton
@Tag(name = "dynamic")
public class DynamicResource {
    @Inject
    DynamicInfoRepository dynamicInfoRepository;

    @Route(path = "/addDynamic", methods = HttpMethod.GET)
    Uni<Long> addDynamic() {
        return dynamicInfoRepository.addDynamicInfo();
    }
}
复制代码

部署方式

首先进行打包

./mvnw package
复制代码

然后将target中的quarkus-app文件夹放到服务器中启动

nohup java -jar quarkus-app/quarkus-run.jar &
复制代码

单元测试

curl http://127.0.0.1:8080/addDynamic
复制代码

能正常访问
image.png
数据库中持久化为
image.png

性能测试(Insert)

[root@ecs-1b4c-0002 k6]# wrk -c50 -d20s 'http://127.0.0.1:8080/addDynamic'  --latency
Running 20s test @ http://127.0.0.1:8080/addDynamic
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.56ms   12.06ms 214.33ms   98.54%
    Req/Sec    10.83k     1.47k   13.73k    75.88%
  Latency Distribution
     50%    2.02ms
     75%    2.65ms
     90%    4.05ms
     99%   29.37ms
  428896 requests in 20.01s, 42.54MB read
Requests/sec:  21438.03
Transfer/sec:      2.13MB
复制代码

数据库在20秒内写入了428936条数据。
image.png

性能测试(Select)

此时数据库中已经存在了43万条数据

[root@ecs-1b4c-0002 k6]# wrk -c50 -d20s 'http://127.0.0.1:8080/findDynamicById?id=1413054691109113856'  --latency
Running 20s test @ http://127.0.0.1:8080/findDynamicById?id=1413054691109113856
  2 threads and 50 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.16ms    1.07ms  48.74ms   97.63%
    Req/Sec    23.06k     1.26k   40.17k    95.51%
  Latency Distribution
     50%    1.05ms
     75%    1.28ms
     90%    1.56ms
     99%    3.88ms
  920108 requests in 20.10s, 194.80MB read
Requests/sec:  45776.45
Transfer/sec:      9.69MB
复制代码

在20秒内进行了92万次检索,QPS达到4.5万。

压测中的进程信息

top - 16:51:39 up 247 days, 20:00,  2 users,  load average: 0.77, 0.28, 0.26
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s): 35.7 us, 26.3 sy,  0.0 ni, 20.3 id,  0.0 wa,  0.0 hi, 17.8 si,  0.0 st
KiB Mem :  8008324 total,  1016916 free,  4775628 used,  2215780 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  2645436 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                        
 5222 root      20   0 5246408 439708  13716 S 265.0  5.5   3:37.46 java    
复制代码

压测后的进程信息

[root@ecs-1b4c-0002 k6]# jmap -J-d64 -heap 5222
Attaching to process ID 5222, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2051014656 (1956.0MB)
   NewSize                  = 42991616 (41.0MB)
   MaxNewSize               = 683671552 (652.0MB)
   OldSize                  = 87031808 (83.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 136314880 (130.0MB)
   used     = 4515344 (4.3061676025390625MB)
   free     = 131799536 (125.69383239746094MB)
   3.3124366173377404% used
From Space:
   capacity = 524288 (0.5MB)
   used     = 131072 (0.125MB)
   free     = 393216 (0.375MB)
   25.0% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 100139008 (95.5MB)
   used     = 21208464 (20.225967407226562MB)
   free     = 78930544 (75.27403259277344MB)
   21.179023463064464% used

11297 interned Strings occupying 1320912 bytes.
复制代码

闲话

QuarkusRest服务上有优势,而明显数据库的性能决定了API服务的性能上限,如果调用Redis或者内存时,则更能体现其性能优势。

这里连接数据库使用了Vert.xReactive Client,相对于同步阻塞的JDBC来说,对资源的利用更加充分。