如何在 java 中为应用程序锁定 Redis 集群

How to lock redis cluster for an application in java

我有两个 java 应用程序(app1、app2)。两个应用程序都使用 JedisCluster 客户端用于 Redis 集群。 app1 从 Redis 集群写入或读取数据。 app2 就像一个调度程序,它只将一些数据写入 Redis 集群。它在固定的时间间隔后运行。我必须确保当 app2 执行写操作时,在 app2 完成整个写操作之前,不会为 app1 提供或写入任何数据。我想在 app2 为 运行 时为 app1 锁定 Redis 集群。当时 app1 是否有异常并不重要。

看来您需要应用程序级锁来确保来自不同应用程序范围的线程安全操作,这与 distributed lock 非常相似。对于 Jedis,快速搜索会产生 Jedis-lock 库。

Jedis jedis = new Jedis("localhost");
JedisLock lock = new JedisLock(jedis, "lockname", 10000, 30000);
lock.acquire();
try {
  // do some stuff
}
finally {
  lock.release();
}

System.out.println(jedis.isLocked());
System.out.println(jedis.isRemoteLocked());

编辑

根据 Jedis-lock 的所有者(感谢这个项目),该项目不再 maintained/pull 不再合并请求。 This fork 现在正在积极维护并具有新功能:

  • SETAPI代替旧SETNX
  • release()
  • 上使用原子 LUA 脚本锁定所有权安全
  • JedisCluster
  • 的锁定支持

你试过Redisson的锁了吗?这是一个基于 Redis 的框架。

它提供了 Lock 对象实现的 java.util.concurrent.locks.Lock 接口并且易于使用。

RedissonClient redisson = Redisson.create(config);

RLock lock = redisson.getLock("myLock");
lock.lock();
try {
   // ...
} finally {
   lock.unlock();
}

它还提供异步版本的锁对象。

我使用 Distributed locks with Redis 在 Jedis 的竞争条件下实现了互斥 因为 "GETs" 不是线程安全的,所以需要在多线程环境中实现互斥锁。这是通过 getJedis()

上的 JedisSentinelPool 实现的
 public void methodWithRaceCondition() {

    Jedis jedis = getJedis();
    try {
         lock();

        //code that requires multiple exclusion on data read
        jedis.//get hget ....


    } catch (Exception up) {
        logException(up);

    } finally {
        //ALWAYS RELEASE LOCK
        releaseLock(jedis);
        closeJedis(jedis);
        jedis = null;
    }
 }

 private void releaseLock(Jedis jedis) {
    String semaphore = "SEMAPHORE";
    try {
        if (!jedis.get(semaphore).isEmpty()) {
            jedis.del(semaphore);
        }
    } catch (final RuntimeException e) {
        LOGGER_SUB.error(e);
    }
}

private void lock(Jedis jedis) throws InterruptedException {
    synchronized (this) {
        try {
            String lock = openSemaphore(jedis);
            while (lock == null || "OK".compareTo(lock) != 0) {
                this.wait(1);
                LOGGER_SUB.info("WAITED");
                lock = openSemaphore(jedis);
            }
        } catch (final RuntimeException e) {
            LOGGER_SUB.error(e);
        }
    }
}

/**
 * Distributed locks with Redis
 * https://redis.io/topics/distlock
 * Set value =1
 * NX if not exixts
 * PX for millisec
 *
 * @param jedis
 * @return
 */
private String openSemaphore(Jedis jedis) {
    return jedis.set("SEMAPHORE", "1", "NX", "PX", 30000);
}