异常场景
最近一段时间时不时就有开发人员向我反应:redis的key有点问题,帮我删个key值、怎么key没有过期,我明明设了过期时间的。一开始没有放心上,以为只是程序逻辑处理不当或者redis偶尔抽风,不用在意。可是渐渐反应的人多了,觉得可能不是这么简单了,于是就和相关的开发人员讨论了下,发现会出现异常的基本是以下两种场景:
- 使用redis 的 incrBy 命令来防止重复提交,大致的redis交互如下:
incrBy key 1 # 返回 1 表示正常 返回 > 1 表示重复提交 直接 return expire key 5 # 5秒后过期 del key # 正常业务逻辑走完后 显示删除key
- 使用 redis (set setnx setex ) + expire 组合命令:
set |setnx | setex key expire key seconds # 设置失败
由于系统中大量使用了第一种方式来防止重复提交,所以这个问题对业务影响还是很大的,redis具体现象为:
- 设置incrby 第一次应该返回 1
- 实际上却返回了 2 ,导致业务流程无法走完,并且key没有删除也没有设置过期时间
查找问题
编写测试程序
为了排查问题写了一个简单的小程序:
@Testpublic void test() throws InterruptedException { final List list = Lists.newArrayListWithCapacity(5000000); Long first_id = 500000000000000001L; for (int i = 0; i < 5000000; i++) { list.add(first_id++); } final CountDownLatch allDone = new CountDownLatch(2); // incrby new Thread( new Runnable() { public void run() { try { testIncrby(list); } catch (InterruptedException e) { } allDone.countDown(); } } ).start(); new Thread( new Runnable() { public void run() { try { testIncrByAndDel(list); } catch (InterruptedException e) { } allDone.countDown(); } } ).start(); allDone.await(); log.info("finish method test");}public void testDelAndTTL() throws InterruptedException { final List list = Lists.newArrayListWithCapacity(5000000); Long first_id = 500000000000000001L; for (int i = 0; i < 5000000; i++) {