Redisクライアントの使用
このガイドでは、QuarkusアプリケーションがRedisクライアントエクステンションを使用してRedisサーバーに接続する方法を説明します。
この技術は、previewと考えられています。 preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリスト や GitHub の課題管理 で受け付けています。 とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。 |
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.8
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
-
Dockerが稼働している環境
アーキテクチャ
このガイドでは、 INCRBY
コマンドを使用して、数値をインクリメントするシンプルな Rest API を公開します。また、 GET
、 SET(文字列グループ)
、 DEL
、 KEYS(キーグループ)
のような他の Redis コマンドの使い方も見ていきましょう。
Quarkus Redisエクステンションを使用して、Redisと対話型で接続しましょう。
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
ソリューションは redis-quickstart
ディレクトリ にあります。
Mavenプロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します:
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=redis-quickstart"
このコマンドは、Redisエクステンションをインポートして新しいプロジェクトを生成します。
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに redis-client
エクステンションを追加することができます。
quarkus extension add redis-client
./mvnw quarkus:add-extension -Dextensions='redis-client'
./gradlew addExtension --extensions='redis-client'
これにより、ビルドファイルに以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
implementation("io.quarkus:quarkus-redis-client")
インクリメントPOJOの作成
Increment
POJO を使用してインクリメントをモデル化します。 src/main/java/org/acme/redis/Increment.java
ファイルを作成し、以下の内容で作成します。
package org.acme.redis;
public class Increment {
public String key; (1)
public long value; (2)
public Increment(String key, long value) {
this.key = key;
this.value = value;
}
public Increment() {
}
}
1 | Redisキーとして使用されるキー |
2 | Redisキーが保持する値 |
インクリメントサービスの作成
Redis クライアントの役割を果たす IncrementService
クラスを作成します。このクラスで、 SET
、 GET
、 DEL
、 KEYS
、 INCRBY
Redis コマンドを実行できるようになります。
以下の内容の src/main/java/org/acme/redis/IncrementService.java
ファイルを作成します:
package org.acme.redis;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.keys.KeyCommands;
import io.quarkus.redis.datasource.keys.ReactiveKeyCommands;
import io.quarkus.redis.datasource.string.StringCommands;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class IncrementService {
// This quickstart demonstrates both the imperative
// and reactive Redis data sources
// Regular applications will pick one of them.
private ReactiveKeyCommands<String> keyCommands; (1)
private ValueCommands<String, Long> countCommands; (2)
public IncrementService(RedisDataSource ds, ReactiveRedisDataSource reactive) { (3)
countCommands = ds.value(Long.class); (4)
keyCommands = reactive.key(); (5)
}
long get(String key) {
Long value = countCommands.get(key); (6)
if (value == null) {
return 0L;
}
return value;
}
void set(String key, Long value) {
countCommands.set(key, value); (7)
}
void increment(String key, Long incrementBy) {
countCommands.incrby(key, incrementBy); (8)
}
Uni<Void> del(String key) {
return keyCommands.del(key) (9)
.replaceWithVoid();
}
Uni<List<String>> keys() {
return keyCommands.keys("*"); (10)
}
}
1 | キー操作のために使用するフィールド |
2 | カウンター操作のために使用するフィールド |
3 | 命令型と反応型の両方のデータソースをインジェクトします |
4 | カウンターを操作するためのコマンドを取得します |
5 | キーを操作するコマンドを取得します |
6 | 与えられたキーに関連する値を取得します null の場合は、 0 を返します |
7 | 与えられたキーに関連する値を設定します |
8 | キーが与えられた値をインクリメントします |
9 | キー(とそれに付随する値)を削除します |
10 | すべてのキーをリストアップします |
インクリメントリソースの作成
以下の内容の src/main/java/org/acme/redis/IncrementResource.java
ファイルを作成します:
package org.acme.redis;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.DELETE;
import java.util.List;
import io.smallrye.mutiny.Uni;
@Path("/increments")
public class IncrementResource {
@Inject
IncrementService service;
@GET
public Uni<List<String>> keys() {
return service.keys();
}
@POST
public Increment create(Increment increment) {
service.set(increment.key, increment.value);
return increment;
}
@GET
@Path("/{key}")
public Increment get(String key) {
return new Increment(key, service.get(key));
}
@PUT
@Path("/{key}")
public void increment(String key, long value) {
service.increment(key, value);
}
@DELETE
@Path("/{key}")
public Uni<Void> delete(String key) {
return service.del(key);
}
}
テストクラスの作成
pom.xml
ファイルを編集し、以下の依存関係を追加します:
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
src/test/java/org/acme/redis/IncrementResourceTest.java
ファイルを以下の内容で作成してください:
package org.acme.redis;
import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import io.restassured.http.ContentType;
@QuarkusTest
public class IncrementResourceTest {
@Test
public void testRedisOperations() {
// verify that we have nothing
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
// create a first increment key with an initial value of 0
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"first-key\",\"value\":0}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(0));
// create a second increment key with an initial value of 10
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"second-key\",\"value\":10}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(10));
// increment first key by 1
given()
.contentType(ContentType.JSON)
.body("1")
.when()
.put("/increments/first-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/first-key")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(1));
// increment second key by 1000
given()
.contentType(ContentType.JSON)
.body("1000")
.when()
.put("/increments/second-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/second-key")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(1010));
// verify that we have two keys in registered
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(2));
// delete first key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/first-key")
.then()
.statusCode(204);
// verify that we have one key left after deletion
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(1));
// delete second key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/second-key")
.then()
.statusCode(204);
// verify that there is no key left
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
}
}
起動
指示に従えば、Redisサーバーが起動しているはずです。あとは、アプリケーションを使って実行するだけです。
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
別のターミナルを開いて curl http://localhost:8080/increments
コマンドを実行します。
アプリケーションとの相互作用
上で見たように、APIは5つのRestエンドポイントを公開しています。このセクションでは、インクリメントを初期化する方法、現在のインクリメントのリストを見る方法、キーを指定して値をインクリメントする方法、インクリメントの現在の値を取得する方法、そして最後にキーを削除する方法を見ていきます。
新しいインクリメントの作成
curl -X POST -H "Content-Type: application/json" -d '{"key":"first","value":10}' http://localhost:8080/increments (1)
1 | 最初のインクリメントを作成し、キーは first 、初期値は 10 とします |
上記のコマンドを実行すると、以下のような結果が返ってくるはずです:
{
"key": "first",
"value": 10
}
現在のインクリメントキーの確認
現在のインクリメントキーのリストを表示するには、以下のコマンドを実行します:
curl http://localhost:8080/increments
上記のコマンドは ["first"]
を返し、これまでのところインクリメントが 1 つしかないことを示しているはずです。
新しいインクリメントの取得
キーを使ってインクリメントを取得するには、以下のコマンドを実行する必要があります:
curl http://localhost:8080/increments/first (1)
1 | このコマンドを実行すると、以下のような結果が返ってくるはずです: |
{
"key": "first",
"value": 10
}
キーが与えられた値をインクリメントします
値をインクリメントするには、以下のコマンドを実行します:
curl -X PUT -H "Content-Type: application/json" -d '27' http://localhost:8080/increments/first (1)
1 | first の値を 27 増やします。 |
さて、コマンドを実行すると curl http://localhost:8080/increments/first
は次のような結果を返します:
{
"key": "first",
"value": 37 (1)
}
1 | first キーの値が 37 になっていることがわかりますが、これはまさに簡単な計算である 10 + 27 の結果と同じです。 |
キーの削除
インクリメントのキーを指定して削除するには、以下のコマンドを使用します。
curl -X DELETE http://localhost:8080/increments/first (1)
1 | first のインクリメントを削除します。 |
さて、コマンドを実行すると curl http://localhost:8080/increments
は空のリスト []
を返します
本番環境での設定
この時点で、QuarkusはRedis Dev Serviceを使用して、Redisサーバーを実行し、アプリケーションを構成しています。 しかし、本番環境では、独自のRedisを実行することになります(または、クラウドサービスを使用します)。
以下の形で6379番ポートでRedisサーバを起動してみましょう:
docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name redis_quarkus_test -p 6379:6379 redis:5.0.6
次に、 src/main/resources/application.properties
ファイルを開き追加します:
%prod.quarkus.redis.hosts=redis://localhost:6379
JVMモードでのパッケージ化と実行
従来の jar ファイルとしてアプリケーションを実行することができます。
まず、パッケージ化します:
quarkus build
./mvnw install
./gradlew build
このコマンドはテストを実行するためのRedisインスタンスを起動します。 |
次に、以下を実行してください:
java -jar target/quarkus-app/quarkus-run.jar
ネイティブ実行
ソースコードを変更することなく、このアプリケーションからネイティブ実行可能ファイルを作成することもできます。ネイティブ実行可能ファイルは、JVMへの依存を取り除きます。ターゲットプラットフォーム上でアプリケーションを実行するために必要なすべてのものが実行ファイルに含まれているため、アプリケーションを最小限のリソースオーバーヘッドで実行することができます。
GraalVMは、不要なコードパスを削除するために追加のステップを実行するため、ネイティブ実行可能ファイルのコンパイルには少し時間がかかります。 native
プロファイルを使用して、ネイティブ実行可能ファイルをコンパイルしてください。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
ビルドが完了したら、実行可能ファイルを次のように実行することが出来ます:
./target/redis-quickstart-1.0.0-SNAPSHOT-runner
さらに詳しく
Quarkus Redisエクステンションの詳細については、 Redis エクステンションリファレンスガイド を参照してください。