Quarkus поддерживает императивные и реактивные стили программирования. В этой статье я сравниваю время доступа к Postgres из микросервисов на основе Java, разработанных с помощью Quarkus. Для синхронных вызовов используется Panache, для асинхронного доступа — Vert.x Axle.
Я создал пример приложения, которое поставляется с проектом cloud-native-starter . Микросервис «article» обращается к базе данных, работающей в Kubernetes. Для простоты сценария тестируется только один REST API, который читает статьи из Postgres.
Сервис статей доступен в двух вариантах:
- Обязательный / синхронный: конечная точка REST была реализована с помощью JAX-RS (синхронно). Сервис читает статьи из Postgres через Panache (см. Руководство Quarkus по упрощенному Hibernate ORM с Panache ).
- Реактивный / асинхронный: конечная точка REST была реализована с помощью асинхронно Vert.x, CompletionStage и CompletableFuture. Служба асинхронно читает статьи из Postgres через Vert.x Axle (см. Руководство Quarkus « Реактивные клиенты SQL» ).
Реактивный стек этого образца обеспечивает время отклика, которое занимает менее половины времени по сравнению с императивным стеком : Реактивный: 142 мс (всего 0:42 мин) — Императивный: 265 мс (всего 1:20 мин). Проверьте документацию для деталей.
Хотя этот сценарий не обязательно является репрезентативным, я думаю, он хорошо демонстрирует эффективность реактивного программирования.
Я провел второй тест производительности, где тестируется более полное облачное приложение. Ознакомьтесь с документацией .
Синхронный доступ через Panache
Panache — это расширение JPA, которое делает упорство действительно простым. После того, как вы определили зависимости и конфигурацию в application.properties , вы можете определить сущность (см. Код ):
Джава
xxxxxxxxxx
1
import javax.persistence.Cacheable;
2
import javax.persistence.Entity;
3
import io.quarkus.hibernate.orm.panache.PanacheEntity;
4
5
6
7
public class Article extends PanacheEntity {
8
public Article() {}
9
public String title;
10
public String url;
11
public String author;
12
public String creationDate;
13
}
Panache поставляется со встроенными удобными методами для доступа к базам данных, например, listAll для чтения всех статей (см. Код ):
Джава
xxxxxxxxxx
1
import javax.ws.rs.GET;
2
import javax.ws.rs.Path;
3
import javax.ws.rs.Produces;
4
import javax.ws.rs.core.Response;
5
...
6
"/v1/articles") (
7
8
"application/json") (
9
"application/json") (
10
public class ArticleResource {
11
12
public List<Article> get() {
13
return Article.listAll(Sort.by("creationdate"));
14
}
15
}
Асинхронный доступ с осью Vert.x
После того, как вы определили зависимости и конфигурацию в application.properties , статьи можно прочитать из базы данных с помощью следующего кода :
Джава
xxxxxxxxxx
1
import io.vertx.axle.sqlclient.Row;
2
import io.vertx.axle.sqlclient.RowSet;
3
import java.util.concurrent.CompletableFuture;
4
import java.util.concurrent.ExecutionException;
5
...
6
public class PostgresDataAccess {
7
...
8
9
io.vertx.axle.pgclient.PgPool client;
10
11
12
void initdb() {
13
client.query("DROP TABLE IF EXISTS articles").thenCompose(r -> client.query(
14
"CREATE TABLE articles (id SERIAL PRIMARY KEY, title TEXT NOT NULL, url TEXT, author TEXT, creationdate TEXT)"))
15
.toCompletableFuture().join();
16
}
17
18
public CompletableFuture<List<Article>> getArticlesReactive() {
19
CompletableFuture<List<Article>> future = new CompletableFuture<List<Article>>();
20
client.query("SELECT id, title, url, author, creationdate FROM articles ORDER BY id ASC").toCompletableFuture()
21
.orTimeout(MAXIMAL_DURATION, TimeUnit.MILLISECONDS).thenAccept(pgRowSet -> {
22
List<Article> list = new ArrayList<>(pgRowSet.size());
23
for (Row row : pgRowSet) {
24
list.add(from(row));
25
}
26
future.complete(list);
27
}).exceptionally(throwable -> {
28
future.completeExceptionally(new NoConnectivity());
29
return null;
30
});
31
return future;
32
}
33
34
private static Article from(Row row) {
35
Article article = new Article();
36
article.id = row.getLong("id").toString();
37
article.title = row.getString("title");
38
article.author = row.getString("author");
39
article.creationDate = row.getString("creationdate");
40
article.url = row.getString("url");
41
return article;
42
}
При использовании реактивного подхода, насколько я знаю, схему нужно создавать программно. Кроме того, данные из баз данных необходимо преобразовать в объекты Java вручную. Надеемся, что эти две области будут упрощены так же, как это делается с JPA и Panache.
Заключительные мысли
Все образцы этой статьи включены в открытый проект cloud-native-starter . Проверьте это, чтобы увидеть код в действии.