【问题标题】:How to lock redis cluster for an application in java如何在java中为应用程序锁定redis集群
【发布时间】:2017-09-21 22:46:26
【问题描述】:

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

【问题讨论】:

  • 可能有助于查看分布式 redis 锁

标签: java redis jedis distributed-lock


【解决方案1】:

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

它提供了实现java.util.concurrent.locks.Lock接口的Lock对象,使用方便。

RedissonClient redisson = Redisson.create(config);

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

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

【讨论】:

    【解决方案2】:

    您似乎需要应用程序级锁来确保来自不同应用程序范围的线程安全操作,这与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 的所有者(感谢此项目),该项目不再维护/拉取请求不再合并。 This fork 现在得到积极维护并具有新功能:

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

    【讨论】:

    • 如果应用程序在执行 finally 块之前崩溃了怎么办,这可能会使 Redis 永远锁定,最好使用一些超时来获取锁定。
    • @AmanSinghal 是的,你是对的,但是这里使用的 API JedisLock(Jedis jedis, String lockKey, int acquireTimeoutMillis, int expiryTimeMillis) 我在这里设置了 30000。因此,如果发生任何故障,它最终会超时。
    • 是的,我注意到只是想突出显示它以便让人们意识到这个问题。
    【解决方案3】:

    我使用Distributed locks with Redis 在 Jedis 上的竞争条件下实现了互斥 因为“GET”不是线程安全的,所以需要在多线程环境中实现互斥锁。这是通过 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-07-01
      • 2018-07-12
      • 2016-05-27
      • 2018-04-20
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多