连接池中的maxidle和maxactive

目前项目中使用了redis连接池。最近的一次压测中发现如下问题:

org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
    ......
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:502)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
	at java.lang.Thread.run(Thread.java:748)
Caused by: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
	at redis.clients.util.Pool.getResource(Pool.java:51)
	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:210)
	at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:17)
	at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:271)
	... 86 common frames omitted
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:432)
	at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:346)
	at redis.clients.util.Pool.getResource(Pool.java:49)
	... 89 common frames omitted

压测的参数如下:
连接池中的maxidle和maxactive_第1张图片
2000并发,循环10次,启动50个服务。
Timeout waiting for idle object,由这个初次判断是等待空闲连接超时。于是第一个念头是连接数是不是太小了?于是查看连接池配置:

spring.redis.jedis.pool.max-idle=30
spring.redis.jedis.pool.min-idle=20
spring.redis.jeids.pool.max-active=50
spring.redis.jedis.pool.max-wait=3000

最大连接数(max-active)是50,对于并发那么高感觉是有点小了。于是把max-active改成了500,这下可够了吧?!
但实际压测结果来看,情况只比之前好一点点,原来的错误还是存在的。按照这个最大连接数500,部署了50个服务,也就是最大能承受25000个连接,但目前并发才2000个!检查了一下代码,连接每次执行完任务之后都会释放,那这哪里出了问题呢?
思考了很久,注意到了max-idle参数,突然想到一个问题,如果这个值设太小(30个),但是最大连接数max-active设得太高(500个),那么每次单服务连接数到达30之后,后面的连接执行完任务之后都会被销毁,然后再重新建立连接,重复的太多的销毁和新建连接,瓶颈就在这里!
为了证明猜想,把max-idle设置为300,max-active还是保留500。按照之前的压测配置进行压测了几次,果然不出问题了,再尝试着把并发量调高点,也不会出错了!
问题到此解决!
由此,得出了一个结论,maxactive和maxidle这两个值最好设置得比较接近一些,不然maxidle设置得太小,单方面把maxactive调得很高,这样会导致频繁的连接销毁和新建,这跟连接池的理念就相悖了。为了提高性能,把maxactive调高,maxidle也相应调到一个接近的数字,池中空闲的连接就会维持一个适当的数量,才达到较理想的性能调优。除了redis连接池,其他连接池比如数据库连接池也同理可得。

你可能感兴趣的:(缓存,redis)