mirror of
https://github.com/SpigotMC/BungeeCord.git
synced 2024-11-24 03:05:49 +01:00
[Performance] Attempt to use Netty's Epoll implementation on Linux.
This will attempt to make use of Netty's EpollEventLoopGroup and Epoll(Server)SocketChannel when on Linux and the native libraries load correctly. It should bring a large increase in performance and hopefully reliability. Big thanks to the @netty team for implementing this and @normanmaurer for some tips on the support detection. Feedback is appreciated.
This commit is contained in:
parent
2b304ecebc
commit
500b0af782
2
pom.xml
2
pom.xml
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<build.number>unknown</build.number>
|
<build.number>unknown</build.number>
|
||||||
<netty.version>4.0.19.Final</netty.version>
|
<netty.version>4.0.20.Final</netty.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -29,6 +29,12 @@
|
|||||||
<version>${netty.version}</version>
|
<version>${netty.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-transport-native-epoll</artifactId>
|
||||||
|
<version>${netty.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jline</groupId>
|
<groupId>jline</groupId>
|
||||||
<artifactId>jline</artifactId>
|
<artifactId>jline</artifactId>
|
||||||
|
@ -21,9 +21,7 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelException;
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.MultithreadEventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
|
||||||
import io.netty.util.ResourceLeakDetector;
|
import io.netty.util.ResourceLeakDetector;
|
||||||
import net.md_5.bungee.conf.Configuration;
|
import net.md_5.bungee.conf.Configuration;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -33,7 +31,6 @@ import java.net.InetSocketAddress;
|
|||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -97,7 +94,7 @@ public class BungeeCord extends ProxyServer
|
|||||||
* Localization bundle.
|
* Localization bundle.
|
||||||
*/
|
*/
|
||||||
public ResourceBundle bundle;
|
public ResourceBundle bundle;
|
||||||
public MultithreadEventLoopGroup eventLoops;
|
public EventLoopGroup eventLoops;
|
||||||
/**
|
/**
|
||||||
* locations.yml save thread.
|
* locations.yml save thread.
|
||||||
*/
|
*/
|
||||||
@ -206,7 +203,7 @@ public class BungeeCord extends ProxyServer
|
|||||||
System.setProperty( "io.netty.selectorAutoRebuildThreshold", "0" ); // Seems to cause Bungee to stop accepting connections
|
System.setProperty( "io.netty.selectorAutoRebuildThreshold", "0" ); // Seems to cause Bungee to stop accepting connections
|
||||||
ResourceLeakDetector.setEnabled( false ); // Eats performance
|
ResourceLeakDetector.setEnabled( false ); // Eats performance
|
||||||
|
|
||||||
eventLoops = new NioEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
eventLoops = PipelineUtils.newEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
||||||
|
|
||||||
File moduleDirectory = new File( "modules" );
|
File moduleDirectory = new File( "modules" );
|
||||||
moduleManager.load( this, moduleDirectory );
|
moduleManager.load( this, moduleDirectory );
|
||||||
@ -259,7 +256,7 @@ public class BungeeCord extends ProxyServer
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
new ServerBootstrap()
|
new ServerBootstrap()
|
||||||
.channel( NioServerSocketChannel.class )
|
.channel( PipelineUtils.getServerChannel() )
|
||||||
.childAttr( PipelineUtils.LISTENER, info )
|
.childAttr( PipelineUtils.LISTENER, info )
|
||||||
.childHandler( PipelineUtils.SERVER_CHILD )
|
.childHandler( PipelineUtils.SERVER_CHILD )
|
||||||
.group( eventLoops )
|
.group( eventLoops )
|
||||||
|
@ -5,7 +5,6 @@ import io.netty.bootstrap.Bootstrap;
|
|||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -131,7 +130,7 @@ public class BungeeServerInfo implements ServerInfo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
new Bootstrap()
|
new Bootstrap()
|
||||||
.channel( NioSocketChannel.class )
|
.channel( PipelineUtils.getChannel() )
|
||||||
.group( BungeeCord.getInstance().eventLoops )
|
.group( BungeeCord.getInstance().eventLoops )
|
||||||
.handler( PipelineUtils.BASE )
|
.handler( PipelineUtils.BASE )
|
||||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||||
|
@ -7,7 +7,6 @@ import io.netty.channel.ChannelFuture;
|
|||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -261,7 +260,7 @@ public final class UserConnection implements ProxiedPlayer
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Bootstrap b = new Bootstrap()
|
Bootstrap b = new Bootstrap()
|
||||||
.channel( NioSocketChannel.class )
|
.channel( PipelineUtils.getChannel() )
|
||||||
.group( ch.getHandle().eventLoop() )
|
.group( ch.getHandle().eventLoop() )
|
||||||
.handler( initializer )
|
.handler( initializer )
|
||||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||||
|
@ -8,7 +8,6 @@ import io.netty.channel.ChannelFuture;
|
|||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
||||||
import io.netty.handler.codec.http.DefaultHttpRequest;
|
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||||
import io.netty.handler.codec.http.HttpHeaders;
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
@ -21,6 +20,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.api.Callback;
|
import net.md_5.bungee.api.Callback;
|
||||||
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
|
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class HttpClient
|
public class HttpClient
|
||||||
@ -90,7 +90,7 @@ public class HttpClient
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
new Bootstrap().channel( NioSocketChannel.class ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ).
|
new Bootstrap().channel( PipelineUtils.getChannel() ).group( eventLoop ).handler( new HttpInitializer( callback, ssl ) ).
|
||||||
option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( inetHost, port ).connect().addListener( future );
|
option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( inetHost, port ).connect().addListener( future );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,25 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelException;
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.ServerChannel;
|
||||||
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
|
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||||
|
import io.netty.channel.epoll.EpollSocketChannel;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
import net.md_5.bungee.BungeeCord;
|
import net.md_5.bungee.BungeeCord;
|
||||||
import net.md_5.bungee.BungeeServerInfo;
|
import net.md_5.bungee.BungeeServerInfo;
|
||||||
import net.md_5.bungee.UserConnection;
|
import net.md_5.bungee.UserConnection;
|
||||||
|
import net.md_5.bungee.Util;
|
||||||
import net.md_5.bungee.connection.InitialHandler;
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
@ -62,6 +74,47 @@ public class PipelineUtils
|
|||||||
public static String LEGACY_DECODER = "legacy-decoder";
|
public static String LEGACY_DECODER = "legacy-decoder";
|
||||||
public static String LEGACY_KICKER = "legacy-kick";
|
public static String LEGACY_KICKER = "legacy-kick";
|
||||||
|
|
||||||
|
private static boolean epoll;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
if ( !PlatformDependent.isWindows() )
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().getLogger().info( "Not on Windows, attempting to use enhanced EpollEventLoop" );
|
||||||
|
EpollEventLoopGroup testGroup = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
testGroup = new EpollEventLoopGroup( 1 );
|
||||||
|
epoll = true;
|
||||||
|
ProxyServer.getInstance().getLogger().info( "Epoll is working, utilising it!" );
|
||||||
|
} catch ( Throwable t )
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Event though Epoll should be supported, it is not working, falling back to NIO: {0}", Util.exception( t ) );
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
if ( testGroup != null )
|
||||||
|
{
|
||||||
|
testGroup.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventLoopGroup newEventLoopGroup(int threads, ThreadFactory factory)
|
||||||
|
{
|
||||||
|
return epoll ? new EpollEventLoopGroup( threads, factory ) : new NioEventLoopGroup( threads, factory );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends ServerChannel> getServerChannel()
|
||||||
|
{
|
||||||
|
return epoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends Channel> getChannel()
|
||||||
|
{
|
||||||
|
return epoll ? EpollSocketChannel.class : NioSocketChannel.class;
|
||||||
|
}
|
||||||
|
|
||||||
public final static class Base extends ChannelInitializer<Channel>
|
public final static class Base extends ChannelInitializer<Channel>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user