「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,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
复制代码
能正常访问
数据库中持久化为
性能测试(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条数据。
性能测试(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.
复制代码
闲话
Quarkus
在Rest
服务上有优势,而明显数据库的性能决定了API
服务的性能上限,如果调用Redis
或者内存时,则更能体现其性能优势。
这里连接数据库使用了Vert.x
的Reactive Client
,相对于同步阻塞的JDBC
来说,对资源的利用更加充分。
近期评论