Skip to content

Commit

Permalink
Document io_uring
Browse files Browse the repository at this point in the history
  • Loading branch information
cescoffier committed May 23, 2023
1 parent eaaeab9 commit f8e326b
Showing 1 changed file with 134 additions and 44 deletions.
178 changes: 134 additions & 44 deletions docs/src/main/asciidoc/vertx-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ As described in the xref:quarkus-reactive-architecture.adoc[Quarkus Reactive Arc
This guide is the companion to the xref:vertx.adoc[Using Eclipse Vert.x API from a Quarkus Application] guide.
It provides more advanced details about the usage and the configuration of the Vert.x instance used by Quarkus.


[#vertx-access]
== Accessing the Vert.x instance
== Access the Vert.x instance

To access the managed Vert.x instance, add the `quarkus-vertx` extension to your project.
Note that this dependency may already be installed (as a transitive dependency).
This dependency might already be available in your project (as a transitive dependency).

With this extension, you can retrieve the managed instance of Vert.x using either field or constructor injection:

Expand Down Expand Up @@ -54,25 +53,26 @@ If you are not familiar with Mutiny, check xref:mutiny-primer.adoc[Mutiny - an i
Documentation about the Vert.x Mutiny variant is available on https://smallrye.io/smallrye-mutiny-vertx-bindings.

[[vertx-config]]
== Configuring the Vert.x instance
== Configure the Vert.x instance

You can configure the Vert.x instance from the `application.properties` file.
The following table lists the supported properties:

include::{generated-dir}/config/quarkus-vertx-core.adoc[opts=optional, leveloffset=+1]

See <<customizing-the-vert-x-configuration>> to configure the Vert.x instance using a programmatic approach.

[[using-vertx-clients]]
== Using Vert.x clients
== Use Vert.x clients

In addition to Vert.x core, you can use most Vert.x ecosystem libraries.
Some Quarkus extension already wraps Vert.x libraries.

=== Available APIs

The following table lists the most used libraries from the Vert.x ecosystem.
The following table lists the **most** used libraries from the Vert.x ecosystem.
To access these APIs, add the indicated extension or dependency to your project.
Refer to the associated documentation to learn how to use them.
Check the associated documentation to learn how to use them.

[cols="1,1,1",stripes=even,options=headers]
|===
Expand Down Expand Up @@ -140,7 +140,7 @@ Refer to the associated documentation to learn how to use them.

To learn more about the usage of the Vert.x Mutiny API, refer to https://smallrye.io/smallrye-mutiny-vertx-bindings.

=== Example of usage
=== Use the Vert.x Web Client

This section gives an example using the Vert.x `WebClient` in the context of a RESTEasy Reactive application.
As indicated in the table above, add the following dependency to your project:
Expand Down Expand Up @@ -230,7 +230,7 @@ Then, create the native executable with:
include::{includes}/devtools/build-native.adoc[]

[#using-vert-x-json]
== Using Vert.x JSON
== Use Vert.x JSON

Vert.x APIs often rely on JSON.
Vert.x provides two convenient classes to manipulate JSON document: `io.vertx.core.json.JsonObject` and `io.vertx.core.json.JsonArray`.
Expand Down Expand Up @@ -302,7 +302,7 @@ http://localhost:8080/hello/Quarkus/array returns:

This works equally well when the JSON content is a request body or is wrapped in a `Uni`, `Multi`, `CompletionStage` or `Publisher`.

== Using verticles
== Use verticles

link:https://vertx.io/docs/vertx-core/java/#_verticles[Verticles] is "a simple, scalable, actor-like deployment and concurrency model" provided by _Vert.x_.
This model does not claim to be a strict actor-model implementation, but it shares similarities, especially concerning concurrency, scaling, and deployment.
Expand All @@ -314,7 +314,7 @@ It supports:
* _bare_ verticle - Java classes extending `io.vertx.core.AbstractVerticle`
* _Mutiny_ verticle - Java classes extending `io.smallrye.mutiny.vertx.core.AbstractVerticle`

=== Deploying verticles
=== Deploy verticles

To deploy verticles, use the `deployVerticle` method:

Expand All @@ -331,7 +331,7 @@ If you use the Mutiny-variant of Vert.x, be aware that the `deployVerticle` meth

NOTE: An example explaining how to deploy verticles during the initialization of the application will follow.

=== Using @ApplicationScoped Beans as Verticle
=== Use @ApplicationScoped Beans as Verticle

In general, Vert.x verticles are not CDI beans.
And so cannot use injection.
Expand Down Expand Up @@ -398,7 +398,7 @@ public void init(@Observes StartupEvent e, Vertx vertx, Instance<AbstractVerticl
}
----

=== Using multiple verticles instances
=== Create multiple verticles instances

When using `@ApplicationScoped`, you will get a single instance for your verticle.
Having multiple instances of verticles can be helpful to share the load among them.
Expand Down Expand Up @@ -463,7 +463,7 @@ Finally, you pass the desired number of instances to the `DeploymentOptions`, su
It will call the supplier twice, which will create two instances of your verticle.

[#eventbus]
== Using the event bus
== Use the Event Bus

Vert.x comes with a built-in https://vertx.io/docs/vertx-core/java/#event_bus[event bus] that you can use from your Quarkus application.
So, your application components (CDI beans, resources...) can interact using asynchronous events, thus promoting loose-coupling.
Expand All @@ -477,7 +477,7 @@ The event bus offers three types of delivery mechanisms:

All these delivery mechanisms are non-blocking and are providing one of the fundamental bricks to build reactive applications.

=== Consuming events
=== Consume Events

While you can use the Vert.x API to register consumers, Quarkus comes with declarative support.
To consume events, use the `io.quarkus.vertx.ConsumeEvent` annotation:
Expand All @@ -502,7 +502,7 @@ public class GreetingService {
<1> If not set, the address is the fully qualified name of the bean; for instance, in this snippet, it's `org.acme.vertx.GreetingService`.
<2> The method parameter is the message body. If the method returns _something_, it's the message response.

=== Configuring the address
=== Configure the Address

The `@ConsumeEvent` annotation can be configured to set the address:

Expand All @@ -515,7 +515,7 @@ public String consume(String name) {
----
<1> Receive the messages sent to the `greeting` address

=== Asynchronous processing
=== Process Events asynchronously

The previous examples use synchronous processing.
Asynchronous processing is also possible by returning either an `io.smallrye.mutiny.Uni` or a `java.util.concurrent.CompletionStage`:
Expand All @@ -534,12 +534,6 @@ import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class GreetingService {
@ConsumeEvent
public CompletionStage<String> consume(String name) {
// return a CompletionStage completed when the processing is finished.
// You can also fail the CompletionStage explicitly
}
@ConsumeEvent
public Uni<String> process(String name) {
// return an Uni completed when the processing is finished.
Expand All @@ -555,7 +549,7 @@ The previous example uses Mutiny reactive types.
If you are not familiar with Mutiny, check xref:mutiny-primer.adoc[Mutiny - an intuitive reactive programming library].
====

=== Blocking processing
=== Blocking Processing of Events

By default, the code consuming the event must be _non-blocking_, as it's called on an I/O thread.
If your processing is blocking, use the `@io.smallrye.common.annotation.Blocking` annotation:
Expand All @@ -581,7 +575,7 @@ void consumeBlocking(String message) {

When using `@Blocking`, it ignores the value of the `blocking` attribute of `@ConsumeEvent`.

=== Replying to messages
=== Reply to Events

The _return_ value of a method annotated with `@ConsumeEvent` is used to respond to the incoming message.
For instance, in the following snippet, the returned `String` is the response.
Expand Down Expand Up @@ -613,7 +607,7 @@ You can inject an `executor` if you use the Context Propagation extension:
----
====

=== Implementing fire and forget interactions
=== Implement Fire-And-Forget Interactions

You don't have to reply to received messages.
Typically, for a _fire and forget_ interaction, the messages are consumed, and the sender does not need to know about it.
Expand All @@ -627,7 +621,7 @@ public void consume(String event) {
}
----

=== Dealing with messages
=== Consume Messages (instead of events)

Unlike the previous example using the _payloads_ directly, you can also use `Message` directly:

Expand All @@ -640,14 +634,14 @@ public void consume(Message<String> msg) {
}
----

=== Handling Failures
=== Handle Failures

If a method annotated with `@ConsumeEvent` throws an exception, then:

* if a reply handler is set, then the failure is propagated back to the sender via an `io.vertx.core.eventbus.ReplyException` with code `ConsumeEvent#FAILURE_CODE` and the exception message,
* if no reply handler is set, then the exception is rethrown (and wrapped in a `RuntimeException` if necessary) and can be handled by the default exception handler, i.e. `io.vertx.core.Vertx#exceptionHandler()`.
* if no reply handler is set, then the exception is rethrown (and wrapped in a `RuntimeException` if necessary) and can be handled by the default exception handler, _i.e._ `io.vertx.core.Vertx#exceptionHandler()`.

=== Sending messages
=== Send Messages

Sending and publishing messages use the Vert.x event bus:

Expand Down Expand Up @@ -700,7 +694,7 @@ Uni<String> response = bus.<String>request("address", "hello, how are you?")
.onItem().transform(Message::body);
----

=== Using codecs
=== Use Codecs

The https://vertx.io/docs/vertx-core/java/#event_bus[Vert.x Event Bus] uses codecs to _serialize_ and _deserialize_ objects.
Quarkus provides a default codec for local delivery.
Expand Down Expand Up @@ -743,7 +737,7 @@ Uni<String> greeting(MyName name) {
<1> Set the name of the codec to use to send the message
<2> Set the codec to use to receive the message

=== Combining HTTP and the event bus
=== Combine HTTP and the Event Bus

Let's revisit a greeting HTTP endpoint and use asynchronous message passing to delegate the call to a separated bean.
It uses the request/reply dispatching mechanism.
Expand Down Expand Up @@ -828,7 +822,7 @@ To better understand, let's detail how the HTTP request/response has been handle
5. Once the reply is received by the sender, the content is written to the HTTP response


=== Bidirectional communication with browsers using SockJS
=== Bidirectional Communication with Browsers using SockJS

The SockJS bridge provided by Vert.x allows browser applications and Quarkus applications to communicate using the event bus.
It connects both sides.
Expand Down Expand Up @@ -910,14 +904,16 @@ The browser must use the `vertx-eventbus` JavaScript library to consume the mess
----

[#native-transport]
== Native Transport
== Use Native Transports

IMPORTANT: Native transports are not supported in native executables.

IMPORTANT: Native transports are not supported in GraalVM produced binaries.
NOTE: To use `io_uring`, refer to the <<use-io_uring>> section.

Vert.x is capable of using https://netty.io/wiki/native-transports.html[Netty's native transports], which offers
performance improvements on specific platforms.To enable them, you must include the appropriate dependency for your
platform. It's usually a good idea to have both to keep your application platform-agnostic. Netty is smart enough
to use the correct one, that includes none at all on unsupported platforms:
Vert.x is capable of using https://netty.io/wiki/native-transports.html[Netty's native transports], which offers performance improvements on specific platforms.
To enable them, you must include the appropriate dependency for your platform.
It's usually a good idea to have both to keep your application platform-agnostic.
Netty is smart enough to use the correct one, that includes none at all on unsupported platforms:

[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
.pom.xml
Expand Down Expand Up @@ -996,8 +992,7 @@ On macOS Sierra and above you can enable the following socket options:
quarkus.http.so-reuse-port=true
----


== Listening to a Unix Domain Socket
== Use a Unix Domain Socket

Listening on a Unix domain socket allows us to dispense with the overhead of TCP
if the connection to the quarkus service is established from the same host.
Expand Down Expand Up @@ -1030,7 +1025,101 @@ See <<native-transport>> for details.

IMPORTANT: Make sure your application has the right permissions to write to the socket.

== Read only deployment environments
[#use-io_uring]
== Use io_uring

IMPORTANT: `io_uring` is not supported in native executables.

NOTE: `io_uring` support is experimental

`io_uring` is a Linux kernel interface that allows you to send and receive data asynchronously.
It provides unified semantics for both file and network I/O.
It was originally designed to target block devices and files but has since gained the ability to work with things like network sockets.
It has the potential to provide modest performance benefits to network I/O on its own and greater benefits for mixed file and network I/O application workloads.

To learn more about `io_uring`, we recommend the following links:

* https://developers.redhat.com/articles/2023/04/12/why-you-should-use-iouring-network-io[Why you should use io_uring for network I/O]: The main benefit of io_uring for network I/O is a modern asynchronous API that is straightforward to use and provides unified semantics for file and network I/O.
A potential performance benefit of io_uring for network I/O is reducing the number of syscalls.
This could provide the biggest benefit for high volumes of small operations where the overhead of system calls can be significant.
* https://dzone.com/articles/the-backend-revolution-or-why-io-uring-is-so-impor[The Backend Revolution and Why io_uring Is So Important]: The io_uring API uses two ring buffers for communication between application and kernel (hence the API name) and designed in a way that enables natural batching of requests and responses.
Besides, it provides a way to submit multiple requests in one system call, which can reduce overhead.
* https://stackoverflow.com/questions/61767702/what-exactly-is-io-uring[What exactly is io_uring?]: io_uring is a Linux kernel interface to efficiently allow you to send and receive data asynchronously.
It was originally designed to target block devices and files but has since gained the ability to work with things like network sockets.


To use `io_uring`, you need to add two dependencies to your project and enable native transport.
First add the following dependencies to your project:

[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"]
.pom.xml
----
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-transport-native-io_uring</artifactId>
<version>0.0.21.Final</version> <!-- Update this version (https://github.com/netty/netty-incubator-transport-io_uring/tags) -->
<classifier>linux-x86_64</classifier>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-io_uring-incubator</artifactId>
</dependency>
----

[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]
.build.gradle
----
// Update the io_uring version by picking the latest from https://github.com/netty/netty-incubator-transport-io_uring/tags
implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final")
implementation("io.vertx:vertx-io_uring-incubator")
----

Then, in the `application.properties`, add:

[source, properties]
----
quarkus.vertx.prefer-native-transport=true
----

[NOTE]
.Can I use io_uring on my Linux machine?
====
To check if you can use `io_uring` on your Linux machine, execute the following command:
[source, shell]
----
> grep io_uring_setup /proc/kallsyms
0000000000000000 t __pfx_io_uring_setup
0000000000000000 t io_uring_setup
0000000000000000 T __pfx___x64_sys_io_uring_setup
0000000000000000 T __x64_sys_io_uring_setup
0000000000000000 T __pfx___ia32_sys_io_uring_setup
0000000000000000 T __ia32_sys_io_uring_setup
0000000000000000 d event_exit__io_uring_setup
0000000000000000 d event_enter__io_uring_setup
0000000000000000 d __syscall_meta__io_uring_setup
0000000000000000 d args__io_uring_setup
0000000000000000 d types__io_uring_setup
0000000000000000 d __event_exit__io_uring_setup
0000000000000000 d __event_enter__io_uring_setup
0000000000000000 d __p_syscall_meta__io_uring_setup
----
If it prints something like above, you can use `io_uring`.
====

[NOTE]
.Troubleshooting
====
`io_uring` support is still experimental.
Check the https://github.com/netty/netty-incubator-transport-io_uring#faq[Netty io_uring FAQ] if you see some odd behavior.
Also, the https://github.com/netty/netty-incubator-transport-io_uring/issues/152[netty io_uring was slower than epoll] issue describes a few configuration mistakes.
====

IMPORTANT: Domain sockets are not yet supported with io_uring.

IMPORTANT: The Vert.x asynchronous file system API does not use io_uring yet.


== Deploy on read-only environments

In environments with read only file systems you may receive errors of the form:

Expand All @@ -1041,13 +1130,14 @@ java.lang.IllegalStateException: Failed to create cache dir

Assuming `/tmp/` is writable this can be fixed by setting the `vertx.cacheDirBase` property to point to a directory in `/tmp/` for instance in OpenShift by creating an environment variable `JAVA_OPTS` with the value `-Dvertx.cacheDirBase=/tmp/vertx`.

== Customizing the Vert.x configuration
[#customizing-the-vert-x-configuration]
== Customize the Vert.x configuration

The configuration of the managed Vert.x instance can be provided using the `application.properties` file, but also using _special beans_.
CDI beans exposing the `io.quarkus.vertx.VertxOptionsCustomizer` interface can be used to customize the Vert.x configuration.
For example, the following customizer change the `tmp` base directory:

[source, java]
[source,java]
----
@ApplicationScoped
public class MyCustomizer implements VertxOptionsCustomizer {
Expand Down

0 comments on commit f8e326b

Please sign in to comment.