Feature - tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, tcpUserTimeout settings added. #5374

pull/5399/head
Nikita Koksharov 1 year ago
parent 70e18aaaab
commit e72194649e

@ -322,7 +322,6 @@
<configuration>
<source>${source.version}</source>
<target>${source.version}</target>
<release>${release.version}</release>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>

@ -432,6 +432,12 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>9.0.82</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

@ -17,13 +17,20 @@ package org.redisson.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.kqueue.KQueueDatagramChannel;
import io.netty.channel.kqueue.KQueueSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.incubator.channel.uring.IOUringChannelOption;
import io.netty.incubator.channel.uring.IOUringSocketChannel;
import io.netty.resolver.AddressResolver;
import io.netty.resolver.dns.DnsAddressResolverGroup;
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
@ -32,6 +39,7 @@ import io.netty.util.NetUtil;
import io.netty.util.Timer;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import jdk.net.ExtendedSocketOptions;
import org.redisson.api.RFuture;
import org.redisson.client.handler.RedisChannelInitializer;
import org.redisson.client.handler.RedisChannelInitializer.Type;
@ -40,6 +48,7 @@ import org.redisson.misc.RedisURI;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketOption;
import java.net.UnknownHostException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
@ -97,6 +106,8 @@ public final class RedisClient {
if (copy.getResolverGroup() == null) {
if (config.getSocketChannelClass() == EpollSocketChannel.class) {
copy.setResolverGroup(new DnsAddressResolverGroup(EpollDatagramChannel.class, DnsServerAddressStreamProviders.platformDefault()));
} else if (config.getSocketChannelClass() == KQueueSocketChannel.class) {
copy.setResolverGroup(new DnsAddressResolverGroup(KQueueDatagramChannel.class, DnsServerAddressStreamProviders.platformDefault()));
} else {
copy.setResolverGroup(new DnsAddressResolverGroup(NioDatagramChannel.class, DnsServerAddressStreamProviders.platformDefault()));
}
@ -131,10 +142,64 @@ public final class RedisClient {
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectTimeout());
bootstrap.option(ChannelOption.SO_KEEPALIVE, config.isKeepAlive());
bootstrap.option(ChannelOption.TCP_NODELAY, config.isTcpNoDelay());
applyChannelOptions(config, bootstrap);
config.getNettyHook().afterBoostrapInitialization(bootstrap);
return bootstrap;
}
private void applyChannelOptions(RedisClientConfig config, Bootstrap bootstrap) {
if (config.getSocketChannelClass() == EpollSocketChannel.class) {
if (config.getTcpKeepAliveCount() > 0) {
bootstrap.option(EpollChannelOption.TCP_KEEPCNT, config.getTcpKeepAliveCount());
}
if (config.getTcpKeepAliveIdle() > 0) {
bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, config.getTcpKeepAliveIdle());
}
if (config.getTcpKeepAliveInterval() > 0) {
bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, config.getTcpKeepAliveInterval());
}
if (config.getTcpUserTimeout() > 0) {
bootstrap.option(EpollChannelOption.TCP_USER_TIMEOUT, config.getTcpUserTimeout());
}
} else if (config.getSocketChannelClass() == IOUringSocketChannel.class) {
if (config.getTcpKeepAliveCount() > 0) {
bootstrap.option(IOUringChannelOption.TCP_KEEPCNT, config.getTcpKeepAliveCount());
}
if (config.getTcpKeepAliveIdle() > 0) {
bootstrap.option(IOUringChannelOption.TCP_KEEPIDLE, config.getTcpKeepAliveIdle());
}
if (config.getTcpKeepAliveInterval() > 0) {
bootstrap.option(IOUringChannelOption.TCP_KEEPINTVL, config.getTcpKeepAliveInterval());
}
if (config.getTcpUserTimeout() > 0) {
bootstrap.option(IOUringChannelOption.TCP_USER_TIMEOUT, config.getTcpUserTimeout());
}
} else if (config.getSocketChannelClass() == NioSocketChannel.class) {
SocketOption<Integer> countOption = null;
SocketOption<Integer> idleOption = null;
SocketOption<Integer> intervalOption = null;
try {
countOption = (SocketOption<Integer>) ExtendedSocketOptions.class.getDeclaredField("TCP_KEEPCOUNT").get(null);
idleOption = (SocketOption<Integer>) ExtendedSocketOptions.class.getDeclaredField("TCP_KEEPIDLE").get(null);
intervalOption = (SocketOption<Integer>) ExtendedSocketOptions.class.getDeclaredField("TCP_KEEPINTERVAL").get(null);
} catch (ReflectiveOperationException e) {
// skip
}
if (config.getTcpKeepAliveCount() > 0 && countOption != null) {
bootstrap.option(NioChannelOption.of(countOption), config.getTcpKeepAliveCount());
}
if (config.getTcpKeepAliveIdle() > 0 && idleOption != null) {
bootstrap.option(NioChannelOption.of(idleOption), config.getTcpKeepAliveIdle());
}
if (config.getTcpKeepAliveInterval() > 0 && intervalOption != null) {
bootstrap.option(NioChannelOption.of(intervalOption), config.getTcpKeepAliveInterval());
}
}
}
public InetSocketAddress getAddr() {
return resolvedAddr;
}

@ -59,6 +59,10 @@ public class RedisClientConfig {
private boolean keepPubSubOrder = true;
private int pingConnectionInterval;
private boolean keepAlive;
private int tcpKeepAliveCount;
private int tcpKeepAliveIdle;
private int tcpKeepAliveInterval;
private int tcpUserTimeout;
private boolean tcpNoDelay;
private String sslHostname;
@ -121,6 +125,10 @@ public class RedisClientConfig {
this.sslTrustManagerFactory = config.sslTrustManagerFactory;
this.commandMapper = config.commandMapper;
this.failedNodeDetector = config.failedNodeDetector;
this.tcpKeepAliveCount = config.tcpKeepAliveCount;
this.tcpKeepAliveIdle = config.tcpKeepAliveIdle;
this.tcpKeepAliveInterval = config.tcpKeepAliveInterval;
this.tcpUserTimeout = config.tcpUserTimeout;
}
public NettyHook getNettyHook() {
@ -315,6 +323,39 @@ public class RedisClientConfig {
return this;
}
public int getTcpKeepAliveCount() {
return tcpKeepAliveCount;
}
public RedisClientConfig setTcpKeepAliveCount(int tcpKeepAliveCount) {
this.tcpKeepAliveCount = tcpKeepAliveCount;
return this;
}
public int getTcpKeepAliveIdle() {
return tcpKeepAliveIdle;
}
public RedisClientConfig setTcpKeepAliveIdle(int tcpKeepAliveIdle) {
this.tcpKeepAliveIdle = tcpKeepAliveIdle;
return this;
}
public int getTcpKeepAliveInterval() {
return tcpKeepAliveInterval;
}
public RedisClientConfig setTcpKeepAliveInterval(int tcpKeepAliveInterval) {
this.tcpKeepAliveInterval = tcpKeepAliveInterval;
return this;
}
public int getTcpUserTimeout() {
return tcpUserTimeout;
}
public RedisClientConfig setTcpUserTimeout(int tcpUserTimeout) {
this.tcpUserTimeout = tcpUserTimeout;
return this;
}
public boolean isTcpNoDelay() {
return tcpNoDelay;
}

@ -103,7 +103,15 @@ public class BaseConfig<T extends BaseConfig<T>> {
private int pingConnectionInterval = 30000;
private boolean keepAlive;
private int tcpKeepAliveCount;
private int tcpKeepAliveIdle;
private int tcpKeepAliveInterval;
private int tcpUserTimeout;
private boolean tcpNoDelay = true;
private NameMapper nameMapper = NameMapper.direct();
@ -135,6 +143,10 @@ public class BaseConfig<T extends BaseConfig<T>> {
setSslTrustManagerFactory(config.getSslTrustManagerFactory());
setPingConnectionInterval(config.getPingConnectionInterval());
setKeepAlive(config.isKeepAlive());
setTcpKeepAliveCount(config.getTcpKeepAliveCount());
setTcpKeepAliveIdle(config.getTcpKeepAliveIdle());
setTcpKeepAliveInterval(config.getTcpKeepAliveInterval());
setTcpUserTimeout(config.getTcpUserTimeout());
setTcpNoDelay(config.isTcpNoDelay());
setNameMapper(config.getNameMapper());
setCredentialsResolver(config.getCredentialsResolver());
@ -459,6 +471,70 @@ public class BaseConfig<T extends BaseConfig<T>> {
return (T) this;
}
public int getTcpKeepAliveCount() {
return tcpKeepAliveCount;
}
/**
* Defines the maximum number of keepalive probes
* TCP should send before dropping the connection.
*
* @param tcpKeepAliveCount maximum number of keepalive probes
* @return config
*/
public T setTcpKeepAliveCount(int tcpKeepAliveCount) {
this.tcpKeepAliveCount = tcpKeepAliveCount;
return (T) this;
}
public int getTcpKeepAliveIdle() {
return tcpKeepAliveIdle;
}
/**
* Defines the time in seconds the connection needs to remain idle
* before TCP starts sending keepalive probes,
*
* @param tcpKeepAliveIdle time in seconds
* @return config
*/
public T setTcpKeepAliveIdle(int tcpKeepAliveIdle) {
this.tcpKeepAliveIdle = tcpKeepAliveIdle;
return (T) this;
}
public int getTcpKeepAliveInterval() {
return tcpKeepAliveInterval;
}
/**
* Defines the time in seconds between individual keepalive probes.
*
* @param tcpKeepAliveInterval time in seconds
* @return config
*/
public T setTcpKeepAliveInterval(int tcpKeepAliveInterval) {
this.tcpKeepAliveInterval = tcpKeepAliveInterval;
return (T) this;
}
public int getTcpUserTimeout() {
return tcpUserTimeout;
}
/**
* Defines the maximum amount of time in milliseconds that transmitted data may
* remain unacknowledged, or buffered data may remain untransmitted
* (due to zero window size) before TCP will forcibly close the connection.
*
* @param tcpUserTimeout time in milliseconds
* @return config
*/
public T setTcpUserTimeout(int tcpUserTimeout) {
this.tcpUserTimeout = tcpUserTimeout;
return (T) this;
}
public boolean isTcpNoDelay() {
return tcpNoDelay;
}

@ -291,6 +291,10 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
c.setSubscriptionMode(cfg.getSubscriptionMode());
c.setDnsMonitoringInterval(cfg.getDnsMonitoringInterval());
c.setKeepAlive(cfg.isKeepAlive());
c.setTcpKeepAliveCount(cfg.getTcpKeepAliveCount());
c.setTcpKeepAliveIdle(cfg.getTcpKeepAliveIdle());
c.setTcpKeepAliveInterval(cfg.getTcpKeepAliveInterval());
c.setTcpUserTimeout(cfg.getTcpUserTimeout());
c.setTcpNoDelay(cfg.isTcpNoDelay());
c.setNameMapper(cfg.getNameMapper());
c.setCredentialsResolver(cfg.getCredentialsResolver());
@ -347,6 +351,10 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
.setKeepPubSubOrder(serviceManager.getCfg().isKeepPubSubOrder())
.setPingConnectionInterval(config.getPingConnectionInterval())
.setKeepAlive(config.isKeepAlive())
.setTcpKeepAliveCount(config.getTcpKeepAliveCount())
.setTcpKeepAliveIdle(config.getTcpKeepAliveIdle())
.setTcpKeepAliveInterval(config.getTcpKeepAliveInterval())
.setTcpUserTimeout(config.getTcpUserTimeout())
.setTcpNoDelay(config.isTcpNoDelay())
.setUsername(config.getUsername())
.setPassword(config.getPassword())

@ -66,6 +66,10 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager {
newconfig.setReadMode(ReadMode.MASTER);
newconfig.setSubscriptionMode(SubscriptionMode.MASTER);
newconfig.setKeepAlive(cfg.isKeepAlive());
newconfig.setTcpKeepAliveCount(cfg.getTcpKeepAliveCount());
newconfig.setTcpKeepAliveIdle(cfg.getTcpKeepAliveIdle());
newconfig.setTcpKeepAliveInterval(cfg.getTcpKeepAliveInterval());
newconfig.setTcpUserTimeout(cfg.getTcpUserTimeout());
newconfig.setTcpNoDelay(cfg.isTcpNoDelay());
newconfig.setNameMapper(cfg.getNameMapper());
newconfig.setCredentialsResolver(cfg.getCredentialsResolver());

Loading…
Cancel
Save