栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

批量分布式锁 Redis 批量命令执行 lua&pipeline

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

批量分布式锁 Redis 批量命令执行 lua&pipeline

场景:分布式锁是使用非常频繁的,批量跑逻辑比如导入、多选提交业务,也会用到,但是由于单个锁频繁网络请求非常耗时,于是就有了批量锁;

批量上锁要原子性用了lua脚本实现,批量解锁用的pipeline,废话不说上代码

public class RedisBatchLock {
    static final Integer MAX_SIZE = 100;

    
    static final String getScriptLua() {
        StringBuffer str = new StringBuffer();
        str.append(" local seccess = {}; ");
        str.append(" for k, v in pairs(KEYS) do ");
        str.append(" local value = ARGV[k] ; ");
        str.append(" local ok = redis.call('setnx', v, value); ");
        str.append("   if ok == 1 then ");
        str.append("   redis.call('expire', v, ARGV[#ARGV]); ");
        str.append("   seccess[k]=v; ");
        str.append("   else ");
        str.append("       if #seccess>0 then ");
        str.append("           for x, y in pairs(seccess) do ");
        str.append("           redis.call('del', y); ");
        str.append("           end ");
        str.append("       end ");
        str.append("   return false; ");
        str.append("   end ");
        str.append(" end ");
        str.append(" return true; ");
        return str.toString();
    }

    
    public static Boolean batchLock(List keys, Long timeOut) {
        if (CollectionUtil.isEmpty(keys) ||
                timeOut < 1000L ||
                keys.size() > MAX_SIZE) {
            return false;
        }
        List values = new ArrayList();
        List finalKeys = new ArrayList();
        for (String key : keys) {
            LockInfo lockInfo = new LockInfo(key, Thread.currentThread().getName(), Thread.currentThread().getId());
            lockInfo.setStatus(1);
            finalKeys.add(RedisLockKeyGenerator.generateRedisLockKey(key));
            values.add(JSON.toJSONString(lockInfo));
        }
        values.add(timeOut / 1000 + "");
        RedisTemplate redisMasterTemplate = RedisHelper.getRedisTemplate();
        RedisScript redisScript = new DefaultRedisScript(getScriptLua(), Boolean.class);
        Boolean flag = redisMasterTemplate.execute(redisScript, finalKeys, values.toArray(new String[0]));
        return flag;
    }

    
    public static boolean batchUnLock(List keys) {
        if (CollectionUtil.isEmpty(keys)) {
            return false;
        }
        RedisTemplate redisTemplate = RedisHelper.getRedisTemplate();
        List list = redisTemplate.executePipelined(new SessionCallback() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                for (String key : keys) {
                    key = RedisLockKeyGenerator.generateRedisLockKey(key);
                    operations.delete(key);
                }
                return null;
            }
        });
        return true;
    }

} 

Redis与spring集成就不多说了,主要逻辑在此,个别封装代码可以忽略,稍微动一下就可以运行啦;

经测试,批量处理10把锁性能提示4倍。

lua脚本和java调用注意返回值类型要一致(这里是Boolean),参数集合类型要一致(这里是String),注意这些坑即可。

另外,这里未支持重入锁的场景,批量处理一般也不会有这种场景;解锁处理要小心,没有做约束本线程可解锁,这需要改进。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号