Allow custom Netty thread count

This commit is contained in:
Felix Cravic 2020-11-29 17:49:02 +01:00
parent cabdb60370
commit 415bcda6fd
2 changed files with 60 additions and 18 deletions

View File

@ -97,6 +97,7 @@ public final class MinecraftServer {
private static PacketListenerManager packetListenerManager; private static PacketListenerManager packetListenerManager;
private static PacketProcessor packetProcessor; private static PacketProcessor packetProcessor;
private static NettyServer nettyServer; private static NettyServer nettyServer;
private static int nettyThreadCount = Runtime.getRuntime().availableProcessors();
private static boolean processNettyErrors = true; private static boolean processNettyErrors = true;
// In-Game Manager // In-Game Manager
@ -626,6 +627,28 @@ public final class MinecraftServer {
return updateManager; return updateManager;
} }
/**
* Gets the number of threads used by Netty.
* <p>
* Is the number of vCPU by default.
*
* @return the number of netty threads
*/
public static int getNettyThreadCount() {
return nettyThreadCount;
}
/**
* Changes the number of threads used by Netty.
*
* @param nettyThreadCount the number of threads
* @throws IllegalStateException if the server is already started
*/
public static void setNettyThreadCount(int nettyThreadCount) {
Check.stateCondition(started, "Netty thread count can only be changed before the server starts!");
MinecraftServer.nettyThreadCount = nettyThreadCount;
}
/** /**
* Gets if the server should process netty errors and other unnecessary netty events * Gets if the server should process netty errors and other unnecessary netty events
* *
@ -659,21 +682,27 @@ public final class MinecraftServer {
Check.stateCondition(!initialized, "#start can only be called after #init"); Check.stateCondition(!initialized, "#start can only be called after #init");
Check.stateCondition(started, "The server is already started"); Check.stateCondition(started, "The server is already started");
MinecraftServer.started = true;
LOGGER.info("Starting Minestom server."); LOGGER.info("Starting Minestom server.");
MinecraftServer.responseDataConsumer = responseDataConsumer; MinecraftServer.responseDataConsumer = responseDataConsumer;
updateManager.start(); updateManager.start();
// Init & start the TCP server
nettyServer.init();
nettyServer.start(address, port); nettyServer.start(address, port);
long t1 = -System.nanoTime();
final long t1 = -System.nanoTime();
// Init extensions // Init extensions
// TODO: Extensions should handle depending on each other and have a load-order. // TODO: Extensions should handle depending on each other and have a load-order.
extensionManager.getExtensions().forEach(Extension::preInitialize); extensionManager.getExtensions().forEach(Extension::preInitialize);
extensionManager.getExtensions().forEach(Extension::initialize); extensionManager.getExtensions().forEach(Extension::initialize);
extensionManager.getExtensions().forEach(Extension::postInitialize); extensionManager.getExtensions().forEach(Extension::postInitialize);
MinecraftServer.started = true;
final double loadTime = MathUtils.round((t1 + System.nanoTime()) / 1_000_000D, 2); final double loadTime = MathUtils.round((t1 + System.nanoTime()) / 1_000_000D, 2);
LOGGER.info("Extensions loaded in " + loadTime + "ms"); LOGGER.info("Extensions loaded in " + loadTime + "ms");
LOGGER.info("Minestom server started successfully."); LOGGER.info("Minestom server started successfully.");
} }

View File

@ -22,6 +22,7 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.network.PacketProcessor; import net.minestom.server.network.PacketProcessor;
import net.minestom.server.network.netty.channel.ClientChannel; import net.minestom.server.network.netty.channel.ClientChannel;
import net.minestom.server.network.netty.codec.*; import net.minestom.server.network.netty.codec.*;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,15 +56,19 @@ public final class NettyServer {
public static final String ENCODER_HANDLER_NAME = "encoder"; // Write public static final String ENCODER_HANDLER_NAME = "encoder"; // Write
public static final String CLIENT_CHANNEL_NAME = "handler"; // Read public static final String CLIENT_CHANNEL_NAME = "handler"; // Read
private final EventLoopGroup boss, worker; private boolean initialized = false;
private final ServerBootstrap bootstrap;
private PacketProcessor packetProcessor;
private EventLoopGroup boss, worker;
private ServerBootstrap bootstrap;
private ServerSocketChannel serverChannel; private ServerSocketChannel serverChannel;
private String address; private String address;
private int port; private int port;
private final GlobalChannelTrafficShapingHandler globalTrafficHandler; private GlobalChannelTrafficShapingHandler globalTrafficHandler;
/** /**
* Scheduler used by {@code globalTrafficHandler}. * Scheduler used by {@code globalTrafficHandler}.
@ -71,32 +76,48 @@ public final class NettyServer {
private final ScheduledExecutorService trafficScheduler = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService trafficScheduler = Executors.newScheduledThreadPool(1);
public NettyServer(@NotNull PacketProcessor packetProcessor) { public NettyServer(@NotNull PacketProcessor packetProcessor) {
this.packetProcessor = packetProcessor;
this.globalTrafficHandler = new GlobalChannelTrafficShapingHandler(trafficScheduler, 200) {
@Override
protected void doAccounting(TrafficCounter counter) {
// TODO proper monitoring API
//System.out.println("data " + counter.lastWriteThroughput() / 1000 + " " + counter.lastReadThroughput() / 1000);
}
};
}
public void init() {
Check.stateCondition(initialized, "Netty server has already been initialized!");
initialized = true;
Class<? extends ServerChannel> channel; Class<? extends ServerChannel> channel;
final int workerThreadCount = MinecraftServer.getNettyThreadCount();
if (IOUring.isAvailable()) { if (IOUring.isAvailable()) {
boss = new IOUringEventLoopGroup(2); boss = new IOUringEventLoopGroup(2);
worker = new IOUringEventLoopGroup(); // thread count = core * 2 worker = new IOUringEventLoopGroup(workerThreadCount);
channel = IOUringServerSocketChannel.class; channel = IOUringServerSocketChannel.class;
LOGGER.info("Using io_uring"); LOGGER.info("Using io_uring");
} else if (Epoll.isAvailable()) { } else if (Epoll.isAvailable()) {
boss = new EpollEventLoopGroup(2); boss = new EpollEventLoopGroup(2);
worker = new EpollEventLoopGroup(); // thread count = core * 2 worker = new EpollEventLoopGroup(workerThreadCount);
channel = EpollServerSocketChannel.class; channel = EpollServerSocketChannel.class;
LOGGER.info("Using epoll"); LOGGER.info("Using epoll");
} else if (KQueue.isAvailable()) { } else if (KQueue.isAvailable()) {
boss = new KQueueEventLoopGroup(2); boss = new KQueueEventLoopGroup(2);
worker = new KQueueEventLoopGroup(); // thread count = core * 2 worker = new KQueueEventLoopGroup(workerThreadCount);
channel = KQueueServerSocketChannel.class; channel = KQueueServerSocketChannel.class;
LOGGER.info("Using kqueue"); LOGGER.info("Using kqueue");
} else { } else {
boss = new NioEventLoopGroup(2); boss = new NioEventLoopGroup(2);
worker = new NioEventLoopGroup(); // thread count = core * 2 worker = new NioEventLoopGroup(workerThreadCount);
channel = NioServerSocketChannel.class; channel = NioServerSocketChannel.class;
@ -107,14 +128,6 @@ public final class NettyServer {
.group(boss, worker) .group(boss, worker)
.channel(channel); .channel(channel);
this.globalTrafficHandler = new GlobalChannelTrafficShapingHandler(trafficScheduler, 200) {
@Override
protected void doAccounting(TrafficCounter counter) {
// TODO proper monitoring API
//System.out.println("data " + counter.lastWriteThroughput() / 1000 + " " + counter.lastReadThroughput() / 1000);
}
};
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(@NotNull SocketChannel ch) { protected void initChannel(@NotNull SocketChannel ch) {