阿里二面:redis分布式锁过期了但业务还没有执行完,怎么办
SETNX KEY_NAME VALUE
SET key value [EX seconds] [PX milliseconds] NX
EXPIRE <key> <seconds>
RLock lock = redisson.getLock("client-lock");
lock.lock();
try {
//处理业务
} catch (Exception e) {
//处理异常
} finally {
lock.unlock();
}
这里的哨兵并不是redis的哨兵,而且为了检测客户端故障业务系统自己做的哨兵。
加锁的命令,我们参照spring包里的分布式锁代码,如果锁存在并且是当前客户端加的锁,那就续锁,如果锁不存在,则加锁。代码如下:
private static final String OBTAIN_LOCK_SCRIPT =
"local lockClientId = redis.call('GET', KEYS[1])\n" +
"if lockClientId == ARGV[1] then\n" +
" redis.call('PEXPIRE', KEYS[1], ARGV[2])\n" +
" return true\n" +
"elseif not lockClientId then\n" +
" redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2])\n" +
" return true\n" +
"end\n" +
"return false";
把锁保存在一个数据结构里,比如HashMap,定时任务定时扫描这个map,对每个锁进行续锁操作。代码如下:
private final Map<String, RedisLock> locks = new ConcurrentHashMap<>();
续锁命令
private static final String RENEW_LOCK_SCRIPT =
"local lockClientId = redis.call('GET', KEYS[1])\n" +
"if lockClientId == ARGV[1] then\n" +
" redis.call('PEXPIRE', KEYS[1], ARGV[2])\n" +
" return true\n" +
"end\n" +
"return false";
写一个定时任务,定时执行续锁代码:
redisTemplate.execute(renewLockScript,
Collections.singletonList(lockKey), clientId,
String.valueOf(expireAfter));
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️