You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RedLock实现Redis值锁定失效求助:锁成功但数据仍可读取

问题核心:误解了RedLock的运作机制

RedLock不会自动锁定Redis中的数据,它只是提供一个分布式互斥锁的标识,用来协调多进程/服务间的互斥操作。你创建的refId:1234锁是Redis中独立的一个key,和你的events列表没有任何关联,所以lpop操作完全不会去检查这个锁的状态,自然能直接弹出数据。

你的代码问题拆解

  • 你成功获取了锁,但后续的listPop函数没有做任何锁校验逻辑,直接执行了弹出操作,完全忽略了锁的存在。
  • 锁实例的expiration字段是锁的到期时间戳(不是剩余TTL),你可以通过expiration - Date.now()计算锁的剩余有效时间。

正确的实现方式

要实现“锁定数据后需等待锁释放才能访问”的效果,必须在操作数据的逻辑前主动检查锁的状态,只有获取到锁(或锁已释放)才能执行数据操作。

修改后的示例代码

const redis = require('ioredis');
const RedLock = require('redlock');

// Connect to Redis
const client = redis.createClient({
    port: 6379,
    host: '127.0.0.1',
});

const redlock = new RedLock([client]);

async function listPush() {
    const value = 'refId:1234';
    await client.rpush('events', value);
    const time = Date.parse(Date());
    console.log('Successfully pushed : ', time);
}

async function listPop() {
    const targetValue = 'refId:1234';
    try {
        // 尝试获取锁:设置重试5次,每次间隔1秒,模拟等待锁释放
        const lock = await redlock.lock(targetValue, 1000, {
            retryCount: 5,
            retryDelay: 1000
        });
        
        // 成功获取锁,执行弹出操作
        const reply = await client.lpop('events');
        const time = Date.parse(Date());
        console.log(`Data read from list: ${reply}`, ' ', time);
        
        // 操作完成后主动释放锁
        await lock.unlock();
    } catch (err) {
        // 多次重试仍无法获取锁,说明锁仍被持有
        const time = Date.parse(Date());
        console.log(`Failed to pop data, lock is still held`, ' ', time);
    }
}
  
async function lockValue(value, ttl) {
    const lock = await redlock.lock(value, ttl);
    const time = Date.parse(Date());
    console.log("Successfully acquired lock on : ", time);
    return lock;
}

// 用async/await保证异步顺序
async function runTest() {
    await listPush();
    await lockValue("refId:1234", 4000);
    setTimeout(listPop, 1000);
}

runTest();

关键逻辑说明

  • 在listPop中,我们先尝试获取锁,如果锁还被持有(前4秒内),会自动重试,直到锁释放或重试次数耗尽。
  • 锁的作用是保护代码执行的互斥性,而不是直接锁定Redis数据。如果要保护整个events列表的弹出操作,也可以把锁key设置为events-list-lock,让所有操作该列表的进程都先获取这个锁。

内容的提问来源于stack exchange,提问作者fbyself2011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 14:05:31