最近在写一个小项目,用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我发现了一些可能的原因不过看着太长了就懒得写了...如有不对的地方,望能指证出来。