-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[improve][broker] Allow to use io_uring instead of epoll #18385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,43 +35,61 @@ | |
| import io.netty.channel.socket.nio.NioDatagramChannel; | ||
| import io.netty.channel.socket.nio.NioServerSocketChannel; | ||
| import io.netty.channel.socket.nio.NioSocketChannel; | ||
| import io.netty.incubator.channel.uring.IOUring; | ||
| import io.netty.incubator.channel.uring.IOUringDatagramChannel; | ||
| import io.netty.incubator.channel.uring.IOUringEventLoopGroup; | ||
| import io.netty.incubator.channel.uring.IOUringServerSocketChannel; | ||
| import io.netty.incubator.channel.uring.IOUringSocketChannel; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ThreadFactory; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.bookkeeper.common.util.affinity.CpuAffinity; | ||
| import org.apache.commons.lang3.StringUtils; | ||
|
|
||
| @SuppressWarnings("checkstyle:JavadocType") | ||
| @Slf4j | ||
| public class EventLoopUtil { | ||
|
|
||
| private static final String ENABLE_IO_URING = "enable.io_uring"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering whether we need a prefix here, or if it's the same as how netty does it. That said, if it's a Pulsar specific property, name it as: private static final String ENABLE_IO_URING_KEY = "pulsar.enableUring";can avoid accidental conflicts.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for missing this comment. This is a good idea, so like:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I learn more properties don't separate
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good suggestion, I will push a new PR to improve it. |
||
|
|
||
| /** | ||
| * @return an EventLoopGroup suitable for the current platform | ||
| */ | ||
| public static EventLoopGroup newEventLoopGroup(int nThreads, boolean enableBusyWait, ThreadFactory threadFactory) { | ||
| if (Epoll.isAvailable()) { | ||
| if (!enableBusyWait) { | ||
| // Regular Epoll based event loop | ||
| return new EpollEventLoopGroup(nThreads, threadFactory); | ||
| } | ||
| String enableIoUring = System.getProperty(ENABLE_IO_URING); | ||
|
|
||
| // With low latency setting, put the Netty event loop on busy-wait loop to reduce cost of | ||
| // context switches | ||
| EpollEventLoopGroup eventLoopGroup = new EpollEventLoopGroup(nThreads, threadFactory, | ||
| () -> (selectSupplier, hasTasks) -> SelectStrategy.BUSY_WAIT); | ||
| // By default, io_uring will not be enabled, even if available. The environment variable will be used: | ||
| // enable.io_uring=1 | ||
| if (StringUtils.equalsAnyIgnoreCase(enableIoUring, "1", "true")) { | ||
| // Throw exception if IOUring cannot be used | ||
| IOUring.ensureAvailability(); | ||
| return new IOUringEventLoopGroup(nThreads, threadFactory); | ||
| } else { | ||
| if (!enableBusyWait) { | ||
| // Regular Epoll based event loop | ||
| return new EpollEventLoopGroup(nThreads, threadFactory); | ||
| } | ||
|
|
||
| // Enable CPU affinity on IO threads | ||
| for (int i = 0; i < nThreads; i++) { | ||
| eventLoopGroup.next().submit(() -> { | ||
| try { | ||
| CpuAffinity.acquireCore(); | ||
| } catch (Throwable t) { | ||
| log.warn("Failed to acquire CPU core for thread {} {}", Thread.currentThread().getName(), | ||
| t.getMessage(), t); | ||
| } | ||
| }); | ||
| } | ||
| // With low latency setting, put the Netty event loop on busy-wait loop to reduce cost of | ||
| // context switches | ||
| EpollEventLoopGroup eventLoopGroup = new EpollEventLoopGroup(nThreads, threadFactory, | ||
| () -> (selectSupplier, hasTasks) -> SelectStrategy.BUSY_WAIT); | ||
|
|
||
| return eventLoopGroup; | ||
| // Enable CPU affinity on IO threads | ||
| for (int i = 0; i < nThreads; i++) { | ||
| eventLoopGroup.next().submit(() -> { | ||
| try { | ||
| CpuAffinity.acquireCore(); | ||
| } catch (Throwable t) { | ||
| log.warn("Failed to acquire CPU core for thread {} {}", Thread.currentThread().getName(), | ||
| t.getMessage(), t); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| return eventLoopGroup; | ||
| } | ||
| } else { | ||
| // Fallback to NIO | ||
| return new NioEventLoopGroup(nThreads, threadFactory); | ||
|
|
@@ -85,23 +103,29 @@ public static EventLoopGroup newEventLoopGroup(int nThreads, boolean enableBusyW | |
| * @return | ||
| */ | ||
| public static Class<? extends SocketChannel> getClientSocketChannelClass(EventLoopGroup eventLoopGroup) { | ||
| if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| if (eventLoopGroup instanceof IOUringEventLoopGroup) { | ||
| return IOUringSocketChannel.class; | ||
| } else if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| return EpollSocketChannel.class; | ||
| } else { | ||
| return NioSocketChannel.class; | ||
| } | ||
| } | ||
|
|
||
| public static Class<? extends ServerSocketChannel> getServerSocketChannelClass(EventLoopGroup eventLoopGroup) { | ||
| if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| if (eventLoopGroup instanceof IOUringEventLoopGroup) { | ||
| return IOUringServerSocketChannel.class; | ||
| } else if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| return EpollServerSocketChannel.class; | ||
| } else { | ||
| return NioServerSocketChannel.class; | ||
| } | ||
| } | ||
|
|
||
| public static Class<? extends DatagramChannel> getDatagramChannelClass(EventLoopGroup eventLoopGroup) { | ||
| if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| if (eventLoopGroup instanceof IOUringEventLoopGroup) { | ||
| return IOUringDatagramChannel.class; | ||
| } else if (eventLoopGroup instanceof EpollEventLoopGroup) { | ||
| return EpollDatagramChannel.class; | ||
| } else { | ||
| return NioDatagramChannel.class; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.