Redis实现分布式锁





1 Redis实现分布式锁

  • 通过Redis的setnx命令来实现分布式锁。

  • setnx: 如果key不存在,则设置key的值为value,返回1;如果key已经存在,则返回0。

# 加锁 setnxlock:service_id(或者ProductId) 唯一性ID
setnx lock:service_id info

# 释放锁
del key

1.1 Redis单节点实现方案

  1. 创建对应productId的锁(设置过期时间)
  2. 假如其他线程也想要操作对应productId的数据,会先去获取锁,如果获取成功,则可以进行操作,否则等待。
  3. 操作完成后,释放锁。

1.2 Redis分布式锁死锁问题

  • 问题:如果加锁始终无法释放,会导致死锁。
  • 解决方案:加锁时设置过期时间ttl,保证锁最终能够被释放。

1.3 Redis分布式锁过期时间的问题

  • 问题1:如果业务操作没有执行完,锁过期了,会导致其他线程获取锁,导致数据不一致。
  • 解决方案:看门狗机制,每隔一段时间,给锁续期。
import redis.clients.jedis.Jedis;

public class RedisLock {
    private Jedis jedis;
    private String lockKey;
    private String lockValue;
    private Thread renewThread;
    private volatile boolean isLocked = false;

    public RedisLock(Jedis jedis, String lockKey, String lockValue) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.lockValue = lockValue;
    }

    public boolean tryLock(long timeout) {
        long start = System.currentTimeMillis();
        while (System.currentTimeMillis() - start < timeout) {
            if (jedis.setnx(lockKey, lockValue) == 1) {
                isLocked = true;
                startRenewThread();
                return true;
            }
        }
        return false;
    }

    public void unlock() {
        if (!isLocked) {
            return;
        }
        isLocked = false;
        renewThread.interrupt();
        if (lockValue.equals(jedis.get(lockKey))) {
            jedis.del(lockKey);
        }
    }

    private void startRenewThread() {
        renewThread = new Thread(() -> {
            while (isLocked) {
                jedis.expire(lockKey, 30);
                try {
                    Thread.sleep(20000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        renewThread.start();
    }
}
  • 问题2:我误删别人的锁,导致数据不一致。
  • 解决方案:我getKey的时候,判断一下是不是自己加的值,是的话再删除。

1.4 Redis分布式锁的 性能 问题(分段锁)

  • 问题1:当有一把把锁因为业务操作时间过长,导致锁的续期线程不断续期,会导致Redis的性能问题。
  • 解决方案:将锁分段(类似ConcurrentHashMap),每一段锁对应一个Redis实例,将锁的数量分散到多个Redis实例上。

比如:1000个锁,分成10段,每一段100个锁,每一段对应一个Redis实例。(每个锁的名字都叫Product_id_1…Product_id_n)






我的Github地址,欢迎大家加入我的开源项目,或者(在我的主页联系我)加入你们的开源项目,点点Github-Stars。

\ 开源项目名称 依赖类型 版本号 描述
1 spring-boot-starter-trie pom 1.0.0-SNAPSHOT 特定需求下查询速度远超开源检索工具,innodb下B+树或者ES中倒排索引无法与之比拟.
2 spring-boot-starter-trie jar 1.0.0-M1 提供了基于SpringCloud的服务节点,可以通过Nacos注册中心进行服务发现,实现了树的动态扩容与缩容,以及服务的动态上下线。
3 Data-Provider pom 1.0.0-SNAPSHOT 提供了多种数据源的查询,以及数据的类型同步,作为一个Jar可以依赖在其他服务上动态的提供数据。

相关推荐

  1. Redis实现分布式

    2024-03-10 21:26:06       45 阅读
  2. Redis分布式实现

    2024-03-10 21:26:06       48 阅读
  3. Redis实现分布式

    2024-03-10 21:26:06       136 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-10 21:26:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-10 21:26:06       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-10 21:26:06       82 阅读
  4. Python语言-面向对象

    2024-03-10 21:26:06       91 阅读

热门阅读

  1. CPU飙升和OOM排查思路

    2024-03-10 21:26:06       40 阅读
  2. MOGDB/openGauss数据库gs dump备份脚本及备份清理

    2024-03-10 21:26:06       36 阅读
  3. HarmonyOS4.0入门学习需要学习哪些知识点呢?

    2024-03-10 21:26:06       44 阅读
  4. openssl3.2 - exp - export RSA pubKey from RSA privKey on memory

    2024-03-10 21:26:06       38 阅读
  5. 8. Go实现Gin服务优雅关机与重启

    2024-03-10 21:26:06       42 阅读
  6. Android 二维码相关(一)

    2024-03-10 21:26:06       43 阅读
  7. 计算机基础专升本笔记十二-Excel常用快捷键大全

    2024-03-10 21:26:06       46 阅读
  8. SpringBoot多环境配置和logback日志记录器

    2024-03-10 21:26:06       43 阅读
  9. 关于设置html不让浏览器进行缓存的问题

    2024-03-10 21:26:06       42 阅读