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 PacketProcessor packetProcessor;
private static NettyServer nettyServer;
private static int nettyThreadCount = Runtime.getRuntime().availableProcessors();
private static boolean processNettyErrors = true;
// In-Game Manager
@ -626,6 +627,28 @@ public final class MinecraftServer {
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
*
@ -659,21 +682,27 @@ public final class MinecraftServer {
Check.stateCondition(!initialized, "#start can only be called after #init");
Check.stateCondition(started, "The server is already started");
MinecraftServer.started = true;
LOGGER.info("Starting Minestom server.");
MinecraftServer.responseDataConsumer = responseDataConsumer;
updateManager.start();
// Init & start the TCP server
nettyServer.init();
nettyServer.start(address, port);
long t1 = -System.nanoTime();
final long t1 = -System.nanoTime();
// Init extensions
// TODO: Extensions should handle depending on each other and have a load-order.
extensionManager.getExtensions().forEach(Extension::preInitialize);
extensionManager.getExtensions().forEach(Extension::initialize);
extensionManager.getExtensions().forEach(Extension::postInitialize);
MinecraftServer.started = true;
final double loadTime = MathUtils.round((t1 + System.nanoTime()) / 1_000_000D, 2);
LOGGER.info("Extensions loaded in " + loadTime + "ms");
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.netty.channel.ClientChannel;
import net.minestom.server.network.netty.codec.*;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
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 CLIENT_CHANNEL_NAME = "handler"; // Read
private final EventLoopGroup boss, worker;
private final ServerBootstrap bootstrap;
private boolean initialized = false;
private PacketProcessor packetProcessor;
private EventLoopGroup boss, worker;
private ServerBootstrap bootstrap;
private ServerSocketChannel serverChannel;
private String address;
private int port;
private final GlobalChannelTrafficShapingHandler globalTrafficHandler;
private GlobalChannelTrafficShapingHandler globalTrafficHandler;
/**
* Scheduler used by {@code globalTrafficHandler}.
@ -71,32 +76,48 @@ public final class NettyServer {
private final ScheduledExecutorService trafficScheduler = Executors.newScheduledThreadPool(1);
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;
final int workerThreadCount = MinecraftServer.getNettyThreadCount();
if (IOUring.isAvailable()) {
boss = new IOUringEventLoopGroup(2);
worker = new IOUringEventLoopGroup(); // thread count = core * 2
worker = new IOUringEventLoopGroup(workerThreadCount);
channel = IOUringServerSocketChannel.class;
LOGGER.info("Using io_uring");
} else if (Epoll.isAvailable()) {
boss = new EpollEventLoopGroup(2);
worker = new EpollEventLoopGroup(); // thread count = core * 2
worker = new EpollEventLoopGroup(workerThreadCount);
channel = EpollServerSocketChannel.class;
LOGGER.info("Using epoll");
} else if (KQueue.isAvailable()) {
boss = new KQueueEventLoopGroup(2);
worker = new KQueueEventLoopGroup(); // thread count = core * 2
worker = new KQueueEventLoopGroup(workerThreadCount);
channel = KQueueServerSocketChannel.class;
LOGGER.info("Using kqueue");
} else {
boss = new NioEventLoopGroup(2);
worker = new NioEventLoopGroup(); // thread count = core * 2
worker = new NioEventLoopGroup(workerThreadCount);
channel = NioServerSocketChannel.class;
@ -107,14 +128,6 @@ public final class NettyServer {
.group(boss, worker)
.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>() {
protected void initChannel(@NotNull SocketChannel ch) {