【思考点滴】
作者 : 杨考 微信号 : devin_cn_hd_09_16
一、背景
不做详细说明,有朋友自己设计了一个redis锁,使用 setnx 之后,通过 expire(1)设置的超时。发现会有偶发的 expire 失败,以及redis锁节点一致无法删除。
二、问题分析
1、首先在生产环境中,不建议使用 setnx + expire的方式来实现锁,毕竟两步操作中间发生异常,则锁一直无法释放。可以使用 setnx(key, timeout)来做更合理
2、expire可以设置超时时间,但是不建议1秒,毕竟来讲在调用expire到expire执行完毕,有可能会跨越一个秒级的时间戳,即1534304914秒执行,执行完毕已经是1534304915秒了,此时1534304915是实际的设置的超时时间,即在设置之后已经过期了。至于设置一个已过期的时间,是否会导致 expire失败?还是redis节点删除? 还是 ttl为其它值,这里不做过多介绍,毕竟expire不能设置负数值。
3、通过expireat 来设置一个已经过期的时间,做一个简单的测试,验证一下expire(负数)的效果。
expireat操作成功,但是TTL为-1,即redis节点一直存在。其实已经验证了redis节点无法删除的问题了。
三、总结:
使用任何API的时候,要多想一下,为什么要使用1秒,1秒有什么好处,有什么坏处
1. 不能触发系统缺陷
2.满足业务需求,且不能提前删除,否则redis锁就是去意义了
3. 至于设置为多少合适,看业务处理的耗时,建议设置为<2*业务的耗时>
毕竟来讲,设置超时时间之后,在操作完成的时候,会主动删除redis锁,因此redis锁超时设置为1秒和100秒是没有差别的,都是在操作执行完之后,就将redis锁删除了。而1秒恰恰还有设计缺陷的弊端,自己统计一下,业务执行时间,然后根据2倍执行时间作为超时时间,这个就是比较好的。