磁盘满时,redis客户端频抛出ConnectionException异常
1. 原因
当磁盘满时,程序在调用Pool.getResource(),从jedis实例池pool里借用实例时,出现连接异常,没有可用的jedis实例,异常log如下:
2013-11-17 21:59:37,155 ERROR [TransportFrameEncoderService:97] main - <redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool Caused by: java.util.NoSuchElementException: Timeout waiting for idle object |
至于为啥磁盘满时,会抛ConnectionException异常,推测redis-server在同步数据到磁盘时出现异常,导致文件句柄连接的异常,同时也会拒绝了网络客户端的连接,如下:
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error; nested exception is redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
2. 修改
2.1 客户端优化修改
a、增加参数testOnReturn和testOnBorrow 为true,表示每次借用和归还jedis实例时,强行判断当前jedis实例是否可用
b、增加config.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW),表示每次pool中没有可用的实例时,建新的jedis实例
c、修改逻辑:每次用完redis实例归还时,如果当前redis坏掉就不用归还,保证pool里面的实例都是可用的,代码摘要如下:
if (redis != null) {
pool.returnResource(redis);
}
2.2 服务端优化修改
由于redis中的热点数据仅有临时性的作用,所以在服务redis.conf配置文件中,禁用redis持久化功能,修改片段如下:
#save 900 1 #save 300 10 #save 60 10000 |
redisPool参数说明
maxActive:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态就成exhausted了,在JedisPoolConfig maxIdle:控制一个pool最多有多少个状态为idle的jedis实例; whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种WHEN_EXHAUSTED_FAIL(表示无jedis实例时,直接抛出NoSuchElementException)、WHEN_EXHAUSTED_BLOCK(则表示阻塞住,或者达到maxWait时抛出JedisConnectionException)、WHEN_EXHAUSTED_GROW(则表示新建一个jedis实例,也就说设置的maxActive无用); maxWait:表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException; testOnBorrow:在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的; testOnReturn:在return给pool时,是否提前进行validate操作; testWhileIdle:如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义; timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数; numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数; minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义; softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义; lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列; |
参考
http://blog.csdn.net/freebird_lb/article/details/7460328
https://github.com/xetorthio/jedis/issues/206
http://www.cnblogs.com/linjiqin/archive/2013/06/14/3135248.html