Redis主从模式下从库过期的key仍然能够被读到的解决方案

Redis主从模式下,当对一个key设定过期时间,到期之后从库依然能够读取到数据。这个问题困扰了我很久,相信很多人都遇到过这种问题了。(前提是你不去读主库,并且redis版本在3.2以下)。

经过一番搜寻,发现很多人遇到的问题和我一样。

主Redis

setex test 20 1
+OK
get test
$1
1
ttl test
:18

从Redis

get test
$1
1
ttl test
:7

以上都没问题,然而过几秒再看从Redis

ttl test
:-1
get test
$1
1

test这个key已经过期了,然而还是可以获取到test的值。

在使用Redis做锁的时候,如果直接取读从库的值,这就有大问题了。

为什么从库不删除数据?

redis删除过期数据有以下几个策略:

1.惰性删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key,很明显,这是被动的!

2.定期删除:由于惰性删除策略无法保证冷数据被及时删掉,所以 redis 会定期主动淘汰一批已过期的key。(在第二节中会具体说明)

3.主动删除:当前已用内存超过maxMemory限定时,触发主动清理策略。主动设置的前提是设置了maxMemory的值

int expireIfNeeded(redisDb *db, robj *key) { 
 time_t when = getExpire(db,key); 
 
 if (when < 0) return 0; /* No expire for this key */ 
 
 /* Don't expire anything while loading. It will be done later. */ 
 if (server.loading) return 0; 
 
 /* If we are running in the context of a slave, return ASAP: 
 * the slave key expiration is controlled by the master that will 
 * send us synthesized DEL operations for expired keys. 
 * 
 * Still we try to return the right information to the caller, 
 * that is, 0 if we think the key should be still valid, 1 if 
 * we think the key is expired at this time. */ 
 if (server.masterhost != NULL) { 
 return time(NULL) > when; 
 } 
 
 /* Return when this key has not expired */ 
 if (time(NULL) <= when) return 0; 
 
 /* Delete the key */ 
 server.stat_expiredkeys++; 
 propagateExpire(db,key); 
 return dbDelete(db,key); 
}
通过以上源码发现,4行:没有设置超时时间,则不删;7行:在”loading”时不删;16行:非主库不删;21行未到期不删。25行同步从库和文件。
所以说,在从库执行主动删除操作,或者通过惰性删除的方式触发删除key的操作,最终都不会执行成功。原因就在上面的第16行代码。
如何解决这种问题
1.升级到redis 3.2
2.通过ttl判断
生产环境升级有风险,运维可能不相干,那么就通过ttl来进行判断是否过期吧。
参考网页
[1] http://www.cnblogs.com/bridger/archive/2012/11/07/2758734.html
[2] http://www.tuicool.com/articles/INRZFr
赞赏

微信赞赏支付宝赞赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注