CLOVER🍀

That was when it all began.

AWS SDK for Java v2に察応したAmazon SQS Java Temporary Queue ClientずLocalStackを䜿っお、䞀時キュヌRPCを詊しおみる

これは、なにをしたくお曞いたもの

以前、Amazon SQS Java Temporary Queue ClientずElasticMQを䜿っお、䞀時キュヌずRPCを䜿った゚ントリヌを曞いたこずがありたす。

Amazon SQS互換のElasticMQを使って、Temoporary Queue+RPCを試してみる - CLOVER🍀

このAmazon SQS Java Temporary Queue Clientですが、AWS SDK for Javaのバヌゞョン1を䜿っおいたのですが、2022幎の5月に
AWS SDK for Java v2を䜿うようになった2.0.0がリリヌスされおいたので、ちょっず詊しおみようかなず。

Amazon SQSの䞀時キュヌずRPC

そもそも、Amazon SQSの䞀時キュヌずRPCに぀いお思い出すずころから。

䞀時キュヌに぀いおはこちらに蚘茉があり、Amazon SQS Java Temporary Queue Clientを䜿うこずで䞀時キュヌを䜜るこずができるず
曞かれおいたす。

Amazon SQS一時キュー - Amazon Simple Queue Service

Amazon SQS Java Temporary Queue ClientのGitHubリポゞトリは、こちら。

GitHub - awslabs/amazon-sqs-java-temporary-queues-client: An Amazon SQS client that supports creating lightweight, automatically-deleted temporary queues, for use in common messaging patterns such as Request/Response. See http://aws.amazon.com/sqs.

そしお、䞀時キュヌの最も䞀般的な䜿甚䟋がリク゚スト - レスポンス型匏のメッセヌゞングパタヌンだずされおいたす。

䟋ずしお、ログむン凊理をAmazon SQSを介しお別のアプリケヌションサヌバヌ偎に凊理させ、結果を受け取るクラむアント偎ような
゜ヌスコヌドが曞かれおいたす。

同様のこずが、AWSのブログ゚ントリヌにも曞かれおいたす。

Simple Two-way Messaging using the Amazon SQS Temporary Queue Client | AWS Compute Blog

それで、以前詊した時にはAmazon SQS Java Temporary Queue ClientはAWS SDK for Java v1を䜿っおおり、v2に察しおはissueがあるだけ
だったのですが、Amazon SQS Java Temporary Queue Client 2.0.0がリリヌスされたこずで状況が倉わったようです。

Two Way Messaging - Virtual Queues · Issue #1647 · aws/aws-sdk-java-v2 · GitHub

Release Version 2.0.0 of the Amazon SQS Java Temporary Queues Client · awslabs/amazon-sqs-java-temporary-queues-client · GitHub

Amazon SQS Java Temporary Queue Client 2.0.0からは、AWS SDK for Java v2を䜿いたす。

せっかくなので、今回はAmazon SQS Java Temporary Queue Client 2.0.0ずLocalStackを䜿っお、前の゚ントリヌで曞いた内容を
曞き盎しおみようず思いたす。

環境

今回の環境は、こちら。

LocalStack。

$ python3 -V
Python 3.10.6


$ localstack --version
1.3.1

起動。

$ localstack start

AWS CLI。LocalStackの提䟛するものを重ねおいたす。

$ awslocal --version
aws-cli/2.9.21 Python/3.9.11 Linux/5.15.0-58-generic exe/x86_64.ubuntu.22 prompt/off

Java。

$ java --version
openjdk 17.0.5 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu122.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu122.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.8.7 (b89d5959fcde851dcb1c8946a785a163f14e1e29)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 17.0.5, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-58-generic", arch: "amd64", family: "unix"

準備

たずは、キュヌを䜜成する必芁がありたすね。今回はmy-queueずいう名前で䜜成したした。

$ awslocal sqs create-queue --queue-name my-queue
{
    "QueueUrl": "http://localhost:4566/000000000000/my-queue"
}

次に、Amazon SQS Java Temporary Queue Clientを䜿うためにMaven䟝存関係などの蚭定を行いたす。確認はテストコヌドで行うこずに
するので、JUnit等も合わせお远加。

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <aws-java-sdk.version>2.19.31</aws-java-sdk.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>amazon-sqs-java-temporary-queues-client</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>sqs</artifactId>
            <version>2.19.31</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.24.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>test-utils</artifactId>
            <version>2.19.31</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M7</version>
            </plugin>
        </plugins>
    </build>

Amazon SQS Java Temporary Queue Clientは以䞋で、掚移的䟝存関係の䞭にAWS SDK for Java v2も含たれおはいるのですが、

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>amazon-sqs-java-temporary-queues-client</artifactId>
            <version>2.0.0</version>
        </dependency>

ちょっず叀かったので、明瀺的に新しいバヌゞョンを指定しおおきたした。

        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>sqs</artifactId>
            <version>2.19.31</version>
        </dependency>


        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>test-utils</artifactId>
            <version>2.19.31</version>
            <scope>test</scope>
        </dependency>

簡単なEchoクラむアントサヌバヌを曞く

では、Amazon SQSの䞀時キュヌを䜿ったプログラムを曞くわけですが、前回のお題ず同様に簡単なEchoクラむアントサヌバヌを
曞いおいこうず思いたす。

クラむアントがサヌバヌにメッセヌゞを送り、サヌバヌは受け取ったメッセヌゞに簡単に装食しお返すずいうものにしたす。

たずは、LocalStack䞊のAmazon SQSにアクセスするためのSqsClientを䜜成する郚分。

src/test/java/org/littlewings/sqs/LocalSqsBuilder.java

package org.littlewings.sqs;

import java.net.URI;

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;

public class LocalSqsBuilder {
    public static SqsClient create() {
        return SqsClient
                .builder()
                .credentialsProvider(
                        StaticCredentialsProvider.create(
                                AwsBasicCredentials.create("mock", "mock")
                        )
                )
                .region(Region.US_EAST_1)
                .endpointOverride(URI.create("http://localhost:4566"))
                .build();
    }
}

クレデンシャルは固定、゚ンドポむントはLocalStackのものを指すようにしおいたす。

次に、サヌバヌを䜜成。

src/test/java/org/littlewings/sqs/TemporaryQueueRpcServer.java

package org.littlewings.sqs;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import com.amazonaws.services.sqs.AmazonSQSResponder;
import com.amazonaws.services.sqs.AmazonSQSResponderClientBuilder;
import com.amazonaws.services.sqs.MessageContent;
import com.amazonaws.services.sqs.util.SQSMessageConsumer;
import com.amazonaws.services.sqs.util.SQSMessageConsumerBuilder;
import software.amazon.awssdk.services.sqs.SqsClient;

public class TemporaryQueueRpcServer {
    SqsClient sqsClient;
    AmazonSQSResponder responder;
    SQSMessageConsumer consumer;

    TemporaryQueueRpcServer() {
    }

    public static TemporaryQueueRpcServer create(String queueUrl) {
        TemporaryQueueRpcServer server = new TemporaryQueueRpcServer();

        SqsClient sqsClient = LocalSqsBuilder.create();

        AmazonSQSResponder responder =
                AmazonSQSResponderClientBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .build();

        SQSMessageConsumer consumer =
                SQSMessageConsumerBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .withQueueUrl(queueUrl)
                        .withConsumer(requestMessage -> {
                            MessageContent requestContent = MessageContent.fromMessage(requestMessage);
                            String requestBody = requestContent.getMessageBody();

                            MessageContent responseContent = new MessageContent("★★★" + requestBody + "★★★");

                            responder.sendResponseMessage(requestContent, responseContent);
                        })
                        .build();

        server.sqsClient = sqsClient;
        server.responder = responder;
        server.consumer = consumer;

        return server;
    }

    public void start() {
        consumer.start();
    }

    public void stop() {
        consumer.close();
        responder.shutdown();
        sqsClient.close();
    }
}

こちらが受け取ったメッセヌゞを送り返すためのAmazonSQSResponder、

        AmazonSQSResponder responder =
                AmazonSQSResponderClientBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .build();

こちらがメッセヌゞを受信しお凊理を行うためのSQSMessageConsumerです。

        SQSMessageConsumer consumer =
                SQSMessageConsumerBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .withQueueUrl(queueUrl)
                        .withConsumer(requestMessage -> {
                            MessageContent requestContent = MessageContent.fromMessage(requestMessage);
                            String requestBody = requestContent.getMessageBody();

                            MessageContent responseContent = new MessageContent("★★★" + requestBody + "★★★");

                            responder.sendResponseMessage(requestContent, responseContent);
                        })
                        .build();

Amazon SQSではキュヌをポヌリングしおメッセヌゞの監芖を行うので、SQSMessageConsumerにはキュヌのURLを蚭定する必芁が
ありたす。

SQSMessageConsumer#startでキュヌの監芖が始たりたす。

    public void start() {
        consumer.start();
    }

停止はこちら。

    public void stop() {
        consumer.close();
        responder.shutdown();
        sqsClient.close();
    }

クラむアント偎は、テストコヌドずしお䜜成したす。たずは雛圢から。

src/test/java/org/littlewings/sqs/TemporaryQueueRpcTest.java

package org.littlewings.sqs;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import com.amazonaws.services.sqs.AmazonSQSRequester;
import com.amazonaws.services.sqs.AmazonSQSRequesterClientBuilder;
import com.amazonaws.services.sqs.MessageContent;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.sqs.model.Message;
import software.amazon.awssdk.services.sqs.model.SendMessageRequest;

import static org.assertj.core.api.Assertions.assertThat;

public class TemporaryQueueRpcTest {
    interface ThrowableRunnable {
        void run() throws Exception;
    }

    void withServer(String queueUrl, ThrowableRunnable runnable) throws Exception {
        TemporaryQueueRpcServer server = TemporaryQueueRpcServer.create(queueUrl);
        server.start();

        try {
            runnable.run();
        } finally {
            server.stop();
        }
    }

    // ここに、テストを曞く
}

先ほど曞いたサヌバヌの、起動ず停止を行うメ゜ッドも付けおいたす。

では、クラむアント偎を曞いおみたす。

    @Test
    void simpleRpc() throws Exception {
        String queueUrl = "http://localhost:4566/000000000000/my-queue";

        withServer(queueUrl, () -> {
            SqsClient sqsClient = LocalSqsBuilder.create();

            AmazonSQSRequester requester =
                    AmazonSQSRequesterClientBuilder
                            .standard()
                            .withAmazonSQS(sqsClient)
                            .build();

            try {
                SendMessageRequest request =
                        SendMessageRequest
                                .builder()
                                .queueUrl(queueUrl)
                                .messageBody("Hello World!!")
                                .build();

                Message responseMessage = requester.sendMessageAndGetResponse(request, 10, TimeUnit.SECONDS);
                MessageContent responseContent = MessageContent.fromMessage(responseMessage);

                System.out.println(responseMessage);
                System.out.println(responseContent.getMessageAttributes());

                assertThat(responseContent.getMessageBody()).isEqualTo("★★★Hello World!!★★★");
            } finally {
                requester.shutdown();
                sqsClient.close();
            }
        });
    }

メッセヌゞ送信を行うのは、AmazonSQSRequesterずなりたす。

            AmazonSQSRequester requester =
                    AmazonSQSRequesterClientBuilder
                            .standard()
                            .withAmazonSQS(sqsClient)
                            .build();

AmazonSQSRequester#sendMessageAndGetResponseで、メッセヌゞ送信。ここでは、同期呌び出しを行っおいたす。

                Message responseMessage = requester.sendMessageAndGetResponse(request, 10, TimeUnit.SECONDS);

結果はここで1床出力しおいたすが、

                System.out.println(responseMessage);
                System.out.println(responseContent.getMessageAttributes());

それぞれ、こちらず

Message(MessageId=2f0e38ea-8440-4247-ab9b-260306b29273, ReceiptHandle=NDA5OWM0ZWUtOTEzMi00YTUzLThlMDEtOTkyZGFiNGNiYzkxIGFybjphd3M6c3FzOnVzLWVhc3QtMTowMDAwMDAwMDAwMDA6X19SZXF1ZXN0ZXJDbGllbnRRdWV1ZXNfX2ViOTNlNDkyLWFhOGYtNGNlNC04NGI1LWZiZDQwMzllMDRkNC0wIDJmMGUzOGVhLTg0NDAtNDI0Ny1hYjliLTI2MDMwNmIyOTI3MyAxNjc1NjA5Njk2LjE5MDY1OQ==, MD5OfBody=b14f6a41b31fd409988bec57f9a1a5cb, Body=★★★Hello World!!★★★, Attributes={ApproximateReceiveCount=1, SentTimestamp=1675609696169, SenderId=000000000000, ApproximateFirstReceiveTimestamp=1675609696190}, MD5OfMessageAttributes=d3d6adc048d9998de883abfd0e923eca, MessageAttributes={__AmazonSQSVirtualQueuesClient.QueueName=MessageAttributeValue(StringValue=__RequesterClientQueues__2a96b18c-ab99-4e99-a48f-d6c4b92043f1, DataType=String)})

こちらですね。

{__AmazonSQSVirtualQueuesClient.QueueName=MessageAttributeValue(StringValue=__RequesterClientQueues__2a96b18c-ab99-4e99-a48f-d6c4b92043f1, DataType=String)}

呌び出しが終わったら、それぞれ停止。

                requester.shutdown();
                sqsClient.close();

送信するメッセヌゞを増やしおみる

次に、送信するメッセヌゞを増やしお、ちゃんずRPCずしお動䜜できおいるか確認しおみたいず思いたす。

たずはサヌバヌ偎。メッセヌゞごずに、ランダムにスリヌプするようにしおみたす。

src/test/java/org/littlewings/sqs/TemporaryQueueRpcSCerver.java

// 省略

public class TemporaryQueueRpcServer {

    // 省略

    public static TemporaryQueueRpcServer createRandomSleep(String queueUrl) {
        Random random = new Random();
        random.nextInt(10);

        TemporaryQueueRpcServer server = new TemporaryQueueRpcServer();

        SqsClient sqsClient = LocalSqsBuilder.create();

        AmazonSQSResponder responder =
                AmazonSQSResponderClientBuilder.standard()
                        .withAmazonSQS(sqsClient)
                        .build();

        SQSMessageConsumer consumer =
                SQSMessageConsumerBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .withQueueUrl(queueUrl)
                        .withPollingThreadCount(5)
                        .withConsumer(requestMessage -> {
                            MessageContent requestContent = MessageContent.fromMessage(requestMessage);
                            String requestBody = requestContent.getMessageBody();

                            MessageContent responseContent = new MessageContent("★★★" + requestBody + "★★★");

                            try {
                                int sleepTime = random.nextInt(10);
                                System.out.printf("Server[%s]: %d sec sleep%n", Thread.currentThread().getName(), sleepTime);
                                TimeUnit.SECONDS.sleep(sleepTime);
                            } catch (InterruptedException e) {
                                // ignore
                            }

                            responder.sendResponseMessage(requestContent, responseContent);
                        })
                        .build();

        server.sqsClient = sqsClient;
        server.responder = responder;
        server.consumer = consumer;

        return server;
    }

    // 省略
}

前回ElasticMQで詊した時はポヌリングするスレッド数を増やすず挙動が䞍安定になりたしたが、今回はそうはなりたせんでした。

        SQSMessageConsumer consumer =
                SQSMessageConsumerBuilder
                        .standard()
                        .withAmazonSQS(sqsClient)
                        .withQueueUrl(queueUrl)
                        .withPollingThreadCount(5)

メッセヌゞを受信した埌は、ランダムにスリヌプさせおいたす。

                        .withConsumer(requestMessage -> {
                            MessageContent requestContent = MessageContent.fromMessage(requestMessage);
                            String requestBody = requestContent.getMessageBody();

                            MessageContent responseContent = new MessageContent("★★★" + requestBody + "★★★");

                            try {
                                int sleepTime = random.nextInt(10);
                                System.out.printf("Server[%s]: %d sec sleep%n", Thread.currentThread().getName(), sleepTime);
                                TimeUnit.SECONDS.sleep(sleepTime);
                            } catch (InterruptedException e) {
                                // ignore
                            }

続いお、クラむアント偎。50個のメッセヌゞを送るようにしおみたす。

src/test/java/org/littlewings/sqs/TemporaryQueueRpcTest.java

// 省略

public class TemporaryQueueRpcTest {

    // 省略

    void withRandomSleepServer(String queueUrl, ThrowableRunnable runnable) throws Exception {
        TemporaryQueueRpcServer server = TemporaryQueueRpcServer.createRandomSleep(queueUrl);
        server.start();

        try {
            runnable.run();
        } finally {
            server.stop();
        }
    }

    @Test
    public void concurrent() throws Exception {
        String queueUrl = "http://localhost:4566/000000000000/my-queue";

        withRandomSleepServer(queueUrl, () -> {
            SqsClient sqsClient = LocalSqsBuilder.create();

            AmazonSQSRequester requester =
                    AmazonSQSRequesterClientBuilder
                            .standard()
                            .withAmazonSQS(sqsClient)
                            .build();

            try {
                Map<String, CompletableFuture<Message>> futures = new LinkedHashMap<>();

                for (int i = 0; i < 50; i++) {
                    String uuid = UUID.randomUUID().toString();
                    SendMessageRequest request =
                            SendMessageRequest
                                    .builder()
                                    .queueUrl(queueUrl)
                                    .messageBody(uuid)
                                    .build();

                    CompletableFuture<Message> responseMessage = requester.sendMessageAndGetResponseAsync(request, 60, TimeUnit.SECONDS);

                    futures.put(uuid, responseMessage);
                }

                assertThat(futures).hasSize(50);

                futures.forEach((uuid, message) -> {
                    long start = System.currentTimeMillis();
                    MessageContent responseContent = MessageContent.fromMessage(message.join());
                    System.out.println("elapsed: " + (System.currentTimeMillis() - start) / 1000.0 + " sec");
                    assertThat(responseContent.getMessageBody()).isEqualTo("★★★" + uuid + "★★★");
                });
            } finally {
                requester.shutdown();
                sqsClient.close();
            }
        });
    }
}

送信するメッセヌゞの内容は、リク゚ストごずに別々になるようにUUIDにしおみたした。

                    String uuid = UUID.randomUUID().toString();
                    SendMessageRequest request =
                            SendMessageRequest
                                    .builder()
                                    .queueUrl(queueUrl)
                                    .messageBody(uuid)
                                    .build();

メッセヌゞの送信は、AmazonSQSRequester#sendMessageAndGetResponseAsyncを䜿っお非同期に倉曎。

                    CompletableFuture<Message> responseMessage = requester.sendMessageAndGetResponseAsync(request, 60, TimeUnit.SECONDS);

これで、期埅のメッセヌゞが凊理できおいるか確認。

                assertThat(futures).hasSize(50);

                futures.forEach((uuid, message) -> {
                    long start = System.currentTimeMillis();
                    MessageContent responseContent = MessageContent.fromMessage(message.join());
                    System.out.println("elapsed: " + (System.currentTimeMillis() - start) / 1000.0 + " sec");
                    assertThat(responseContent.getMessageBody()).isEqualTo("★★★" + uuid + "★★★");
                });

リク゚ストずレスポンスの内容が察になっおいたので、今回もRPCずしお動䜜できおいるこずは確認できたした。

ただ、今回の環境ではメッセヌゞをたくさん送るずサヌバヌ偎である皋床メッセヌゞを凊理しきらないずクラむアントにメッセヌゞが
返らないようで、今回の曞き方だず最初に送ったメッセヌゞを受け取るたでの時間がかなり長くなったりしたす。
しかも安定しおいない感じがするので、このあたりは本圓に䜿うならちゃんずしたAmazon SQSで挙動を確認した方が良さそうですね。

ずりあえず、Amazon SQS Java Temporary Queue Clientの2.0.0ず䞀時キュヌを䜿っおRPCを行うずいう目的は達成できたので、
良しずしたすか。

たずめ

2.0.0になったAmazon SQS Java Temporary Queue ClientずLocalStackを䜿っお、䞀時キュヌずRPCを詊しおみたした。
前回はけっこうハマったのですが、今回はそうでもなかったですね。ElasticMQでなくおも、LocalStackでも動きたしたし。

ただ、たくさんメッセヌゞを送った時の動きが䞍安定なのは今回も倉わらなかったので、実際の挙動は本物を䜿っお確認、ずいうのが
正解だろうずいう感芚も倉わりたせんが、やりやすくなったのは良かったかなず思いたす。

AWS SDK for Java v1の制玄もなくなりたしたし。

Infinispan 14.0で実隓的にサポヌトされた、io_uringを有効にしおみる

これは、なにをしたくお曞いたもの

前に、NettyのincubatorプロゞェクトであるNetty io_uringを詊しおみる゚ントリヌを曞きたした。

TCP Echo Server/Clientを書いて、Netty io_uringを試してみる - CLOVER🍀

Infinispanでも14.0.0.Finalから、Netty io_uringを䜿えるようになっおいるずいうこずなので、詊しおみたいず思いたす。

Infinispan 14.0.0.Final

io_uringに぀いお

io_uringは、Linuxカヌネル5.1から導入された、非同期IO甚のAPIです。こちらにも、少し曞いおおきたした。

TCP Echo Server/Clientを書いて、Netty io_uringを試してみる - CLOVER🍀

Infinispan 14.0ずNetty io_uring

Infinispan 14.0.0.Finalのリリヌス時のブログ゚ントリヌを芋おみるず、Infinispan Serverで実隓的にio_uringをサポヌトしたこずが
曞かれおいたす。

Server

  • Experimental IO_Uring support

Infinispan 14.0.0.Final

情報は、䟋によっおこれだけです。どうやったらio_uringを䜿うようになるかですら、情報がありたせん。

ずりあえず、Infinispan Serverをダりンロヌドしおみたしょう。

$ curl -LO https://downloads.jboss.org/infinispan/14.0.6.Final/infinispan-server-14.0.6.Final.zip
$ unzip infinispan-server-14.0.6.Final.zip
$ cd infinispan-server-14.0.6.Final

libディレクトリには、Netty io_uringのラむブラリがありたした。

$ ll lib/*io_uring*
-rw-r--r-- 1 xxxxx xxxxx 99211  1月 19 03:23 lib/netty-incubator-transport-classes-io_uring-0.0.14.Final.jar
-rw-r--r-- 1 xxxxx xxxxx  5563  1月 19 03:23 lib/netty-incubator-transport-native-io_uring-0.0.14.Final.jar
-rw-r--r-- 1 xxxxx xxxxx 37477  1月 19 03:23 lib/netty-incubator-transport-native-io_uring-linux-aarch_64-0.0.14.Final.jar
-rw-r--r-- 1 xxxxx xxxxx 36251  1月 19 03:23 lib/netty-incubator-transport-native-io_uring-linux-x86_64-0.0.14.Final.jar

ずいうわけで、Infinispan ServerでもNetty io_uringを䜿うようですね。

なにも考えずに、Infinispan Serverを起動しおみたす。

$ bin/server.sh

するず、ログの䞭にこんな衚蚘が混じっおいるこずに気づきたす。

2023-02-05 18:24:12,669 INFO  (main) [org.infinispan.SERVER] Using transport: Epoll

デフォルトではepollを䜿うようなので、これをio_uringに倉曎しおみるのが今回のお題です。

環境

今回の環境は、こちら。

Ubuntu Linux 22.04 LTSで、カヌネルは5.15です。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
Codename:       jammy


$ uname -srmvpio
Linux 5.15.0-58-generic #64-Ubuntu SMP Thu Jan 5 11:43:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Java。

$ java --version
openjdk 17.0.5 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu122.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu122.04, mixed mode, sharing)

Infinispan ServerでNetty io_uringを䜿う

Infinispan Serverの゜ヌスコヌドを芋おいるず、以䞋の3぀の条件を満たしおいるずNetty io_uringを䜿っおくれるようですね。

  • epollを䜿わないようにしおいるシステムプロパティinfinispan.server.channel.epollをfalseにする
  • システムプロパティinfinispan.server.channel.iouringがtrueになっおいるデフォルト倀
  • 実行環境OSがLinuxである
  • io.netty.incubator.channel.uring.IOUringクラスが、クラスパス䞊に存圚する
  • Netty io_uringがio_uringを䜿える状態だず認識しおいる

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/NativeTransport.java#L19

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/NativeTransport.java#L22

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/NativeTransport.java#L48-L50

優先順䜍を芋おみるず、EpollServerSocketChannel → IOUringServerSocketChannel → NioServerSocketChannelずなっおいるので、
epollを無効にしないずio_uringが遞ばれないこずになりたす。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/NativeTransport.java#L65-L75

これらの条件を満たしおいるず、IOUringEventLoopGroupやIOUringServerSocketChannelを䜿っおくれるこずになりたす。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/IOURingNativeTransport.java

ずいうわけで、システムプロパティinfinispan.server.channel.epollをfalseにしお、epollを䜿わないようにしお起動しおみたしょう。

$ bin/server.sh -Dinfinispan.server.channel.epoll=false

するず、ログから以䞋のようにNetty io_uringを䜿うように倉わったこずがわかりたす。

2023-02-05 18:38:35,690 INFO  (main) [org.infinispan.SERVER] Using transport: IOUring

確認のために、straceでシステムコヌルを芋おみたしょう。

$ strace -f -tt bin/server.sh -Dinfinispan.server.channel.epoll=false 2>&1 | grep io_uring

芋おみるず、io_uringのシステムコヌルを䜿っおいるこずが確認できたす。

[pid  7926] 18:44:13.963512 io_uring_setup(4096, {flags=0, sq_thread_cpu=0, sq_thread_idle=0, sq_entries=4096, cq_entries=8192, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS, sq_off={head=0, tail=64, ring_mask=256, ring_entries=264, flags=276, dropped=272, array=131392}, cq_off={head=128, tail=192, ring_mask=260, ring_entries=268, overflow=284, cqes=320, flags=280}}) = 185
[pid  7926] 18:44:13.970822 io_uring_register(185, IORING_REGISTER_PROBE, {last_op=IORING_OP_LINKAT, ops_len=40, ops=[{op=IORING_OP_NOP, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_READV, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_WRITEV, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_FSYNC, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_READ_FIXED, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_WRITE_FIXED, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_POLL_ADD, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_POLL_REMOVE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_SYNC_FILE_RANGE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_SENDMSG, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_RECVMSG, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_TIMEOUT, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_TIMEOUT_REMOVE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_ACCEPT, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_ASYNC_CANCEL, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_LINK_TIMEOUT, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_CONNECT, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_FALLOCATE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_OPENAT, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_CLOSE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_FILES_UPDATE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_STATX, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_READ, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_WRITE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_FADVISE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_MADVISE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_SEND, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_RECV, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_OPENAT2, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_EPOLL_CTL, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_SPLICE, flags=IO_URING_OP_SUPPORTED}, {op=IORING_OP_PROVIDE_BUFFERS, flags=IO_URING_OP_SUPPORTED}, ...]}, 256) = 0
[pid  7926] 18:44:14.041339 io_uring_setup(4096, {flags=0, sq_thread_cpu=0, sq_thread_idle=0, sq_entries=4096, cq_entries=8192, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS, sq_off={head=0, tail=64, ring_mask=256, ring_entries=264, flags=276, dropped=272, array=131392}, cq_off={head=128, tail=192, ring_mask=260, ring_entries=268, overflow=284, cqes=320, flags=280}}) = 185
[pid  7926] 18:44:14.042557 io_uring_setup(4096, {flags=0, sq_thread_cpu=0, sq_thread_idle=0 <unfinished ...>
[pid  7926] 18:44:14.043615 <... io_uring_setup resumed>, sq_entries=4096, cq_entries=8192, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS, sq_off={head=0, tail=64, ring_mask=256, ring_entries=264, flags=276, dropped=272, array=131392}, cq_off={head=128, tail=192, ring_mask=260, ring_entries=268, overflow=284, cqes=320, flags=280}}) = 188
[pid  7926] 18:44:14.044349 io_uring_setup(4096, {flags=0, sq_thread_cpu=0, sq_thread_idle=0, sq_entries=4096, cq_entries=8192, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS, sq_off={head=0, tail=64, ring_mask=256, ring_entries=264, flags=276, dropped=272, array=131392}, cq_off={head=128, tail=192, ring_mask=260, ring_entries=268, overflow=284, cqes=320, flags=280}}) = 189
[pid  7926] 18:44:14.045776 io_uring_setup(4096, {flags=0, sq_thread_cpu=0, sq_thread_idle=0, sq_entries=4096, cq_entries=8192, features=IORING_FEAT_SINGLE_MMAP|IORING_FEAT_NODROP|IORING_FEAT_SUBMIT_STABLE|IORING_FEAT_RW_CUR_POS|IORING_FEAT_CUR_PERSONALITY|IORING_FEAT_FAST_POLL|IORING_FEAT_POLL_32BITS|IORING_FEAT_SQPOLL_NONFIXED|IORING_FEAT_EXT_ARG|IORING_FEAT_NATIVE_WORKERS|IORING_FEAT_RSRC_TAGS, sq_off={head=0, tail=64, ring_mask=256, ring_entries=264, flags=276, dropped=272, array=131392}, cq_off={head=128, tail=192, ring_mask=260, ring_entries=268, overflow=284, cqes=320, flags=280}}) = 191
[pid  7957] 18:44:18.154084 io_uring_enter(185, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7958] 18:44:18.164140 io_uring_enter(188, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7959] 18:44:18.443682 io_uring_enter(189, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7961] 18:44:18.445582 io_uring_enter(191, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7957] 18:44:19.048567 <... io_uring_enter resumed>) = 1
[pid  7957] 18:44:19.048858 io_uring_enter(185, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7958] 18:44:19.156755 <... io_uring_enter resumed>) = 1
[pid  7958] 18:44:19.157795 io_uring_enter(188, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7959] 18:44:19.160497 <... io_uring_enter resumed>) = 1
[pid  7959] 18:44:19.160678 io_uring_enter(189, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>
[pid  7961] 18:44:19.391462 <... io_uring_enter resumed>) = 1
[pid  7957] 18:44:19.464994 <... io_uring_enter resumed>) = 1
[pid  7957] 18:44:19.465651 io_uring_enter(185, 1, 1, IORING_ENTER_GETEVENTS, NULL, 139637976727560 <unfinished ...>

ちなみに、興味本䜍ですが、AlmaLinux 8のような、カヌネルが5.1よりも䜎いLinuxで詊すずこうなりたした。

$ uname -srvmpio
Linux 4.18.0-425.3.1.el8.x86_64 #1 SMP Tue Nov 8 14:08:25 EST 2022 x86_64 x86_64 x86_64 GNU/Linux


$ bin/server.sh -Dinfinispan.server.channel.epoll=false

NioServerSocketChannelが遞ばれおいたす。

2023-02-05 18:53:47,839 INFO  (main) [org.infinispan.SERVER] Using transport: NIO

これは、io_uringが䜿える環境ではないずNetty io_uringが刀定するからですね。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/server/core/src/main/java/org/infinispan/server/core/transport/NativeTransport.java#L49

https://github.com/netty/netty-incubator-transport-io_uring/blob/netty-incubator-transport-parent-io_uring-0.0.14.Final/transport-classes-io_uring/src/main/java/io/netty/incubator/channel/uring/IOUring.java#L25-L58

Hot Rod Clientは

ずころで、Infinispanのリポゞトリをio_uringで調べおいるず、どうもInfinispan Server以倖にもNetty io_uringを䜿っおいるず思われる箇所が
芋぀かりたす。

Hot Rod Clientですね。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/netty/NativeTransport.java

ずいうわけで、こちらも詊しおみたしょう。

䜿甚するMavenのバヌゞョン。

$ mvn --version
Apache Maven 3.8.7 (b89d5959fcde851dcb1c8946a785a163f14e1e29)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 17.0.5, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-58-generic", arch: "amd64", family: "unix"

Infinispan Serverは、172.18.0.2〜172.18.0.4で3ノヌド起動させ、クラスタヌを構成しおおくこずにしたす。

起動コマンドは、こちら。

$ bin/server.sh \
    -b 0.0.0.0 \
    -Djgroups.tcp.address=$(hostname -i) \
    -Dinfinispan.server.channel.epoll=false

各Infinispan Serverには、管理甚ナヌザヌ、アプリケヌション甚ナヌザヌをそれぞれ䜜成しおおきたす。

$ bin/cli.sh user create -g admin -p password ispn-admin
$ bin/cli.sh user create -g application -p password ispn-user

Maven䟝存関係等は、たずはこんな感じで甚意。

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>14.0.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>14.0.6.Final</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.24.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M7</version>
            </plugin>
        </plugins>
    </build>

簡単なテストコヌドを曞いお、確認しおみたす。

src/test/java/org/littlewings/infinspan/remote/iouring/HotRodClientIoUringTest.java

package org.littlewings.infinspan.remote.iouring;

import java.util.function.Consumer;
import java.util.stream.IntStream;

import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.RemoteCacheManager;
import org.infinispan.client.hotrod.RemoteCacheManagerAdmin;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class HotRodClientIoUringTest {
    static String createUri(String userName, String password) {
        return String.format(
                "hotrod://%s:%s@172.18.0.2:11222,172.18.0.3:11222,172.18.0.4:11222",
                userName,
                password
        );
    }

    @BeforeAll
    static void setUpAll() {
        String uri = createUri("ispn-admin", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCacheManagerAdmin admin = manager.administration();

            admin.removeCache("distCache");

            org.infinispan.configuration.cache.Configuration configuration =
                    new org.infinispan.configuration.cache.ConfigurationBuilder()
                            .clustering()
                            .cacheMode(org.infinispan.configuration.cache.CacheMode.DIST_SYNC)
                            .encoding().key().mediaType("application/x-protostream")
                            .encoding().value().mediaType("application/x-protostream")
                            .build();

            admin.getOrCreateCache("distCache", configuration);
        }
    }

    <K, V> void withCache(String cacheName, Consumer<RemoteCache<K, V>> func) {
        String uri = createUri("ispn-user", "password");

        try (RemoteCacheManager manager = new RemoteCacheManager(uri)) {
            RemoteCache<K, V> cache = manager.getCache(cacheName);

            func.accept(cache);
        }
    }

    @Test
    void transportIoUring() {
        this.<String, String>withCache("distCache", cache -> {
            IntStream
                    .rangeClosed(1, 100)
                    .forEach(i -> cache.put("key" + i, "value" + i));

            IntStream
                    .rangeClosed(1, 100)
                    .forEach(i -> assertThat(cache.get("key" + i)).isEqualTo("value" + i));
        });
    }
}

確認。

$ mvn test

このテスト自䜓は動くのですが、io_uringは䜿えないずいった感じのログが出たす。

2月 05, 2023 7:37:16 午埌 org.infinispan.client.hotrod.impl.transport.netty.NativeTransport useNativeIOUring
INFO: ISPN004108: Native IOUring transport not available, using NIO instead: io.netty.incubator.channel.uring.IOUring

どうやらクラスパス䞊にio.netty.incubator.channel.uring.IOUringクラスがなく、か぀Hot Rod Clientのpom.xmlを芋るず
Netty io_uringはオプションになっおいるようです。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/client/hotrod-client/pom.xml#L103-L121

ずいうわけで、䟝存関係にNetty io_uringを远加したす。

        <dependency>
            <groupId>io.netty.incubator</groupId>
            <artifactId>netty-incubator-transport-native-io_uring</artifactId>
            <version>0.0.14.Final</version>
            <classifier>linux-x86_64</classifier>
        </dependency>

バヌゞョンは、Infinispanが䜿甚しおいるものに合わせおおきたす。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/build/configuration/pom.xml#L184

再床実行。

$ mvn test

transportに関するログがなくなったので、io_uringが䜿われおいるかどうかもわからなくなりたした 。
Infinispan Serverず違っお、どのトランスポヌトを遞択したのかを瀺すログは出力されないんですよね。

straceで確認するず、io_uringを䜿っおいなさそうだったので

$ strace -f mvn test 2>&1 | grep io_uring

゜ヌスコヌドの感じからしお、やっぱりepollを無効にする必芁がありそうです。

https://github.com/infinispan/infinispan/blob/14.0.6.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/transport/netty/NativeTransport.java#L64-L72

システムプロパティで指定しお実行。

$ mvn test -Dinfinispan.server.channel.epoll=false

やっぱり芋かけ䞊はわからないので、straceで確認するず

$ strace -f mvn test -Dinfinispan.server.channel.epoll=false 2>&1 | grep io_uring

io_uringに関するシステムコヌルが䜿われおいるこずが確認できたす。

[pid 25604] <... io_uring_enter resumed>) = 2
[pid 25604] io_uring_enter(93, 2, 1, IORING_ENTER_GETEVENTS, NULL, 140217797312520 <unfinished ...>
[pid 25604] <... io_uring_enter resumed>) = 2
[pid 25604] io_uring_enter(93, 2, 1, IORING_ENTER_GETEVENTS, NULL, 140217797312520 <unfinished ...>
[pid 25604] <... io_uring_enter resumed>) = 2
[pid 25604] io_uring_enter(93, 0, 1, IORING_ENTER_GETEVENTS, NULL, 30064771080 <unfinished ...>
[pid 25604] <... io_uring_enter resumed>) = 0

最終的なMaven䟝存関係などを曞くず、こうなりたした。

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-client-hotrod</artifactId>
            <version>14.0.6.Final</version>
        </dependency>
        <dependency>
            <groupId>io.netty.incubator</groupId>
            <artifactId>netty-incubator-transport-native-io_uring</artifactId>
            <version>0.0.14.Final</version>
            <classifier>linux-x86_64</classifier>
        </dependency>

        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>14.0.6.Final</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.24.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M7</version>
            </plugin>
        </plugins>
    </build>

それから、システムプロパティの指定は今回の䟋だず゜ヌスコヌドにそのたた曞いおも良いかなず。

public class HotRodClientIoUringTest {
    static {
        System.setProperty("infinispan.server.channel.epoll", "false");
    }

ずりあえず、io_uringを䜿うようにはできたので、良しずしたしょう。

たずめ

Infinispanで、io_uringを䜿うようにしおみたした。

Infinispan Serverだけかなず思っおいたのですが、Hot Rod Client偎も察応しおいたんですね。ただ、新しいHot Rod Clientの方は察応しお
いないようでしたが。

今回䜜成した゜ヌスコヌドは、こちらに眮いおいたす。

https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-experimental-io_uring