redis 获取连接池连接不上问题

问题详情:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool>
2017-12-21 13:50:58,192 WARN [com.inspeeding.StoreUploadFileToInThread] Thread-8 - <start again.....>
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
        at redis.clients.util.Pool.getResource(Pool.java:50)
        at redis.clients.jedis.JedisSentinelPool.getResource(JedisSentinelPool.java:181)
        at com.inspeeding.util.IntranetRedisUtil2.rpop(IntranetRedisUtil2.java:262)
        at com.inspeeding.StoreUploadFileToInThread.server(StoreUploadFileToInThread.java:83)
        at com.inspeeding.StoreUploadFileToInThread.run(StoreUploadFileToInThread.java:67)
Caused by: java.util.NoSuchElementException: Unable to validate object
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:502)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
        at redis.clients.util.Pool.getResource(Pool.java:48)
        ... 4 more

问题原因分析:

redis是我们数据的保管者,我们可以随时存随时取,大的小的,重要的不重要的,它都毫无怨言的帮我们保存着,甚至有些时候,我们变得很懒,存东西进去的时候顺便还贴张纸:“过了一个星期就帮我扔了吧”,对于这些,Redis也都默默的接受了(谁叫Antirez把redis设计的这么好呢)。

这次要写的就是关于这张留言纸的事。

Redis提供了一套“美好”的过期数据清理机制:
主动过期: Redis对数据是惰性过期,当一个key到了过期时间,Redis也不会马上清理,但如果这个key过期后被再次访问,Redis就会主动将它清理掉。
被动过期: 如果过期的Key一直没被访问,Redis也不会一直把它放那不管,它会每秒10次的执行以下的清理工作:
        随机从所有带有过期时间的Key里取出20个
        如果发现有过期的,就清理
        如果这里有25%的Key都是过期的,就继续回到第一步再来一次

这套过期机制设计的很赞,可以这样理解:如果当前有超过1/4的Key是过期的话,就不停地清理,直到只剩下1/4不到的Key是要过期的为止,然后就慢慢地随机抽查着清理。



这个错误是因为JedisPool拿到一个连接后,调用 jedis.ping() 方法没有得到正确的返回”pong”消息,而出现这个问题时,并不是traffic的高峰期,redis的cpu不高,于是程序员很快就怀疑到网络上,难道有”丢包”?

但跑了几天,发现出错的时间固定在某几个时间点(如晚上9点~10点),莫非是扫地阿姨每天定时在机房打扫卫生,碰着网线了?(有时候不得不佩服程序员的想象力)

然而在一个夜黑风高的晚上,程序员的脑子在这个时候一般是最清醒的,这时告警短信又来了,打开redis监控,像在唯品会上逛街一样,对着redis的各项监控数据逛啊逛,突然,看到有几条Expires的数据,当时的表情只能用看到关注了几天的商品上标了大大”0.1折”时的表情来形容。

接下来的事情,想必大家也都猜到个七七八八了,当然是下单抢购支付了,
脑子里一系列的运算,掐指一算: “这个时间点正好有一大批key过期”,而且都是大的Set集合,每个都有几十万的数据,再一算: “Redis里的大部分需要过期的key就是这些key”。

于是,答案有了,Redis进行被动过期清理时,发现怎么随机,都有超过1/4的Key都是过期的,就忙着不停的删啊删,再加上又都是大集合的删除,O(N)的操作复杂度,无奈,
等redis删完时,客户端那边的命令都等超时了。

原因找到了,如何解决?看业务场景吧,对于我们的场景,
做法是将过期时间设长一点,然后把这些可以删掉的Key标记一下,丢到一个后台线程那里分页删Set里的数据,这样就算redis再做过期操作,也不会用太多的时间来删除。

最后,稍稍总结下,对于大个的集合对象,放redis的时候需要额外注意,如果想依赖redis的过期,可能会造成过期时短暂的redis block。

所以,要善待redis数据,比如不用了就自己清理掉,不要等着redis来帮你

 

 

 

 

解决办法:

解决办法:
1:  
登录redis :
redis-cli
127.0.0.1:6379>config set stop-writes-on-bgsave-error no

2:使用redis-cli修改rdb目录
CONFIG SET dir /tmp/redis_data
CONFIG SET dbfilename temp.rdb
重启redis-server,问题解决!但是需要每次启动server都要修改rdb的路径。

3:直接修改redis.conf文件

dir /tmp/redis_data    #./ -->  /tmp/redis_data
dbfilename temp.rdb   #

启动redis服务

 

posted @ 2017-12-21 14:41 磕磕碰碰后才知道如何改变 阅读(...) 评论(...) 编辑 收藏