最近在写一个小项目,用redis过期来实现验证码的时间限制。因为SpringBoot默认采用
lettuce作为客户端,引入了 commons-pool2
依赖之后做了如下配置:
spring:
redis:
host: 192.168.56.1
lettuce:
pool:
min-idle: 2
max-active: 8 #默认
max-idle: 8 #默认
复制代码
本来以为这样做就行了,然后写了如下代码测了下
@Test
public void test() throws InterruptedException {
int i ;
CountDownLatch c = new CountDownLatch(5000);
for (i = 1; i <= 5000; i++) {
new Thread(() -> {
System.out.println(redisTemplate.execute(RedisConnection::ping));
c.countDown();
}).start();
}
c.await();
}
复制代码
测试期间,实际客户端最大接入:
127.0.0.1:6379> info clients # Clients connected_clients:2 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 复制代码
???,我设置的配置去哪里了??,于是开始了漫长的探索
首先看下默认下是怎样的。去除了pool的设置,再跑一下。
127.0.0.1:6379> info clients # Clients connected_clients:2 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 复制代码
很好,同样的结果。说明刚刚的配置根本没有效果。没准是lettuce的原因?于是我修改了pom,用jedis测试了一下。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.7.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>lettuce-core</artifactId>
<groupId>io.lettuce</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<!-- 注意版本和SpringData兼容 -->
<version>2.9.1</version>
</dependency>
复制代码
spring:
redis:
host: 192.168.56.1
jedis:
pool:
min-idle: 2
max-active: 8
max-idle: 8
复制代码
看下结果:
# Clients connected_clients:9 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 127.0.0.1:6379> info clients 复制代码
最大换成15再试试:
# Clients connected_clients:16 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 复制代码
很好,jedis没有问题,那说明是lettuce的配置上除了问题。
我们看下lettuce的 LettuceConnectionFactory
中的 getConnection
是怎样实现的。
public RedisConnection getConnection() {
if (this.isClusterAware()) {
return this.getClusterConnection();
} else {
LettuceConnection connection;
if (this.pool != null) {
connection = new LettuceConnection(this.getSharedConnection(), this.getTimeout(), (AbstractRedisClient)null, this.pool, this.getDatabase());
} else {
connection = new LettuceConnection(this.getSharedConnection(), this.connectionProvider, this.getTimeout(), this.getDatabase());
}
connection.setConvertPipelineAndTxResults(this.convertPipelineAndTxResults);
return connection;
}
}
复制代码
首先,是关于集群判断,因为我没设置任何集群相关,所以直接来到 else
。 LettuceConnection
的构造函数中的 this.getSharedConnection()
引起了我的注意,字面意思 获得共享连接
。好的,就决定是你了!
protected StatefulRedisConnection<byte[], byte[]> getSharedConnection() {
return this.shareNativeConnection ? (StatefulRedisConnection)this.getOrCreateSharedConnection().getConnection() : null;
}
复制代码
首先要判断这个 shareNativeConnection
默认值。从上面的属性能看到:
private boolean shareNativeConnection = true; 复制代码
OK,默认为 true
。先到这猜测一下,因为默认共享连接实例,所以此时使用的都为同一个实例,同时最多只有一个与redis连接。那我尝试认为改变一下设置:
@Configuration
public class Config {
@Autowired
public void setLettuceConnectionFactory(LettuceConnectionFactory lettuceConnectionFactory){
lettuceConnectionFactory.setShareNativeConnection(false);
}
}
复制代码
还是按下面的配置及测试:
spring:
redis:
host: 192.168.56.1
lettuce:
pool:
min-idle: 2
max-active: 8
max-idle: 8
复制代码
@Test
public void test() throws InterruptedException {
int i ;
CountDownLatch c = new CountDownLatch(5000);
for (i = 1; i <= 5000; i++) {
new Thread(() -> {
System.out.println(redisTemplate.execute(RedisConnection::ping));
c.countDown();
}).start();
}
c.await();
}
复制代码
之后结果:
127.0.0.1:6379> info clients # Clients connected_clients:9 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 复制代码
OK,验证成功,再改下10试试,结果也是相符。
127.0.0.1:6379> info clients # Clients connected_clients:11 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 127.0.0.1:6379> 复制代码
如果将刚才的 shareNativeConnection
的修改之后,而 application.yml
对 pool
的属性不进行设置的话,那结果相当可怕,我们看下测试结果:
127.0.0.1:6379> info clients # Clients connected_clients:573 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 127.0.0.1:6379> info clients # Clients connected_clients:683 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 127.0.0.1:6379> info clients # Clients connected_clients:890 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 127.0.0.1:6379> info clients # Clients connected_clients:1034 client_recent_max_input_buffer:4 client_recent_max_output_buffer:0 blocked_clients:0 复制代码
这连接数是直接放飞自我了。。。。。不过设置后则可得到限制。
通过探索,发现Lettuce的 pool
与 shareNativeConnection
息息相关,通过debug我发现了一些可能的原因不过看着太长了就懒得写了...如有不对的地方,望能指证出来。